UI: SCADA symbol - implement create widget from SCADA symbol, add widget size parameters, make target device optional for SCADA symbol widgets.
This commit is contained in:
parent
4fd84315a5
commit
cfc4d3d65f
@ -6,6 +6,8 @@
|
||||
"level",
|
||||
"fan"
|
||||
],
|
||||
"widgetSizeX": 3,
|
||||
"widgetSizeY": 3,
|
||||
"stateRenderFunction": "var showMinMaxLevel = ctx.properties.showMinMaxLevel;\nvar minLevelElement = ctx.tags.minLevel[0];\nvar maxLevelElement = ctx.tags.maxLevel[0];\nvar minLevel = ctx.properties.minLevel; \nvar maxLevel = ctx.properties.maxLevel;\n\nif (showMinMaxLevel) {\n \n var minMaxLevelFont = ctx.properties.minMaxLevelFont;\n var minMaxLevelColor = ctx.properties.minMaxLevelColor;\n \n ctx.api.text(minLevelElement, minLevel);\n ctx.api.text(maxLevelElement, maxLevel);\n \n ctx.api.font(minLevelElement, minMaxLevelFont, minMaxLevelColor);\n ctx.api.font(maxLevelElement, minMaxLevelFont, minMaxLevelColor);\n \n} else {\n minLevelElement.hide();\n maxLevelElement.hide();\n}\n\nvar disabled = ctx.values.disabled;\nvar on = ctx.values.on;\nvar level = ctx.values.level;\n\nvar onButton = ctx.tags.onButton;\nvar offButton = ctx.tags.offButton;\nvar levelUpButton = ctx.tags.levelUpButton;\nvar levelDownButton = ctx.tags.levelDownButton;\n\nvar onButtonEnabled = !disabled && !on;\nvar offButtonEnabled = !disabled && on;\nvar levelUpEnabled = !disabled && level < maxLevel;\nvar levelDownEnabled = !disabled && level > minLevel;\n\nif (onButtonEnabled) {\n ctx.api.enable(onButton);\n onButton[0].findOne('rect').attr({fill: '#12ed19'});\n} else {\n ctx.api.disable(onButton);\n onButton[0].findOne('rect').attr({fill: '#777'});\n}\n \nif (offButtonEnabled) {\n ctx.api.enable(offButton);\n offButton[0].findOne('rect').attr({fill: '#ed121f'});\n} else {\n ctx.api.disable(offButton);\n offButton[0].findOne('rect').attr({fill: '#777'});\n} \n\n\nif (levelUpEnabled) {\n ctx.api.enable(levelUpButton);\n levelUpButton[0].findOne('rect').attr({fill: '#fff'});\n} else {\n ctx.api.disable(levelUpButton);\n levelUpButton[0].findOne('rect').attr({fill: '#777'});\n}\n \nif (levelDownEnabled) {\n ctx.api.enable(levelDownButton);\n levelDownButton[0].findOne('rect').attr({fill: '#fff'});\n} else {\n ctx.api.disable(levelDownButton);\n levelDownButton[0].findOne('rect').attr({fill: '#777'});\n}",
|
||||
"tags": [
|
||||
{
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -6,12 +6,12 @@
|
||||
"description": "",
|
||||
"descriptor": {
|
||||
"type": "rpc",
|
||||
"sizeX": 3.5,
|
||||
"sizeY": 3.5,
|
||||
"sizeX": 3,
|
||||
"sizeY": 3,
|
||||
"resources": [],
|
||||
"templateHtml": "<tb-scada-symbol-widget\n [ctx]='ctx'\n [widgetTitlePanel]=\"widgetTitlePanel\">\n</tb-scada-symbol-widget>",
|
||||
"templateCss": "",
|
||||
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.actionWidget.onInit();\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '280px',\n previewHeight: '280px',\n embedTitlePanel: true,\n displayRpcMessageToast: false\n };\n};\n\nself.onDestroy = function() {\n}\n",
|
||||
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.actionWidget.onInit();\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '300px',\n previewHeight: '320px',\n embedTitlePanel: true,\n targetDeviceOptional: true,\n displayRpcMessageToast: false\n };\n};\n\nself.onDestroy = function() {\n}\n",
|
||||
"settingsSchema": "",
|
||||
"dataKeySettingsSchema": "{}\n",
|
||||
"settingsDirective": "tb-scada-symbol-widget-settings",
|
||||
|
||||
@ -382,6 +382,12 @@ public class InstallScripts {
|
||||
}
|
||||
settings.put("scadaSymbolUrl", symbolUrl);
|
||||
((ObjectNode)descriptor).put("defaultConfig", JacksonUtil.toString(defaultConfig));
|
||||
((ObjectNode)descriptor).put("sizeX", metadata.getWidgetSizeX());
|
||||
((ObjectNode)descriptor).put("sizeY", metadata.getWidgetSizeY());
|
||||
String controllerScript = descriptor.get("controllerScript").asText();
|
||||
controllerScript = controllerScript.replaceAll("previewWidth: '\\d*px'", "previewWidth: '" + (metadata.getWidgetSizeX() * 100) + "px'");
|
||||
controllerScript = controllerScript.replaceAll("previewHeight: '\\d*px'", "previewHeight: '" + (metadata.getWidgetSizeY() * 100 + 20) + "px'");
|
||||
((ObjectNode)descriptor).put("controllerScript", controllerScript);
|
||||
var savedWidget = widgetTypeService.saveWidgetType(scadaSymbolWidget);
|
||||
return savedWidget.getFqn();
|
||||
}
|
||||
|
||||
@ -283,6 +283,8 @@ public class ImageUtils {
|
||||
private String title;
|
||||
private String description;
|
||||
private String[] searchTags;
|
||||
private int widgetSizeX;
|
||||
private int widgetSizeY;
|
||||
|
||||
public ScadaSymbolMetadataInfo(String fileName, JsonNode metaData) {
|
||||
if (metaData != null && metaData.has("title")) {
|
||||
@ -304,6 +306,16 @@ public class ImageUtils {
|
||||
} else {
|
||||
searchTags = new String[0];
|
||||
}
|
||||
if (metaData != null && metaData.has("widgetSizeX")) {
|
||||
widgetSizeX = metaData.get("widgetSizeX").asInt();
|
||||
} else {
|
||||
widgetSizeX = 3;
|
||||
}
|
||||
if (metaData != null && metaData.has("widgetSizeY")) {
|
||||
widgetSizeY = metaData.get("widgetSizeY").asInt();
|
||||
} else {
|
||||
widgetSizeY = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,9 @@
|
||||
</mat-spinner>
|
||||
</div>
|
||||
<div id="gridster-parent"
|
||||
fxFlex class="tb-dashboard-content layout-wrap" [class]="{'autofill-height': isAutofillHeight()}"
|
||||
fxFlex class="tb-dashboard-content" [class.autofill-height]="isAutofillHeight()"
|
||||
[class.center-vertical]="centerVertical"
|
||||
[class.center-horizontal]="centerHorizontal"
|
||||
(contextmenu)="openDashboardContextMenu($event)">
|
||||
<div #dashboardMenuTrigger="matMenuTrigger" style="visibility: hidden; position: fixed"
|
||||
[style.left]="dashboardMenuPosition.x"
|
||||
@ -61,7 +63,7 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
<div [class]="dashboardClass" id="gridster-background" style="height: 100%;">
|
||||
<div [class]="dashboardClass" id="gridster-background">
|
||||
<gridster #gridster id="gridster-child" [options]="gridsterOpts">
|
||||
<gridster-item #gridsterItem [item]="widget" [class]="{'tb-noselect': isEdit}" *ngFor="let widget of dashboardWidgets">
|
||||
<tb-widget-container
|
||||
|
||||
@ -37,6 +37,10 @@
|
||||
outline: none;
|
||||
overflow-y: auto;
|
||||
|
||||
#gridster-background {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
gridster-item {
|
||||
transition: none;
|
||||
overflow: visible;
|
||||
@ -49,6 +53,30 @@
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&.center-vertical, &.center-horizontal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
#gridster-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
&.center-vertical {
|
||||
#gridster-background {
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&.center-horizontal {
|
||||
#gridster-background {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#gridster-child {
|
||||
|
||||
@ -59,6 +59,8 @@ import { ResizeObserver } from '@juggle/resize-observer';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { WidgetComponentAction, WidgetComponentActionType } from '@home/components/widget/widget-container.component';
|
||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||
import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
|
||||
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-dashboard',
|
||||
@ -88,12 +90,30 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
@Input()
|
||||
columns: number;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
setGridSize = false;
|
||||
|
||||
@Input()
|
||||
margin: number;
|
||||
|
||||
@Input()
|
||||
outerMargin: boolean;
|
||||
|
||||
@Input()
|
||||
displayGrid: displayGrids = 'onDrag&Resize';
|
||||
|
||||
@Input()
|
||||
gridType: GridType;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
centerVertical = false;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
centerHorizontal = false;
|
||||
|
||||
@Input()
|
||||
isEdit: boolean;
|
||||
|
||||
@ -208,7 +228,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
this.dashboardTimewindow = this.timeService.defaultTimewindow();
|
||||
}
|
||||
this.gridsterOpts = {
|
||||
gridType: GridType.ScrollVertical,
|
||||
gridType: this.gridType || GridType.ScrollVertical,
|
||||
keepFixedHeightInMobile: true,
|
||||
disableWarnings: false,
|
||||
disableAutoPositionOnConflict: false,
|
||||
@ -216,6 +236,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
swap: false,
|
||||
maxRows: 3000,
|
||||
minCols: this.columns ? this.columns : 24,
|
||||
setGridSize: this.setGridSize,
|
||||
maxCols: 3000,
|
||||
maxItemCols: 1000,
|
||||
maxItemRows: 1000,
|
||||
@ -226,6 +247,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
minItemRows: 1,
|
||||
defaultItemCols: 8,
|
||||
defaultItemRows: 6,
|
||||
displayGrid: this.displayGrid,
|
||||
resizable: {enabled: this.isEdit},
|
||||
draggable: {enabled: this.isEdit},
|
||||
itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
|
||||
@ -530,7 +552,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
if (autofillHeight) {
|
||||
this.gridsterOpts.gridType = this.isMobileSize ? GridType.Fixed : GridType.Fit;
|
||||
} else {
|
||||
this.gridsterOpts.gridType = this.isMobileSize ? GridType.Fixed : GridType.ScrollVertical;
|
||||
this.gridsterOpts.gridType = this.isMobileSize ? GridType.Fixed : this.gridType || GridType.ScrollVertical;
|
||||
}
|
||||
const mobileBreakPoint = this.isMobileSize ? 20000 : 0;
|
||||
this.gridsterOpts.mobileBreakpoint = mobileBreakPoint;
|
||||
|
||||
@ -24,13 +24,13 @@
|
||||
</tb-toggle-select>
|
||||
</div>
|
||||
<tb-entity-autocomplete *ngIf="targetDeviceFormGroup.get('type').value === targetDeviceType.device"
|
||||
[required]="!widgetEditMode"
|
||||
[required]="(!widgetEditMode && !targetDeviceOptional)"
|
||||
[entityType]="entityType.DEVICE"
|
||||
formControlName="deviceId">
|
||||
</tb-entity-autocomplete>
|
||||
<tb-entity-alias-select
|
||||
*ngIf="targetDeviceFormGroup.get('type').value === targetDeviceType.entity"
|
||||
[tbRequired]="!widgetEditMode"
|
||||
[tbRequired]="(!widgetEditMode && !targetDeviceOptional)"
|
||||
[aliasController]="aliasController"
|
||||
[callbacks]="entityAliasSelectCallbacks"
|
||||
formControlName="entityAliasId">
|
||||
|
||||
@ -60,6 +60,10 @@ export class TargetDeviceComponent implements ControlValueAccessor, OnInit, Vali
|
||||
return this.widgetConfigComponent.widgetConfigCallbacks;
|
||||
}
|
||||
|
||||
public get targetDeviceOptional(): boolean {
|
||||
return this.widgetConfigComponent.modelValue?.typeParameters?.targetDeviceOptional;
|
||||
}
|
||||
|
||||
targetDeviceType = TargetDeviceType;
|
||||
|
||||
entityType = EntityType;
|
||||
@ -103,9 +107,9 @@ export class TargetDeviceComponent implements ControlValueAccessor, OnInit, Vali
|
||||
|
||||
ngOnInit() {
|
||||
this.targetDeviceFormGroup = this.fb.group({
|
||||
type: [null, !this.widgetEditMode ? [Validators.required] : []],
|
||||
deviceId: [null, !this.widgetEditMode ? [Validators.required] : []],
|
||||
entityAliasId: [null, !this.widgetEditMode ? [Validators.required] : []]
|
||||
type: [null, (!this.widgetEditMode && !this.targetDeviceOptional) ? [Validators.required] : []],
|
||||
deviceId: [null, (!this.widgetEditMode && !this.targetDeviceOptional) ? [Validators.required] : []],
|
||||
entityAliasId: [null, (!this.widgetEditMode && !this.targetDeviceOptional) ? [Validators.required] : []]
|
||||
});
|
||||
this.targetDeviceFormGroup.get('type').valueChanges.subscribe(() => {
|
||||
this.updateValidators();
|
||||
|
||||
@ -177,6 +177,8 @@ export interface ScadaSymbolMetadata {
|
||||
title: string;
|
||||
description?: string;
|
||||
searchTags?: string[];
|
||||
widgetSizeX: number;
|
||||
widgetSizeY: number;
|
||||
stateRenderFunction?: string;
|
||||
stateRender?: ScadaSymbolStateRenderFunction;
|
||||
tags: ScadaSymbolTag[];
|
||||
@ -186,6 +188,8 @@ export interface ScadaSymbolMetadata {
|
||||
|
||||
export const emptyMetadata = (): ScadaSymbolMetadata => ({
|
||||
title: '',
|
||||
widgetSizeX: 3,
|
||||
widgetSizeY: 3,
|
||||
tags: [],
|
||||
behavior: [],
|
||||
properties: []
|
||||
@ -443,12 +447,14 @@ export class ScadaSymbolObject {
|
||||
this.stateValueSubjects[stateValueId].unsubscribe();
|
||||
}
|
||||
this.valueActions.forEach(v => v.destroy());
|
||||
for (const tag of this.metadata.tags) {
|
||||
const elements = this.context.tags[tag.tag];
|
||||
elements.forEach(element => {
|
||||
element.timeline().finish();
|
||||
element.timeline(null);
|
||||
});
|
||||
if (this.context) {
|
||||
for (const tag of this.metadata.tags) {
|
||||
const elements = this.context.tags[tag.tag];
|
||||
elements.forEach(element => {
|
||||
element.timeline().finish();
|
||||
element.timeline(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (this.svgShape) {
|
||||
this.svgShape.remove();
|
||||
|
||||
@ -589,6 +589,9 @@ export class WidgetComponentService {
|
||||
if (isUndefined(result.typeParameters.displayRpcMessageToast)) {
|
||||
result.typeParameters.displayRpcMessageToast = true;
|
||||
}
|
||||
if (isUndefined(result.typeParameters.targetDeviceOptional)) {
|
||||
result.typeParameters.targetDeviceOptional = false;
|
||||
}
|
||||
if (isFunction(widgetTypeInstance.actionSources)) {
|
||||
result.actionSources = widgetTypeInstance.actionSources();
|
||||
} else {
|
||||
|
||||
@ -962,7 +962,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
||||
if (this.modelValue) {
|
||||
const config = this.modelValue.config;
|
||||
if (this.widgetType === widgetType.rpc && this.modelValue.isDataEnabled) {
|
||||
if (!this.widgetEditMode && !targetDeviceValid(config.targetDevice)) {
|
||||
if ((!this.widgetEditMode && !this.modelValue?.typeParameters.targetDeviceOptional) && !targetDeviceValid(config.targetDevice)) {
|
||||
return {
|
||||
targetDevice: {
|
||||
valid: false
|
||||
|
||||
@ -52,6 +52,23 @@
|
||||
</tb-string-items-list>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width" translate>scada.widget-size</div>
|
||||
<div fxLayout="row" fxFlex fxLayoutAlign="end center" fxLayoutGap="8px">
|
||||
<div class="tb-small-label">{{ 'scada.cols' | translate }}</div>
|
||||
<mat-form-field appearance="outline" class="number flex" subscriptSizing="dynamic">
|
||||
<input matInput formControlName="widgetSizeX" required
|
||||
[min]="1" [max]="24" [step]="1"
|
||||
type="number" placeholder="{{ 'widget-config.set' | translate }}">
|
||||
</mat-form-field>
|
||||
<div class="tb-small-label">{{ 'scada.rows' | translate }}</div>
|
||||
<mat-form-field appearance="outline" class="number flex" subscriptSizing="dynamic">
|
||||
<input matInput formControlName="widgetSizeY" required
|
||||
[min]="1" [max]="24" [step]="1"
|
||||
type="number" placeholder="{{ 'widget-config.set' | translate }}">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tb-form-panel stroked">
|
||||
<mat-expansion-panel class="tb-settings" expanded>
|
||||
<mat-expansion-panel-header fxLayout="row wrap">
|
||||
|
||||
@ -130,6 +130,8 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
|
||||
title: [null, [Validators.required]],
|
||||
description: [null],
|
||||
searchTags: [null],
|
||||
widgetSizeX: [null, [Validators.min(1), Validators.max(24), Validators.required]],
|
||||
widgetSizeY: [null, [Validators.min(1), Validators.max(24), Validators.required]],
|
||||
stateRenderFunction: [null],
|
||||
tags: [null],
|
||||
behavior: [null],
|
||||
@ -176,6 +178,8 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
|
||||
title: value?.title,
|
||||
description: value?.description,
|
||||
searchTags: value?.searchTags,
|
||||
widgetSizeX: value?.widgetSizeX || 3,
|
||||
widgetSizeY: value?.widgetSizeY || 3,
|
||||
stateRenderFunction: value?.stateRenderFunction,
|
||||
tags: value?.tags,
|
||||
behavior: value?.behavior,
|
||||
|
||||
@ -29,6 +29,13 @@
|
||||
[showCloseDetails]="false"
|
||||
headerHeightPx="64"
|
||||
headerTitle="{{symbolData?.imageResource?.title}}">
|
||||
<div class="details-buttons" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
|
||||
<button mat-stroked-button
|
||||
[disabled]="scadaSymbolFormGroup.invalid"
|
||||
(click)="createWidget()">
|
||||
{{ 'scada.create-widget' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="previewMode" class="tb-scada-symbol-editor-preview-content tb-absolute-fill">
|
||||
<div class="tb-scada-symbol-editor-preview-header">
|
||||
<button mat-button
|
||||
@ -110,7 +117,7 @@
|
||||
</div>
|
||||
</tb-details-panel>
|
||||
</mat-drawer>
|
||||
<mat-drawer-content class="tb-scada-symbol-editor-content">
|
||||
<mat-drawer-content class="tb-scada-symbol-editor-content" [class.preview]="previewMode">
|
||||
<tb-scada-symbol-editor *ngIf="!previewMode" #symbolEditor
|
||||
[readonly]="readonly"
|
||||
[data]="symbolEditorData"
|
||||
@ -121,8 +128,13 @@
|
||||
class="tb-absolute-fill"
|
||||
[aliasController]="aliasController"
|
||||
[widgets]="previewWidgets"
|
||||
[autofillHeight]="true"
|
||||
[columns]="24"
|
||||
[autofillHeight]="false"
|
||||
displayGrid="always"
|
||||
[gridType]="previewWidget.sizeX >= previewWidget.sizeY ? GridType.ScrollVertical : GridType.ScrollHorizontal"
|
||||
[columns]="previewWidget.sizeX"
|
||||
setGridSize
|
||||
[centerVertical]="previewWidget.sizeX >= previewWidget.sizeY"
|
||||
[centerHorizontal]="previewWidget.sizeX < previewWidget.sizeY"
|
||||
[margin]="0"
|
||||
[isEdit]="false"
|
||||
[isMobileDisabled]="true"
|
||||
|
||||
@ -63,5 +63,12 @@
|
||||
min-height: 0;
|
||||
max-width: 50%;
|
||||
background: #fff;
|
||||
&.preview {
|
||||
#gridster-parent {
|
||||
#gridster-background {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ import {
|
||||
ScadaSymbolEditorData
|
||||
} from '@home/pages/scada-symbol/scada-symbol-editor.component';
|
||||
import { ImageService } from '@core/http/image.service';
|
||||
import { imageResourceType, IMAGES_URL_PREFIX } from '@shared/models/resource.models';
|
||||
import { imageResourceType, IMAGES_URL_PREFIX, TB_IMAGE_PREFIX } from '@shared/models/resource.models';
|
||||
import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
|
||||
import { IAliasController, IStateController, StateParams } from '@core/api/widget-api.models';
|
||||
import { EntityAliases } from '@shared/models/alias.models';
|
||||
@ -54,7 +54,7 @@ import { AliasController } from '@core/api/alias-controller';
|
||||
import { EntityService } from '@core/http/entity.service';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Widget, widgetType } from '@shared/models/widget.models';
|
||||
import { Widget, WidgetConfig, widgetType, WidgetTypeDetails } from '@shared/models/widget.models';
|
||||
import {
|
||||
scadaSymbolWidgetDefaultSettings,
|
||||
ScadaSymbolWidgetSettings
|
||||
@ -71,6 +71,14 @@ import {
|
||||
UploadImageDialogData, UploadImageDialogResult
|
||||
} from '@shared/components/image/upload-image-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { BackgroundType } from '@shared/models/widget-settings.models';
|
||||
import { GridType } from 'angular-gridster2';
|
||||
import {
|
||||
SaveWidgetTypeAsDialogComponent, SaveWidgetTypeAsDialogData,
|
||||
SaveWidgetTypeAsDialogResult
|
||||
} from '@home/pages/widget/save-widget-type-as-dialog.component';
|
||||
import { WidgetService } from '@core/http/widget.service';
|
||||
import { de } from 'date-fns/locale';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-scada-symbol',
|
||||
@ -83,6 +91,8 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
|
||||
widgetType = widgetType;
|
||||
|
||||
GridType = GridType;
|
||||
|
||||
@HostBinding('style.width') width = '100%';
|
||||
@HostBinding('style.height') height = '100%';
|
||||
|
||||
@ -115,6 +125,8 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
fetchCellClickColumns: () => []
|
||||
};
|
||||
|
||||
previewWidget: Widget;
|
||||
|
||||
previewWidgets: Array<Widget> = [];
|
||||
|
||||
tags: string[];
|
||||
@ -125,8 +137,6 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
|
||||
private previewScadaSymbolObjectSettings: ScadaSymbolObjectSettings;
|
||||
|
||||
private previewWidget: Widget;
|
||||
|
||||
private forcePristine = false;
|
||||
|
||||
private authUser = getCurrentAuthUser(this.store);
|
||||
@ -149,6 +159,7 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
private utils: UtilsService,
|
||||
private translate: TranslateService,
|
||||
private imageService: ImageService,
|
||||
private widgetService: WidgetService,
|
||||
private dialog: MatDialog) {
|
||||
super(store);
|
||||
}
|
||||
@ -247,14 +258,23 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
scadaSymbolUrl: null,
|
||||
scadaSymbolContent: this.symbolData.scadaSymbolContent,
|
||||
scadaSymbolObjectSettings: this.previewScadaSymbolObjectSettings,
|
||||
padding: '0'
|
||||
padding: '0',
|
||||
background: {
|
||||
type: BackgroundType.color,
|
||||
color: 'rgba(0,0,0,0)',
|
||||
overlay: {
|
||||
enabled: false,
|
||||
color: 'rgba(255,255,255,0.72)',
|
||||
blur: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
this.previewWidget = {
|
||||
typeFullFqn: 'system.scada_symbol',
|
||||
type: widgetType.rpc,
|
||||
sizeX: 24,
|
||||
sizeY: 24,
|
||||
sizeX: this.previewMetadata.widgetSizeX || 3,
|
||||
sizeY: this.previewMetadata.widgetSizeY || 3,
|
||||
row: 0,
|
||||
col: 0,
|
||||
config: {
|
||||
@ -262,7 +282,8 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
showTitle: false,
|
||||
dropShadow: false,
|
||||
padding: '0',
|
||||
margin: '0'
|
||||
margin: '0',
|
||||
backgroundColor: 'rgba(0,0,0,0)'
|
||||
}
|
||||
};
|
||||
this.previewWidgets = [this.previewWidget];
|
||||
@ -366,6 +387,56 @@ export class ScadaSymbolComponent extends PageComponent
|
||||
linkElement.dispatchEvent(clickEvent);
|
||||
}
|
||||
|
||||
createWidget() {
|
||||
const metadata: ScadaSymbolMetadata = this.scadaSymbolFormGroup.get('metadata').value;
|
||||
this.dialog.open<SaveWidgetTypeAsDialogComponent, SaveWidgetTypeAsDialogData,
|
||||
SaveWidgetTypeAsDialogResult>(SaveWidgetTypeAsDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
title: metadata.title,
|
||||
dialogTitle: 'scada.create-widget-from-symbol',
|
||||
saveAsActionTitle: 'action.create'
|
||||
}
|
||||
}).afterClosed().subscribe(
|
||||
(saveWidgetAsData) => {
|
||||
if (saveWidgetAsData) {
|
||||
this.widgetService.getWidgetType('system.scada_symbol').subscribe(
|
||||
(widgetTemplate) => {
|
||||
const symbolUrl = TB_IMAGE_PREFIX + this.symbolData.imageResource.link;
|
||||
const widget: WidgetTypeDetails = {
|
||||
image: symbolUrl,
|
||||
description: metadata.description,
|
||||
tags: metadata.searchTags,
|
||||
...widgetTemplate
|
||||
};
|
||||
widget.fqn = undefined;
|
||||
widget.id = undefined;
|
||||
widget.name = saveWidgetAsData.widgetName;
|
||||
const descriptor = widget.descriptor;
|
||||
descriptor.sizeX = metadata.widgetSizeX;
|
||||
descriptor.sizeY = metadata.widgetSizeY;
|
||||
descriptor.controllerScript = descriptor.controllerScript
|
||||
.replace(/previewWidth: '\d*px'/gm, `previewWidth: '${metadata.widgetSizeX * 100}px'`);
|
||||
descriptor.controllerScript = descriptor.controllerScript
|
||||
.replace(/previewHeight: '\d*px'/gm, `previewHeight: '${metadata.widgetSizeY * 100 + 20}px'`);
|
||||
const config: WidgetConfig = JSON.parse(descriptor.defaultConfig);
|
||||
config.title = saveWidgetAsData.widgetName;
|
||||
config.settings = config.settings || {};
|
||||
config.settings.scadaSymbolUrl = symbolUrl;
|
||||
descriptor.defaultConfig = JSON.stringify(config);
|
||||
this.widgetService.saveWidgetType(widget).subscribe((saved) => {
|
||||
if (saveWidgetAsData.widgetBundleId) {
|
||||
this.widgetService.addWidgetFqnToWidgetBundle(saveWidgetAsData.widgetBundleId, saved.fqn).subscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private updatePreviewWidgetSettings() {
|
||||
this.previewWidget = deepClone(this.previewWidget);
|
||||
this.previewWidget.config.settings.scadaSymbolObjectSettings = this.previewScadaSymbolObjectSettings;
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<form [formGroup]="saveWidgetTypeAsFormGroup" (ngSubmit)="saveAs()" style="width: 360px">
|
||||
<form [formGroup]="saveWidgetTypeAsFormGroup" (ngSubmit)="saveAs()" style="min-width: 360px">
|
||||
<mat-toolbar color="primary">
|
||||
<h2 translate>widget.save-widget-as</h2>
|
||||
<h2 translate>{{ dialogTitle }}</h2>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button
|
||||
(click)="cancel()"
|
||||
@ -29,7 +29,7 @@
|
||||
</mat-progress-bar>
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<div mat-dialog-content>
|
||||
<span translate>widget.save-widget-as-text</span>
|
||||
<span translate>{{ dialogTitle }}</span>
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label translate>widget.title</mat-label>
|
||||
<input matInput formControlName="title" required>
|
||||
@ -53,7 +53,7 @@
|
||||
type="submit"
|
||||
[disabled]="(isLoading$ | async) || saveWidgetTypeAsFormGroup.invalid
|
||||
|| !saveWidgetTypeAsFormGroup.dirty">
|
||||
{{ 'action.saveAs' | translate }}
|
||||
{{ saveAsActionTitle | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
@ -29,6 +29,12 @@ export interface SaveWidgetTypeAsDialogResult {
|
||||
widgetBundleId?: string;
|
||||
}
|
||||
|
||||
export interface SaveWidgetTypeAsDialogData {
|
||||
dialogTitle?: string;
|
||||
title?: string;
|
||||
saveAsActionTitle?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tb-save-widget-type-as-dialog',
|
||||
templateUrl: './save-widget-type-as-dialog.component.html',
|
||||
@ -39,9 +45,12 @@ export class SaveWidgetTypeAsDialogComponent extends
|
||||
|
||||
saveWidgetTypeAsFormGroup: FormGroup;
|
||||
bundlesScope: string;
|
||||
dialogTitle = 'widget.save-widget-as';
|
||||
saveAsActionTitle = 'action.saveAs';
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
@Inject(MAT_DIALOG_DATA) private data: SaveWidgetTypeAsDialogData,
|
||||
public dialogRef: MatDialogRef<SaveWidgetTypeAsDialogComponent, SaveWidgetTypeAsDialogResult>,
|
||||
public fb: FormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
@ -52,11 +61,18 @@ export class SaveWidgetTypeAsDialogComponent extends
|
||||
} else {
|
||||
this.bundlesScope = 'system';
|
||||
}
|
||||
|
||||
if (this.data?.dialogTitle) {
|
||||
this.dialogTitle = this.data.dialogTitle;
|
||||
}
|
||||
if (this.data?.saveAsActionTitle) {
|
||||
this.saveAsActionTitle = this.data.saveAsActionTitle;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.saveWidgetTypeAsFormGroup = this.fb.group({
|
||||
title: [null, [Validators.required]],
|
||||
title: [this.data?.title, [Validators.required]],
|
||||
widgetsBundle: [null]
|
||||
});
|
||||
}
|
||||
|
||||
@ -187,6 +187,7 @@ export interface WidgetTypeParameters {
|
||||
defaultLatestDataKeysFunction?: (configComponent: any, configData: any) => DataKey[];
|
||||
dataKeySettingsFunction?: DataKeySettingsFunction;
|
||||
displayRpcMessageToast?: boolean;
|
||||
targetDeviceOptional?: boolean;
|
||||
}
|
||||
|
||||
export interface WidgetControllerDescriptor {
|
||||
|
||||
@ -3455,6 +3455,9 @@
|
||||
"title": "Title",
|
||||
"description": "Description",
|
||||
"search-tags": "Search tags",
|
||||
"widget-size": "Widget size",
|
||||
"cols": "cols",
|
||||
"rows": "rows",
|
||||
"state-render-function": "State render function",
|
||||
"preview": "Preview",
|
||||
"preview-widget-action-text": "Widget action '{{type}}' successfully invoked!",
|
||||
@ -3464,6 +3467,8 @@
|
||||
"browse-symbol-from-gallery": "Browse SCADA symbol from gallery",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"create-widget": "Create widget",
|
||||
"create-widget-from-symbol": "Create widget from SCADA symbol",
|
||||
"tag": {
|
||||
"tag": "Tag",
|
||||
"on-click-action": "On click action",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user