Browse Source

UI: Implement SCADA layout.

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
e84447d28e
  1. 4
      application/src/main/data/json/system/widget_types/power_button.json
  2. 92
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  3. 4
      ui-ngx/src/app/core/services/menu.service.ts
  4. 14
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  5. 283
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html
  6. 39
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts
  7. 10
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html
  8. 20
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts
  9. 1
      ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss
  10. 8
      ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts
  11. 4
      ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts
  12. 1
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss
  13. 8
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts
  14. 12
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts
  15. 1
      ui-ngx/src/app/shared/models/dashboard.models.ts
  16. 18
      ui-ngx/src/app/shared/models/widget-settings.models.ts
  17. 3
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
application/src/main/data/json/system/widget_types/power_button.json

File diff suppressed because one or more lines are too long

92
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -50,6 +50,7 @@ import { EntityId } from '@app/shared/models/id/entity-id';
import { initModelFromDefaultTimewindow } from '@shared/models/time/time.models';
import { AlarmSearchStatus } from '@shared/models/alarm.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { BackgroundType, colorBackground, isBackgroundSettings } from '@shared/models/widget-settings.models';
@Injectable({
providedIn: 'root'
@ -332,6 +333,27 @@ export class DashboardUtilsService {
return widgetConfig;
}
public prepareWidgetForScadaLayout(widget: Widget): Widget {
const config = widget.config;
config.showTitle = false;
config.dropShadow = false;
config.padding = '0';
config.margin = '0';
config.backgroundColor = 'rgba(0,0,0,0)';
const settings = config.settings || {};
settings.padding = '0';
const background = settings.background;
if (isBackgroundSettings(background)) {
background.type = BackgroundType.color;
background.color = 'rgba(0,0,0,0)';
background.overlay.enabled = false;
} else {
settings.background = colorBackground('rgba(0,0,0,0)');
}
config.settings = settings;
return widget;
}
public validateAndUpdateDatasources(datasources?: Datasource[]): Datasource[] {
if (!datasources) {
datasources = [];
@ -588,15 +610,17 @@ export class DashboardUtilsService {
originalColumns = 24;
}
const gridSettings = layout.gridSettings;
let columns = 24;
if (gridSettings && gridSettings.columns) {
columns = gridSettings.columns;
}
columns = columns * layoutCount;
if (columns !== originalColumns) {
const ratio = columns / originalColumns;
widgetLayout.sizeX *= ratio;
widgetLayout.sizeY *= ratio;
if (!gridSettings.isScada) {
let columns = 24;
if (gridSettings && gridSettings.columns) {
columns = gridSettings.columns;
}
columns = columns * layoutCount;
if (columns !== originalColumns) {
const ratio = columns / originalColumns;
widgetLayout.sizeX *= ratio;
widgetLayout.sizeY *= ratio;
}
}
if (row > -1 && column > - 1) {
@ -662,31 +686,33 @@ export class DashboardUtilsService {
const columns = gridSettings.columns || 24;
const ratio = columns / prevColumns;
layout.gridSettings = gridSettings;
let maxRow = 0;
for (const w of Object.keys(layout.widgets)) {
const widget = layout.widgets[w];
if (!widget.sizeX) {
widget.sizeX = 1;
}
if (!widget.sizeY) {
widget.sizeY = 1;
}
maxRow = Math.max(maxRow, widget.row + widget.sizeY);
}
const newMaxRow = Math.round(maxRow * ratio);
for (const w of Object.keys(layout.widgets)) {
const widget = layout.widgets[w];
if (widget.row + widget.sizeY === maxRow) {
widget.row = Math.round(widget.row * ratio);
widget.sizeY = newMaxRow - widget.row;
} else {
widget.row = Math.round(widget.row * ratio);
widget.sizeY = Math.round(widget.sizeY * ratio);
if (!gridSettings.isScada) {
let maxRow = 0;
for (const w of Object.keys(layout.widgets)) {
const widget = layout.widgets[w];
if (!widget.sizeX) {
widget.sizeX = 1;
}
if (!widget.sizeY) {
widget.sizeY = 1;
}
maxRow = Math.max(maxRow, widget.row + widget.sizeY);
}
widget.sizeX = Math.round(widget.sizeX * ratio);
widget.col = Math.round(widget.col * ratio);
if (widget.col + widget.sizeX > columns) {
widget.sizeX = columns - widget.col;
const newMaxRow = Math.round(maxRow * ratio);
for (const w of Object.keys(layout.widgets)) {
const widget = layout.widgets[w];
if (widget.row + widget.sizeY === maxRow) {
widget.row = Math.round(widget.row * ratio);
widget.sizeY = newMaxRow - widget.row;
} else {
widget.row = Math.round(widget.row * ratio);
widget.sizeY = Math.round(widget.sizeY * ratio);
}
widget.sizeX = Math.round(widget.sizeX * ratio);
widget.col = Math.round(widget.col * ratio);
if (widget.col + widget.sizeX > columns) {
widget.sizeX = columns - widget.col;
}
}
}
}

4
ui-ngx/src/app/core/services/menu.service.ts

@ -155,7 +155,7 @@ export class MenuService {
name: 'scada.symbols',
type: 'link',
path: '/resources/scada-symbols',
icon: 'precision_manufacturing'
icon: 'view_in_ar'
},
{
id: 'resources_library',
@ -561,7 +561,7 @@ export class MenuService {
name: 'scada.symbols',
type: 'link',
path: '/resources/scada-symbols',
icon: 'precision_manufacturing'
icon: 'view_in_ar'
},
{
id: 'resources_library',

14
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -1163,6 +1163,17 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
this.runChangeDetection();
}
private isAddingToScadaLayout(): boolean {
const layouts = this.dashboardConfiguration.states[this.dashboardCtx.state].layouts;
let layoutIds: DashboardLayoutId[];
if (this.addingLayoutCtx?.id) {
layoutIds = [this.addingLayoutCtx?.id];
} else {
layoutIds = Object.keys(layouts) as DashboardLayoutId[];
}
return layoutIds.every(id => layouts[id].gridSettings.isScada);
}
private selectTargetLayout(): Observable<DashboardLayoutId> {
const layouts = this.dashboardConfiguration.states[this.dashboardCtx.state].layouts;
const layoutIds = Object.keys(layouts);
@ -1208,6 +1219,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
col: 0
};
newWidget = this.dashboardUtils.validateAndUpdateWidget(newWidget);
if (this.isAddingToScadaLayout()) {
newWidget = this.dashboardUtils.prepareWidgetForScadaLayout(newWidget);
}
if (widgetTypeInfo.typeParameters.useCustomDatasources) {
this.addWidgetToDashboard(newWidget);
} else {

283
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html

@ -27,129 +27,149 @@
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div mat-dialog-content>
<fieldset [disabled]="isLoading$ | async">
<div *ngIf="settings" [formGroup]="settingsFormGroup" fxLayout="column">
<mat-form-field class="mat-block">
<mat-label translate>dashboard.state-controller</mat-label>
<div mat-dialog-content class="tb-form-panel no-border no-padding">
<div *ngIf="settings" class="tb-form-panel no-border no-padding" [formGroup]="settingsFormGroup">
<div class="tb-form-row space-between">
<div>{{ 'dashboard.state-controller' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select required formControlName="stateControllerId">
<mat-option *ngFor="let stateControllerId of stateControllerIds" [value]="stateControllerId">
{{ getStatesControllerTranslation(stateControllerId) }}
</mat-option>
</mat-select>
</mat-form-field>
<fieldset class="fields-group" fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px">
<legend class="group-title" translate>dashboard.title-settings</legend>
<mat-slide-toggle fxFlex formControlName="showTitle">
{{ 'dashboard.display-title' | translate }}
</div>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>dashboard.title-settings</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitle">
{{ 'dashboard.title' | translate }}
</mat-slide-toggle>
<tb-color-input fxFlex
label="{{'dashboard.title-color' | translate}}"
icon="format_color_fill"
openOnInput
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</fieldset>
<fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">
<legend class="group-title" translate>dashboard.dashboard-logo-settings</legend>
<mat-slide-toggle formControlName="showDashboardLogo">
</div>
</div>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>dashboard.dashboard-logo-settings</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showDashboardLogo">
{{ 'dashboard.display-dashboard-logo' | translate }}
</mat-slide-toggle>
<tb-gallery-image-input fxFlex
label="{{'dashboard.dashboard-logo-image' | translate}}"
formControlName="dashboardLogoUrl">
</tb-gallery-image-input>
</fieldset>
<fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">
<legend class="group-title" translate>dashboard.toolbar-settings</legend>
<mat-slide-toggle formControlName="hideToolbar">
{{ 'dashboard.hide-toolbar' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="toolbarAlwaysOpen">
{{ 'dashboard.toolbar-always-open' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showDashboardsSelect">
{{ 'dashboard.display-dashboards-selection' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showEntitiesSelect">
{{ 'dashboard.display-entities-selection' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showFilters">
{{ 'dashboard.display-filters' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showDashboardTimewindow">
{{ 'dashboard.display-dashboard-timewindow' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showDashboardExport">
{{ 'dashboard.display-dashboard-export' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showUpdateDashboardImage">
{{ 'dashboard.display-update-dashboard-image' | translate }}
</mat-slide-toggle>
</fieldset>
<mat-expansion-panel class="tb-settings">
<mat-expansion-panel-header>
<mat-panel-description fxLayoutAlign="end" translate>
dashboard.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-css
label="{{ 'dashboard.dashboard-css' | translate }}"
formControlName="dashboardCss"
></tb-css>
</ng-template>
</mat-expansion-panel>
</div>
<tb-gallery-image-input fxFlex
label="{{'dashboard.dashboard-logo-image' | translate}}"
formControlName="dashboardLogoUrl">
</tb-gallery-image-input>
</div>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>dashboard.toolbar-settings</div>
<mat-slide-toggle class="mat-slide" formControlName="hideToolbar">
{{ 'dashboard.hide-toolbar' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="toolbarAlwaysOpen">
{{ 'dashboard.toolbar-always-open' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showDashboardsSelect">
{{ 'dashboard.display-dashboards-selection' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showEntitiesSelect">
{{ 'dashboard.display-entities-selection' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showFilters">
{{ 'dashboard.display-filters' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showDashboardTimewindow">
{{ 'dashboard.display-dashboard-timewindow' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showDashboardExport">
{{ 'dashboard.display-dashboard-export' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="showUpdateDashboardImage">
{{ 'dashboard.display-update-dashboard-image' | translate }}
</mat-slide-toggle>
</div>
<mat-expansion-panel class="tb-settings">
<mat-expansion-panel-header>
<mat-panel-description fxLayoutAlign="end" translate>
dashboard.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-css
label="{{ 'dashboard.dashboard-css' | translate }}"
formControlName="dashboardCss"
></tb-css>
</ng-template>
</mat-expansion-panel>
</div>
<div *ngIf="gridSettings" class="tb-form-panel no-border no-padding" [formGroup]="gridSettingsFormGroup">
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="isScada">
{{ 'dashboard.scada-layout' | translate }}
</mat-slide-toggle>
</div>
<div *ngIf="gridSettings" [formGroup]="gridSettingsFormGroup" fxLayout="column">
<fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">
<legend class="group-title" translate>dashboard.layout-settings</legend>
<mat-form-field class="mat-block">
<mat-label translate>dashboard.columns-count</mat-label>
<input matInput formControlName="columns" type="number" step="any" min="10"
max="1000" required>
<mat-error *ngIf="gridSettingsFormGroup.get('columns').hasError('required')">
{{ 'dashboard.columns-count-required' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('columns').hasError('min')">
{{ 'dashboard.min-columns-count-message' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('columns').hasError('max')">
{{ 'dashboard.max-columns-count-message' | translate }}
</mat-error>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>dashboard.layout-settings</div>
<div class="tb-form-row space-between">
<div translate>dashboard.columns-count</div>
<mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
<input matInput formControlName="columns" type="number" min="10" max="1000" step="1"
required
placeholder="{{ 'widget-config.set' | translate }}">
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="(gridSettingsFormGroup.get('columns').hasError('required') ? 'dashboard.columns-count-required' :
(gridSettingsFormGroup.get('columns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate"
*ngIf="gridSettingsFormGroup.get('columns').invalid && gridSettingsFormGroup.get('columns').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>dashboard.widgets-margins</mat-label>
<input matInput formControlName="margin" type="number" step="any" min="0"
max="50" required>
<mat-error *ngIf="gridSettingsFormGroup.get('margin').hasError('required')">
{{ 'dashboard.margin-required' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('margin').hasError('min')">
{{ 'dashboard.min-margin-message' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('margin').hasError('max')">
{{ 'dashboard.max-margin-message' | translate }}
</mat-error>
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row space-between">
<div translate>dashboard.widgets-margins</div>
<mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
<input matInput formControlName="margin" type="number" min="0" max="50" step="any"
required
placeholder="{{ 'widget-config.set' | translate }}">
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="(gridSettingsFormGroup.get('margin').hasError('required') ? 'dashboard.margin-required' :
(gridSettingsFormGroup.get('margin').hasError('min') ? 'dashboard.min-margin-message' : 'dashboard.max-margin-message')) | translate"
*ngIf="gridSettingsFormGroup.get('margin').invalid && gridSettingsFormGroup.get('margin').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
<mat-slide-toggle fxFlex formControlName="outerMargin" style="display: block; padding-bottom: 12px;">
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="outerMargin">
{{ 'dashboard.apply-outer-margin' | translate }}
</mat-slide-toggle>
<mat-slide-toggle fxFlex formControlName="autoFillHeight" style="display: block; padding-bottom: 12px;">
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="autoFillHeight">
{{ 'dashboard.autofill-height' | translate }}
</mat-slide-toggle>
<tb-color-input fxFlex
label="{{'dashboard.background-color' | translate}}"
icon="format_color_fill"
openOnInput
</div>
<div class="tb-form-row space-between">
<div translate>dashboard.background-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="backgroundColor">
</tb-color-input>
<tb-gallery-image-input fxFlex
label="{{'dashboard.background-image' | translate}}"
formControlName="backgroundImageUrl">
</tb-gallery-image-input>
<mat-form-field class="mat-block">
<mat-label translate>dashboard.background-size-mode</mat-label>
</div>
<tb-gallery-image-input fxFlex
label="{{'dashboard.background-image' | translate}}"
formControlName="backgroundImageUrl">
</tb-gallery-image-input>
<div class="tb-form-row space-between">
<div>{{ 'dashboard.background-size-mode' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="backgroundSizeMode">
<mat-option value="100%">Fit width</mat-option>
<mat-option value="auto 100%">Fit height</mat-option>
@ -158,34 +178,41 @@
<mat-option value="auto">Original size</mat-option>
</mat-select>
</mat-form-field>
</fieldset>
<fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">
<legend class="group-title" translate>dashboard.mobile-layout</legend>
<mat-slide-toggle *ngIf="isRightLayout" fxFlex formControlName="mobileDisplayLayoutFirst" style="display: block;">
</div>
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value || isRightLayout" class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>dashboard.mobile-layout</div>
<div *ngIf="isRightLayout" class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="mobileDisplayLayoutFirst">
{{ 'dashboard.display-first-in-mobile-view' | translate }}
</mat-slide-toggle>
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px" >
<mat-slide-toggle fxFlex formControlName="mobileAutoFillHeight">
{{ 'dashboard.autofill-height' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>dashboard.mobile-row-height</mat-label>
<input matInput formControlName="mobileRowHeight" type="number" step="any" min="5"
max="200" required>
<mat-error *ngIf="gridSettingsFormGroup.get('mobileRowHeight').hasError('required')">
{{ 'dashboard.mobile-row-height-required' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('mobileRowHeight').hasError('min')">
{{ 'dashboard.min-mobile-row-height-message' | translate }}
</mat-error>
<mat-error *ngIf="gridSettingsFormGroup.get('mobileRowHeight').hasError('max')">
{{ 'dashboard.max-mobile-row-height-message' | translate }}
</mat-error>
</mat-form-field>
</div>
</fieldset>
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="mobileAutoFillHeight">
{{ 'dashboard.autofill-height' | translate }}
</mat-slide-toggle>
</div>
<div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row space-between">
<div translate>dashboard.mobile-row-height</div>
<mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
<input matInput formControlName="mobileRowHeight" type="number" min="5" max="200" step="any"
required
placeholder="{{ 'widget-config.set' | translate }}">
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="(gridSettingsFormGroup.get('mobileRowHeight').hasError('required') ? 'dashboard.mobile-row-height-required' :
(gridSettingsFormGroup.get('mobileRowHeight').hasError('min') ?
'dashboard.min-mobile-row-height-message' : 'dashboard.max-mobile-row-height-message')) | translate"
*ngIf="gridSettingsFormGroup.get('mobileRowHeight').invalid && gridSettingsFormGroup.get('mobileRowHeight').touched"
class="tb-error">
warning
</mat-icon>
<span matSuffix>px</span>
</mat-form-field>
</div>
</div>
</fieldset>
</div>
</div>
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-button color="primary"

39
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts

@ -26,6 +26,7 @@ import { TranslateService } from '@ngx-translate/core';
import { DashboardSettings, GridSettings, StateControllerId } from '@app/shared/models/dashboard.models';
import { isDefined, isUndefined } from '@core/utils';
import { StatesControllerService } from './states/states-controller.service';
import { merge } from 'rxjs';
export interface DashboardSettingsDialogData {
settings?: DashboardSettings;
@ -156,6 +157,7 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
if (this.gridSettings) {
const mobileAutoFillHeight = isUndefined(this.gridSettings.mobileAutoFillHeight) ? false : this.gridSettings.mobileAutoFillHeight;
this.gridSettingsFormGroup = this.fb.group({
isScada: [this.gridSettings.isScada, []],
columns: [this.gridSettings.columns || 24, [Validators.required, Validators.min(10), Validators.max(1000)]],
margin: [isDefined(this.gridSettings.margin) ? this.gridSettings.margin : 10,
[Validators.required, Validators.min(0), Validators.max(50)]],
@ -169,18 +171,17 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
disabled: mobileAutoFillHeight}, [Validators.required, Validators.min(5), Validators.max(200)]]
});
if (this.isRightLayout) {
const mobileDisplayLayoutFirst = isUndefined(this.gridSettings.mobileDisplayLayoutFirst) ? false : this.gridSettings.mobileDisplayLayoutFirst;
const mobileDisplayLayoutFirst =
isUndefined(this.gridSettings.mobileDisplayLayoutFirst) ? false : this.gridSettings.mobileDisplayLayoutFirst;
this.gridSettingsFormGroup.addControl('mobileDisplayLayoutFirst', this.fb.control(mobileDisplayLayoutFirst, []));
}
this.gridSettingsFormGroup.get('mobileAutoFillHeight').valueChanges.subscribe(
(mobileAutoFillHeightValue: boolean) => {
if (mobileAutoFillHeightValue) {
this.gridSettingsFormGroup.get('mobileRowHeight').disable();
} else {
this.gridSettingsFormGroup.get('mobileRowHeight').enable();
}
merge(this.gridSettingsFormGroup.get('isScada').valueChanges,
this.gridSettingsFormGroup.get('mobileAutoFillHeight').valueChanges).subscribe(
() => {
this.updateGridSettingsFormState();
}
);
this.updateGridSettingsFormState();
} else {
this.gridSettingsFormGroup = this.fb.group({});
}
@ -218,4 +219,26 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
}
return stateControllerId;
}
private updateGridSettingsFormState() {
const isScada: boolean = this.gridSettingsFormGroup.get('isScada').value;
if (isScada) {
this.gridSettingsFormGroup.get('margin').disable();
this.gridSettingsFormGroup.get('outerMargin').disable();
this.gridSettingsFormGroup.get('autoFillHeight').disable();
this.gridSettingsFormGroup.get('mobileAutoFillHeight').disable({emitEvent: false});
this.gridSettingsFormGroup.get('mobileRowHeight').disable();
} else {
this.gridSettingsFormGroup.get('margin').enable();
this.gridSettingsFormGroup.get('outerMargin').enable();
this.gridSettingsFormGroup.get('autoFillHeight').enable();
this.gridSettingsFormGroup.get('mobileAutoFillHeight').enable({emitEvent: false});
const mobileAutoFillHeight: boolean = this.gridSettingsFormGroup.get('mobileAutoFillHeight').value;
if (mobileAutoFillHeight) {
this.gridSettingsFormGroup.get('mobileRowHeight').disable();
} else {
this.gridSettingsFormGroup.get('mobileRowHeight').enable();
}
}
}
}

10
ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.html

@ -42,17 +42,17 @@
[widgets]="layoutCtx.widgets"
[widgetLayouts]="layoutCtx.widgetLayouts"
[columns]="layoutCtx.gridSettings.columns"
[outerMargin]="layoutCtx.gridSettings.outerMargin"
[margin]="layoutCtx.gridSettings.margin"
[outerMargin]="outerMargin"
[margin]="margin"
[aliasController]="dashboardCtx.aliasController"
[stateController]="dashboardCtx.stateController"
[dashboardTimewindow]="dashboardCtx.dashboardTimewindow"
[isEdit]="isEdit"
[autofillHeight]="layoutCtx.gridSettings.autoFillHeight && !isEdit"
[mobileAutofillHeight]="layoutCtx.gridSettings.mobileAutoFillHeight && !isEdit"
[autofillHeight]="autoFillHeight"
[mobileAutofillHeight]="mobileAutoFillHeight"
[mobileRowHeight]="layoutCtx.gridSettings.mobileRowHeight"
[isMobile]="isMobile"
[isMobileDisabled]="widgetEditMode"
[isMobileDisabled]="isMobileDisabled"
[disableWidgetInteraction]="isEdit"
[isEditActionEnabled]="isEdit"
[isExportActionEnabled]="isEdit && !widgetEditMode"

20
ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts

@ -66,6 +66,26 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo
return this.layoutCtxValue;
}
get outerMargin(): boolean {
return this.layoutCtx.gridSettings.isScada ? false : this.layoutCtx.gridSettings.outerMargin;
}
get margin(): number {
return this.layoutCtx.gridSettings.isScada ? 0 : this.layoutCtx.gridSettings.margin;
}
get autoFillHeight(): boolean {
return (this.isEdit || this.layoutCtx.gridSettings.isScada) ? false : this.layoutCtx.gridSettings.autoFillHeight;
}
get mobileAutoFillHeight(): boolean {
return (this.isEdit || this.layoutCtx.gridSettings.isScada) ? false : this.layoutCtx.gridSettings.mobileAutoFillHeight;
}
get isMobileDisabled(): boolean {
return this.widgetEditMode || this.layoutCtx.gridSettings.isScada;
}
@Input()
dashboardCtx: DashboardContext;

1
ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss

@ -45,6 +45,7 @@
display: flex;
align-items: center;
justify-content: center;
fill: none;
}
}
}

8
ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts

@ -482,7 +482,13 @@ export class ScadaSymbolObject {
this.svgShape = SVG().svg(doc.documentElement.innerHTML);
this.svgShape.node.style.overflow = 'visible';
this.svgShape.node.style['user-select'] = 'none';
this.box = this.svgShape.bbox();
const origSvg = SVG(doc.documentElement.outerHTML);
if (origSvg.type === 'svg') {
this.box = (origSvg as Svg).viewbox();
} else {
this.box = this.svgShape.bbox();
}
origSvg.remove();
this.svgShape.size(this.box.width, this.box.height);
this.svgShape.addTo(this.rootElement);
}

4
ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts

@ -118,7 +118,7 @@ const routes: Routes = [
data: {
breadcrumb: {
label: 'scada.symbols',
icon: 'precision_manufacturing'
icon: 'view_in_ar'
}
},
children: [
@ -138,7 +138,7 @@ const routes: Routes = [
data: {
breadcrumb: {
labelFunction: scadaSymbolBreadcumbLabelFunction,
icon: 'precision_manufacturing'
icon: 'view_in_ar'
} as BreadCrumbConfig<ScadaSymbolComponent>,
auth: [Authority.TENANT_ADMIN, Authority.SYS_ADMIN],
title: 'scada.symbol'

1
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss

@ -19,6 +19,7 @@
display: flex;
align-items: center;
justify-content: center;
fill: none;
}
.tb-scada-symbol-editor-tooltips {
position: absolute;

8
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts

@ -100,7 +100,13 @@ export class ScadaSymbolEditObject {
this.svgShape = SVG().svg(contentData.innerSvg);
this.svgShape.node.style.overflow = 'visible';
this.svgShape.node.style['user-select'] = 'none';
this.box = this.svgShape.bbox();
const origSvg = SVG(svgContent);
if (origSvg.type === 'svg') {
this.box = (origSvg as Svg).viewbox();
} else {
this.box = this.svgShape.bbox();
}
origSvg.remove();
this.svgShape.size(this.box.width, this.box.height);
this.svgShape.viewbox(`0 0 ${this.box.width} ${this.box.height}`);
this.svgShape.style().attr('tb:inner', true).rule('.tb-element', {cursor: 'pointer', transition: '0.2s filter ease-in-out'});

12
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts

@ -71,7 +71,7 @@ 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 { BackgroundType, colorBackground } from '@shared/models/widget-settings.models';
import { GridType } from 'angular-gridster2';
import {
SaveWidgetTypeAsDialogComponent, SaveWidgetTypeAsDialogData,
@ -259,15 +259,7 @@ export class ScadaSymbolComponent extends PageComponent
scadaSymbolContent: this.symbolData.scadaSymbolContent,
scadaSymbolObjectSettings: this.previewScadaSymbolObjectSettings,
padding: '0',
background: {
type: BackgroundType.color,
color: 'rgba(0,0,0,0)',
overlay: {
enabled: false,
color: 'rgba(255,255,255,0.72)',
blur: 3
}
}
background: colorBackground('rgba(0,0,0,0)')
}
};
this.previewWidget = {

1
ui-ngx/src/app/shared/models/dashboard.models.ts

@ -61,6 +61,7 @@ export interface GridSettings {
mobileRowHeight?: number;
mobileDisplayLayoutFirst?: boolean;
layoutDimension?: LayoutDimension;
isScada?: boolean;
[key: string]: any;
}

18
ui-ngx/src/app/shared/models/widget-settings.models.ts

@ -935,6 +935,24 @@ export interface BackgroundSettings {
overlay: OverlaySettings;
}
export const isBackgroundSettings = (background: any): background is BackgroundSettings => {
if (background && background.type && background.overlay && background.overlay.color) {
return true;
} else {
return false;
}
};
export const colorBackground = (color: string): BackgroundSettings => ({
type: BackgroundType.color,
color,
overlay: {
enabled: false,
color: 'rgba(255,255,255,0.72)',
blur: 3
}
});
export const iconStyle = (size: number | string, sizeUnit: cssUnit = 'px'): ComponentStyle => {
const iconSize = typeof size === 'number' ? size + sizeUnit : size;
return {

3
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1163,6 +1163,7 @@
"maximum-upload-file-size": "Maximum upload file size: {{ size }}",
"cannot-upload-file": "Cannot upload file",
"settings": "Settings",
"scada-layout": "SCADA layout",
"layout-settings": "Layout settings",
"columns-count": "Columns count",
"columns-count-required": "Columns count is required.",
@ -1183,7 +1184,7 @@
"apply-outer-margin": "Apply margin to the sides of the layout",
"autofill-height": "Auto fill layout height",
"mobile-layout": "Mobile layout settings",
"mobile-row-height": "Mobile row height, px",
"mobile-row-height": "Mobile row height",
"mobile-row-height-required": "Mobile row height value is required.",
"min-mobile-row-height-message": "Only 5 pixels is allowed as minimum mobile row height value.",
"max-mobile-row-height-message": "Only 200 pixels is allowed as maximum mobile row height value.",

Loading…
Cancel
Save