2019-09-19 20:10:52 +03:00
|
|
|
///
|
2024-01-09 10:46:16 +02:00
|
|
|
/// Copyright © 2016-2024 The Thingsboard Authors
|
2019-09-19 20:10:52 +03:00
|
|
|
///
|
|
|
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
/// you may not use this file except in compliance with the License.
|
|
|
|
|
/// You may obtain a copy of the License at
|
|
|
|
|
///
|
|
|
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
///
|
|
|
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
/// See the License for the specific language governing permissions and
|
|
|
|
|
/// limitations under the License.
|
|
|
|
|
///
|
|
|
|
|
|
|
|
|
|
import { Injectable } from '@angular/core';
|
|
|
|
|
import { UtilsService } from '@core/services/utils.service';
|
|
|
|
|
import { TimeService } from '@core/services/time.service';
|
|
|
|
|
import {
|
2024-08-05 00:49:43 +03:00
|
|
|
BreakpointLayoutInfo,
|
2019-09-19 20:10:52 +03:00
|
|
|
Dashboard,
|
2019-09-20 20:30:43 +03:00
|
|
|
DashboardConfiguration,
|
2019-11-15 12:22:14 +02:00
|
|
|
DashboardLayout,
|
|
|
|
|
DashboardLayoutId,
|
|
|
|
|
DashboardLayoutsInfo,
|
|
|
|
|
DashboardState,
|
|
|
|
|
DashboardStateLayouts,
|
|
|
|
|
GridSettings,
|
|
|
|
|
WidgetLayout
|
2019-09-19 20:10:52 +03:00
|
|
|
} from '@shared/models/dashboard.models';
|
2024-08-08 12:15:56 +03:00
|
|
|
import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined } from '@core/utils';
|
2023-05-16 20:00:53 +03:00
|
|
|
import {
|
|
|
|
|
Datasource,
|
2023-05-26 12:50:52 +03:00
|
|
|
datasourcesHasOnlyComparisonAggregation,
|
2023-05-16 20:00:53 +03:00
|
|
|
DatasourceType,
|
2024-01-23 20:03:14 +02:00
|
|
|
defaultLegendConfig,
|
|
|
|
|
isValidWidgetFullFqn,
|
|
|
|
|
TargetDevice,
|
|
|
|
|
TargetDeviceType,
|
2023-05-16 20:00:53 +03:00
|
|
|
Widget,
|
|
|
|
|
WidgetConfig,
|
2024-08-08 12:15:56 +03:00
|
|
|
WidgetConfigMode, WidgetSize,
|
2023-05-30 12:37:47 +03:00
|
|
|
widgetType,
|
|
|
|
|
WidgetTypeDescriptor
|
2023-05-16 20:00:53 +03:00
|
|
|
} from '@app/shared/models/widget.models';
|
2019-09-19 20:10:52 +03:00
|
|
|
import { EntityType } from '@shared/models/entity-type.models';
|
2019-11-15 12:22:14 +02:00
|
|
|
import { AliasFilterType, EntityAlias, EntityAliasFilter } from '@app/shared/models/alias.models';
|
|
|
|
|
import { EntityId } from '@app/shared/models/id/entity-id';
|
2022-09-13 14:07:56 +03:00
|
|
|
import { initModelFromDefaultTimewindow } from '@shared/models/time/time.models';
|
2023-04-21 18:00:56 +03:00
|
|
|
import { AlarmSearchStatus } from '@shared/models/alarm.models';
|
2023-05-30 12:37:47 +03:00
|
|
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
2024-06-11 18:44:50 +03:00
|
|
|
import { BackgroundType, colorBackground, isBackgroundSettings } from '@shared/models/widget-settings.models';
|
2019-09-19 20:10:52 +03:00
|
|
|
|
|
|
|
|
@Injectable({
|
|
|
|
|
providedIn: 'root'
|
|
|
|
|
})
|
|
|
|
|
export class DashboardUtilsService {
|
|
|
|
|
|
|
|
|
|
constructor(private utils: UtilsService,
|
|
|
|
|
private timeService: TimeService) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public validateAndUpdateDashboard(dashboard: Dashboard): Dashboard {
|
|
|
|
|
if (!dashboard.configuration) {
|
|
|
|
|
dashboard.configuration = {};
|
|
|
|
|
}
|
|
|
|
|
if (isUndefined(dashboard.configuration.widgets)) {
|
|
|
|
|
dashboard.configuration.widgets = {};
|
|
|
|
|
} else if (Array.isArray(dashboard.configuration.widgets)) {
|
|
|
|
|
const widgetsMap: {[id: string]: Widget} = {};
|
|
|
|
|
dashboard.configuration.widgets.forEach((widget) => {
|
|
|
|
|
if (!widget.id) {
|
|
|
|
|
widget.id = this.utils.guid();
|
|
|
|
|
}
|
|
|
|
|
widgetsMap[widget.id] = widget;
|
|
|
|
|
});
|
|
|
|
|
dashboard.configuration.widgets = widgetsMap;
|
|
|
|
|
}
|
|
|
|
|
for (const id of Object.keys(dashboard.configuration.widgets)) {
|
|
|
|
|
const widget = dashboard.configuration.widgets[id];
|
|
|
|
|
dashboard.configuration.widgets[id] = this.validateAndUpdateWidget(widget);
|
|
|
|
|
}
|
|
|
|
|
if (isUndefined(dashboard.configuration.states)) {
|
|
|
|
|
dashboard.configuration.states = {
|
|
|
|
|
default: this.createDefaultState(dashboard.title, true)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const mainLayout = dashboard.configuration.states.default.layouts.main;
|
|
|
|
|
for (const id of Object.keys(dashboard.configuration.widgets)) {
|
|
|
|
|
const widget = dashboard.configuration.widgets[id];
|
|
|
|
|
mainLayout.widgets[id] = {
|
|
|
|
|
sizeX: widget.sizeX,
|
|
|
|
|
sizeY: widget.sizeY,
|
|
|
|
|
row: widget.row,
|
|
|
|
|
col: widget.col
|
|
|
|
|
};
|
|
|
|
|
if (isDefined(widget.config.mobileHeight)) {
|
|
|
|
|
mainLayout.widgets[id].mobileHeight = widget.config.mobileHeight;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widget.config.mobileOrder)) {
|
|
|
|
|
mainLayout.widgets[id].mobileOrder = widget.config.mobileOrder;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const states = dashboard.configuration.states;
|
|
|
|
|
let rootFound = false;
|
|
|
|
|
for (const stateId of Object.keys(states)) {
|
|
|
|
|
const state = states[stateId];
|
|
|
|
|
if (isUndefined(state.root)) {
|
|
|
|
|
state.root = false;
|
|
|
|
|
} else if (state.root) {
|
|
|
|
|
rootFound = true;
|
|
|
|
|
}
|
2019-10-31 10:06:57 +02:00
|
|
|
this.validateAndUpdateState(state);
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
|
|
|
|
if (!rootFound) {
|
|
|
|
|
const firstStateId = Object.keys(states)[0];
|
|
|
|
|
states[firstStateId].root = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const datasourcesByAliasId: {[aliasId: string]: Array<Datasource>} = {};
|
2024-01-23 20:03:14 +02:00
|
|
|
const targetDevicesByAliasId: {[aliasId: string]: Array<TargetDevice>} = {};
|
2019-09-19 20:10:52 +03:00
|
|
|
for (const widgetId of Object.keys(dashboard.configuration.widgets)) {
|
|
|
|
|
const widget = dashboard.configuration.widgets[widgetId];
|
2022-07-13 11:02:05 +03:00
|
|
|
const datasources = widget.type === widgetType.alarm ? [widget.config.alarmSource] : widget.config.datasources;
|
|
|
|
|
datasources.forEach((datasource) => {
|
2019-09-19 20:10:52 +03:00
|
|
|
if (datasource.entityAliasId) {
|
|
|
|
|
const aliasId = datasource.entityAliasId;
|
|
|
|
|
let aliasDatasources = datasourcesByAliasId[aliasId];
|
|
|
|
|
if (!aliasDatasources) {
|
|
|
|
|
aliasDatasources = [];
|
|
|
|
|
datasourcesByAliasId[aliasId] = aliasDatasources;
|
|
|
|
|
}
|
|
|
|
|
aliasDatasources.push(datasource);
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-01-23 20:03:14 +02:00
|
|
|
if (widget.config.targetDevice?.type === TargetDeviceType.entity && widget.config.targetDevice.entityAliasId) {
|
|
|
|
|
const aliasId = widget.config.targetDevice.entityAliasId;
|
|
|
|
|
let targetDevicesList = targetDevicesByAliasId[aliasId];
|
|
|
|
|
if (!targetDevicesList) {
|
|
|
|
|
targetDevicesList = [];
|
|
|
|
|
targetDevicesByAliasId[aliasId] = targetDevicesList;
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
2024-01-23 20:03:14 +02:00
|
|
|
targetDevicesList.push(widget.config.targetDevice);
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dashboard.configuration = this.validateAndUpdateEntityAliases(dashboard.configuration, datasourcesByAliasId, targetDevicesByAliasId);
|
2020-06-30 19:37:50 +03:00
|
|
|
if (!dashboard.configuration.filters) {
|
|
|
|
|
dashboard.configuration.filters = {};
|
|
|
|
|
}
|
2019-09-19 20:10:52 +03:00
|
|
|
|
|
|
|
|
if (isUndefined(dashboard.configuration.timewindow)) {
|
|
|
|
|
dashboard.configuration.timewindow = this.timeService.defaultTimewindow();
|
|
|
|
|
}
|
|
|
|
|
if (isUndefined(dashboard.configuration.settings)) {
|
|
|
|
|
dashboard.configuration.settings = {};
|
|
|
|
|
dashboard.configuration.settings.stateControllerId = 'entity';
|
|
|
|
|
dashboard.configuration.settings.showTitle = false;
|
|
|
|
|
dashboard.configuration.settings.showDashboardsSelect = true;
|
|
|
|
|
dashboard.configuration.settings.showEntitiesSelect = true;
|
|
|
|
|
dashboard.configuration.settings.showDashboardTimewindow = true;
|
|
|
|
|
dashboard.configuration.settings.showDashboardExport = true;
|
|
|
|
|
dashboard.configuration.settings.toolbarAlwaysOpen = true;
|
|
|
|
|
} else {
|
|
|
|
|
if (isUndefined(dashboard.configuration.settings.stateControllerId)) {
|
|
|
|
|
dashboard.configuration.settings.stateControllerId = 'entity';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(dashboard.configuration.gridSettings)) {
|
|
|
|
|
const gridSettings = dashboard.configuration.gridSettings;
|
|
|
|
|
if (isDefined(gridSettings.showTitle)) {
|
|
|
|
|
dashboard.configuration.settings.showTitle = gridSettings.showTitle;
|
|
|
|
|
delete gridSettings.showTitle;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(gridSettings.titleColor)) {
|
|
|
|
|
dashboard.configuration.settings.titleColor = gridSettings.titleColor;
|
|
|
|
|
delete gridSettings.titleColor;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(gridSettings.showDevicesSelect)) {
|
|
|
|
|
dashboard.configuration.settings.showEntitiesSelect = gridSettings.showDevicesSelect;
|
|
|
|
|
delete gridSettings.showDevicesSelect;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(gridSettings.showEntitiesSelect)) {
|
|
|
|
|
dashboard.configuration.settings.showEntitiesSelect = gridSettings.showEntitiesSelect;
|
|
|
|
|
delete gridSettings.showEntitiesSelect;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(gridSettings.showDashboardTimewindow)) {
|
|
|
|
|
dashboard.configuration.settings.showDashboardTimewindow = gridSettings.showDashboardTimewindow;
|
|
|
|
|
delete gridSettings.showDashboardTimewindow;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(gridSettings.showDashboardExport)) {
|
|
|
|
|
dashboard.configuration.settings.showDashboardExport = gridSettings.showDashboardExport;
|
|
|
|
|
delete gridSettings.showDashboardExport;
|
|
|
|
|
}
|
|
|
|
|
dashboard.configuration.states.default.layouts.main.gridSettings = gridSettings;
|
|
|
|
|
delete dashboard.configuration.gridSettings;
|
|
|
|
|
}
|
|
|
|
|
return dashboard;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public createSingleWidgetDashboard(widget: Widget): Dashboard {
|
|
|
|
|
if (!widget.id) {
|
|
|
|
|
widget.id = this.utils.guid();
|
|
|
|
|
}
|
|
|
|
|
let dashboard: Dashboard = {};
|
|
|
|
|
dashboard = this.validateAndUpdateDashboard(dashboard);
|
|
|
|
|
dashboard.configuration.widgets[widget.id] = widget;
|
|
|
|
|
dashboard.configuration.states.default.layouts.main.widgets[widget.id] = {
|
|
|
|
|
sizeX: widget.sizeX,
|
|
|
|
|
sizeY: widget.sizeY,
|
|
|
|
|
row: widget.row,
|
|
|
|
|
col: widget.col,
|
|
|
|
|
};
|
|
|
|
|
return dashboard;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public validateAndUpdateWidget(widget: Widget): Widget {
|
2023-04-21 18:00:56 +03:00
|
|
|
widget.config = this.validateAndUpdateWidgetConfig(widget.config, widget.type);
|
2023-08-18 16:14:21 +03:00
|
|
|
widget = this.validateAndUpdateWidgetTypeFqn(widget);
|
2023-09-05 12:18:59 +03:00
|
|
|
if (isDefined((widget as any).title)) {
|
|
|
|
|
delete (widget as any).title;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined((widget as any).image)) {
|
|
|
|
|
delete (widget as any).image;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined((widget as any).description)) {
|
|
|
|
|
delete (widget as any).description;
|
|
|
|
|
}
|
2023-04-21 18:00:56 +03:00
|
|
|
// Temp workaround
|
2023-08-18 16:14:21 +03:00
|
|
|
if (['system.charts.state_chart',
|
|
|
|
|
'system.charts.basic_timeseries',
|
|
|
|
|
'system.charts.timeseries_bars_flot'].includes(widget.typeFullFqn)) {
|
2023-05-16 20:00:53 +03:00
|
|
|
const widgetConfig = widget.config;
|
|
|
|
|
const widgetSettings = widget.config.settings;
|
|
|
|
|
if (isDefinedAndNotNull(widgetConfig.showLegend)) {
|
|
|
|
|
widgetSettings.showLegend = widgetConfig.showLegend;
|
|
|
|
|
delete widgetConfig.showLegend;
|
|
|
|
|
} else if (isUndefined(widgetSettings.showLegend)) {
|
|
|
|
|
widgetSettings.showLegend = true;
|
|
|
|
|
}
|
|
|
|
|
if (isDefinedAndNotNull(widgetConfig.legendConfig)) {
|
|
|
|
|
widgetSettings.legendConfig = widgetConfig.legendConfig;
|
|
|
|
|
delete widgetConfig.legendConfig;
|
|
|
|
|
} else if (isUndefined(widgetSettings.legendConfig)) {
|
|
|
|
|
widgetSettings.legendConfig = defaultLegendConfig(widget.type);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-21 18:00:56 +03:00
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-18 16:14:21 +03:00
|
|
|
private validateAndUpdateWidgetTypeFqn(widget: Widget): Widget {
|
2023-09-05 12:18:59 +03:00
|
|
|
const w = widget as any;
|
2023-08-18 16:14:21 +03:00
|
|
|
if (!isValidWidgetFullFqn(widget.typeFullFqn)) {
|
|
|
|
|
if (isDefinedAndNotNull(w.isSystemType) && isNotEmptyStr(w.bundleAlias) && isNotEmptyStr(w.typeAlias)) {
|
|
|
|
|
widget.typeFullFqn = (w.isSystemType ? 'system' : 'tenant') + '.' + w.bundleAlias + '.' + w.typeAlias;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-05 12:18:59 +03:00
|
|
|
if (isDefined(w.isSystemType)) {
|
|
|
|
|
delete w.isSystemType;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(w.bundleAlias)) {
|
|
|
|
|
delete w.bundleAlias;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(w.typeAlias)) {
|
|
|
|
|
delete w.typeAlias;
|
|
|
|
|
}
|
2023-08-18 16:14:21 +03:00
|
|
|
// Temp workaround
|
|
|
|
|
if (widget.typeFullFqn === 'system.charts.timeseries') {
|
|
|
|
|
widget.typeFullFqn = 'system.charts.basic_timeseries';
|
|
|
|
|
}
|
|
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-21 18:00:56 +03:00
|
|
|
public validateAndUpdateWidgetConfig(widgetConfig: WidgetConfig | undefined, type: widgetType): WidgetConfig {
|
|
|
|
|
if (!widgetConfig) {
|
|
|
|
|
widgetConfig = {};
|
|
|
|
|
}
|
2024-01-23 20:03:14 +02:00
|
|
|
widgetConfig.datasources = this.validateAndUpdateDatasources(widgetConfig.datasources);
|
2023-04-21 18:00:56 +03:00
|
|
|
if (type === widgetType.latest) {
|
2023-05-26 12:50:52 +03:00
|
|
|
const onlyHistoryTimewindow = datasourcesHasOnlyComparisonAggregation(widgetConfig.datasources);
|
2023-05-26 16:57:50 +03:00
|
|
|
widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, onlyHistoryTimewindow, this.timeService);
|
2024-01-23 20:03:14 +02:00
|
|
|
} else if (type === widgetType.rpc) {
|
|
|
|
|
if (widgetConfig.targetDeviceAliasIds && widgetConfig.targetDeviceAliasIds.length) {
|
|
|
|
|
widgetConfig.targetDevice = {
|
|
|
|
|
type: TargetDeviceType.entity,
|
|
|
|
|
entityAliasId: widgetConfig.targetDeviceAliasIds[0]
|
|
|
|
|
};
|
|
|
|
|
delete widgetConfig.targetDeviceAliasIds;
|
|
|
|
|
} else if (!widgetConfig.targetDevice) {
|
|
|
|
|
widgetConfig.targetDevice = {
|
|
|
|
|
type: TargetDeviceType.device
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} else if (type === widgetType.alarm) {
|
2023-04-21 18:00:56 +03:00
|
|
|
if (!widgetConfig.alarmFilterConfig) {
|
|
|
|
|
widgetConfig.alarmFilterConfig = {};
|
|
|
|
|
const alarmFilterConfig = widgetConfig.alarmFilterConfig;
|
|
|
|
|
if (isDefined(widgetConfig.alarmStatusList) && widgetConfig.alarmStatusList.length) {
|
|
|
|
|
alarmFilterConfig.statusList = widgetConfig.alarmStatusList;
|
|
|
|
|
} else if (isDefined(widgetConfig.alarmSearchStatus) && widgetConfig.alarmSearchStatus !== AlarmSearchStatus.ANY) {
|
|
|
|
|
alarmFilterConfig.statusList = [widgetConfig.alarmSearchStatus];
|
|
|
|
|
} else {
|
|
|
|
|
alarmFilterConfig.statusList = [];
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widgetConfig.alarmStatusList)) {
|
|
|
|
|
delete widgetConfig.alarmStatusList;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widgetConfig.alarmSearchStatus)) {
|
|
|
|
|
delete widgetConfig.alarmSearchStatus;
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widgetConfig.alarmSeverityList)) {
|
|
|
|
|
alarmFilterConfig.severityList = widgetConfig.alarmSeverityList;
|
|
|
|
|
delete widgetConfig.alarmSeverityList;
|
|
|
|
|
} else {
|
|
|
|
|
alarmFilterConfig.severityList = [];
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widgetConfig.alarmTypeList)) {
|
|
|
|
|
alarmFilterConfig.typeList = widgetConfig.alarmTypeList;
|
|
|
|
|
delete widgetConfig.alarmTypeList;
|
|
|
|
|
} else {
|
|
|
|
|
alarmFilterConfig.typeList = [];
|
|
|
|
|
}
|
|
|
|
|
if (isDefined(widgetConfig.searchPropagatedAlarms)) {
|
|
|
|
|
alarmFilterConfig.searchPropagatedAlarms = widgetConfig.searchPropagatedAlarms;
|
|
|
|
|
delete widgetConfig.searchPropagatedAlarms;
|
|
|
|
|
} else {
|
|
|
|
|
alarmFilterConfig.searchPropagatedAlarms = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
2023-04-21 18:00:56 +03:00
|
|
|
return widgetConfig;
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-11 18:44:50 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-23 20:03:14 +02:00
|
|
|
public validateAndUpdateDatasources(datasources?: Datasource[]): Datasource[] {
|
|
|
|
|
if (!datasources) {
|
|
|
|
|
datasources = [];
|
|
|
|
|
}
|
|
|
|
|
datasources.forEach((datasource) => {
|
|
|
|
|
if (datasource.deviceAliasId) {
|
|
|
|
|
datasource.type = DatasourceType.entity;
|
|
|
|
|
datasource.entityAliasId = datasource.deviceAliasId;
|
|
|
|
|
delete datasource.deviceAliasId;
|
|
|
|
|
}
|
|
|
|
|
if (datasource.deviceName) {
|
|
|
|
|
datasource.entityName = datasource.deviceName;
|
|
|
|
|
delete datasource.deviceName;
|
|
|
|
|
}
|
|
|
|
|
if (datasource.type === DatasourceType.entity && datasource.entityId) {
|
|
|
|
|
datasource.name = datasource.entityName;
|
|
|
|
|
}
|
|
|
|
|
if (!datasource.dataKeys) {
|
|
|
|
|
datasource.dataKeys = [];
|
|
|
|
|
}
|
|
|
|
|
datasource.dataKeys.forEach(dataKey => {
|
|
|
|
|
if (isUndefined(dataKey.label)) {
|
|
|
|
|
dataKey.label = dataKey.name;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return datasources;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 20:10:52 +03:00
|
|
|
public createDefaultLayoutData(): DashboardLayout {
|
|
|
|
|
return {
|
|
|
|
|
widgets: {},
|
2019-10-31 10:06:57 +02:00
|
|
|
gridSettings: this.createDefaultGridSettings()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private createDefaultGridSettings(): GridSettings {
|
|
|
|
|
return {
|
|
|
|
|
backgroundColor: '#eeeeee',
|
|
|
|
|
columns: 24,
|
|
|
|
|
margin: 10,
|
2023-04-13 12:59:01 +03:00
|
|
|
outerMargin: true,
|
2019-10-31 10:06:57 +02:00
|
|
|
backgroundSizeMode: '100%'
|
2019-09-19 20:10:52 +03:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public createDefaultLayouts(): DashboardStateLayouts {
|
|
|
|
|
return {
|
|
|
|
|
main: this.createDefaultLayoutData()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public createDefaultState(name: string, root: boolean): DashboardState {
|
|
|
|
|
return {
|
|
|
|
|
name,
|
|
|
|
|
root,
|
|
|
|
|
layouts: this.createDefaultLayouts()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 12:22:14 +02:00
|
|
|
public createSingleEntityFilter(entityId: EntityId): EntityAliasFilter {
|
|
|
|
|
return {
|
|
|
|
|
type: AliasFilterType.singleEntity,
|
|
|
|
|
singleEntity: entityId,
|
|
|
|
|
resolveMultiple: false
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-30 12:37:47 +03:00
|
|
|
public widgetConfigFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor): WidgetConfig {
|
|
|
|
|
const config: WidgetConfig = JSON.parse(widgetTypeDescriptor.defaultConfig);
|
|
|
|
|
config.datasources = this.convertDatasourcesFromWidgetType(widgetTypeDescriptor, config, config.datasources);
|
|
|
|
|
if (isDefinedAndNotNull(config.alarmSource)) {
|
|
|
|
|
config.alarmSource = this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, config.alarmSource);
|
|
|
|
|
}
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private convertDatasourcesFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor,
|
|
|
|
|
config: WidgetConfig, datasources?: Datasource[]): Datasource[] {
|
|
|
|
|
const newDatasources: Datasource[] = [];
|
2023-07-27 17:18:39 +03:00
|
|
|
if (datasources?.length) {
|
|
|
|
|
newDatasources.push(this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, datasources[0]));
|
2023-05-30 12:37:47 +03:00
|
|
|
}
|
|
|
|
|
return newDatasources;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private convertDatasourceFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor, config: WidgetConfig,
|
|
|
|
|
datasource: Datasource): Datasource {
|
|
|
|
|
const newDatasource = deepClone(datasource);
|
|
|
|
|
if (newDatasource.type === DatasourceType.function) {
|
|
|
|
|
newDatasource.type = DatasourceType.entity;
|
2023-09-15 10:44:37 +03:00
|
|
|
newDatasource.name = '';
|
2023-05-30 12:37:47 +03:00
|
|
|
if (widgetTypeDescriptor.hasBasicMode && config.configMode === WidgetConfigMode.basic) {
|
|
|
|
|
newDatasource.type = DatasourceType.device;
|
|
|
|
|
}
|
|
|
|
|
const dataKeys = newDatasource.dataKeys;
|
|
|
|
|
newDatasource.dataKeys = [];
|
2023-06-06 17:20:35 +03:00
|
|
|
if (widgetTypeDescriptor.type === widgetType.alarm) {
|
|
|
|
|
dataKeys.forEach(dataKey => {
|
|
|
|
|
const newDataKey = deepClone(dataKey);
|
|
|
|
|
newDataKey.funcBody = null;
|
|
|
|
|
newDataKey.type = DataKeyType.alarm;
|
|
|
|
|
newDatasource.dataKeys.push(newDataKey);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-05-30 12:37:47 +03:00
|
|
|
}
|
|
|
|
|
return newDatasource;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-31 10:06:57 +02:00
|
|
|
private validateAndUpdateState(state: DashboardState) {
|
|
|
|
|
if (!state.layouts) {
|
|
|
|
|
state.layouts = this.createDefaultLayouts();
|
|
|
|
|
}
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
|
|
|
|
const layout = state.layouts[l as DashboardLayoutId];
|
|
|
|
|
this.validateAndUpdateLayout(layout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private validateAndUpdateLayout(layout: DashboardLayout) {
|
|
|
|
|
if (!layout.gridSettings) {
|
|
|
|
|
layout.gridSettings = this.createDefaultGridSettings();
|
|
|
|
|
}
|
|
|
|
|
if (layout.gridSettings.margins && layout.gridSettings.margins.length === 2) {
|
|
|
|
|
layout.gridSettings.margin = layout.gridSettings.margins[0];
|
|
|
|
|
delete layout.gridSettings.margins;
|
|
|
|
|
}
|
2023-04-13 12:59:01 +03:00
|
|
|
layout.gridSettings.outerMargin = isDefined(layout.gridSettings.outerMargin) ? layout.gridSettings.outerMargin : true;
|
2020-05-25 17:22:17 +03:00
|
|
|
layout.gridSettings.margin = isDefined(layout.gridSettings.margin) ? layout.gridSettings.margin : 10;
|
2019-10-31 10:06:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public setLayouts(dashboard: Dashboard, targetState: string, newLayouts: DashboardStateLayouts) {
|
|
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const state = states[targetState];
|
|
|
|
|
let addedCount = 0;
|
|
|
|
|
let removedCount = 0;
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
|
|
|
|
if (!newLayouts[l]) {
|
|
|
|
|
removedCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const l of Object.keys(newLayouts)) {
|
|
|
|
|
if (!state.layouts[l]) {
|
|
|
|
|
addedCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
state.layouts = newLayouts;
|
|
|
|
|
const layoutsCount = Object.keys(state.layouts).length;
|
|
|
|
|
let newColumns;
|
|
|
|
|
if (addedCount) {
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
|
|
|
|
newColumns = state.layouts[l].gridSettings.columns * (layoutsCount - addedCount) / layoutsCount;
|
|
|
|
|
if (newColumns > 0) {
|
|
|
|
|
state.layouts[l].gridSettings.columns = newColumns;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (removedCount) {
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
|
|
|
|
newColumns = state.layouts[l].gridSettings.columns * (layoutsCount + removedCount) / layoutsCount;
|
|
|
|
|
if (newColumns > 0) {
|
|
|
|
|
state.layouts[l].gridSettings.columns = newColumns;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.removeUnusedWidgets(dashboard);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-05 23:24:09 +03:00
|
|
|
public isReferenceWidget(dashboard: Dashboard, widgetId: string): boolean {
|
|
|
|
|
const states = dashboard.configuration.states;
|
|
|
|
|
let foundWidgetRefs = 0;
|
|
|
|
|
|
|
|
|
|
for (const state of Object.values(states)) {
|
|
|
|
|
for (const layout of Object.values(state.layouts)) {
|
|
|
|
|
if (layout.widgets[widgetId]) {
|
|
|
|
|
foundWidgetRefs++;
|
|
|
|
|
}
|
|
|
|
|
if (layout.breakpoints) {
|
|
|
|
|
for (const breakpoint of Object.values(layout.breakpoints)) {
|
|
|
|
|
if (breakpoint.widgets[widgetId]) {
|
|
|
|
|
foundWidgetRefs++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return foundWidgetRefs > 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-20 20:30:43 +03:00
|
|
|
public getRootStateId(states: {[id: string]: DashboardState }): string {
|
|
|
|
|
for (const stateId of Object.keys(states)) {
|
|
|
|
|
const state = states[stateId];
|
|
|
|
|
if (state.root) {
|
|
|
|
|
return stateId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Object.keys(states)[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getStateLayoutsData(dashboard: Dashboard, targetState: string): DashboardLayoutsInfo {
|
|
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const state = states[targetState];
|
|
|
|
|
if (state) {
|
|
|
|
|
const result: DashboardLayoutsInfo = {};
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
|
|
|
|
const layout: DashboardLayout = state.layouts[l];
|
|
|
|
|
if (layout) {
|
2024-08-05 00:49:43 +03:00
|
|
|
result[l]= {
|
|
|
|
|
default: this.getBreakpointLayoutData(layout)
|
|
|
|
|
};
|
|
|
|
|
if (layout.breakpoints) {
|
|
|
|
|
for (const breakpoint of Object.keys(layout.breakpoints)) {
|
|
|
|
|
result[l][breakpoint] = this.getBreakpointLayoutData(layout.breakpoints[breakpoint]);
|
|
|
|
|
}
|
2019-09-20 20:30:43 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-05 00:49:43 +03:00
|
|
|
private getBreakpointLayoutData(layout: DashboardLayout): BreakpointLayoutInfo {
|
|
|
|
|
const result: BreakpointLayoutInfo = {
|
|
|
|
|
widgetIds: [],
|
|
|
|
|
widgetLayouts: {},
|
|
|
|
|
gridSettings: {}
|
|
|
|
|
};
|
|
|
|
|
for (const id of Object.keys(layout.widgets)) {
|
|
|
|
|
result.widgetIds.push(id);
|
|
|
|
|
}
|
|
|
|
|
result.widgetLayouts = layout.widgets;
|
|
|
|
|
result.gridSettings = layout.gridSettings;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-10 13:00:29 +03:00
|
|
|
public getWidgetsArray(dashboard: Dashboard): Array<Widget> {
|
|
|
|
|
const widgetsArray: Array<Widget> = [];
|
|
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const widgets = dashboardConfiguration.widgets;
|
|
|
|
|
for (const widgetId of Object.keys(widgets)) {
|
|
|
|
|
const widget = widgets[widgetId];
|
|
|
|
|
widgetsArray.push(widget);
|
|
|
|
|
}
|
|
|
|
|
return widgetsArray;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-17 13:09:16 +03:00
|
|
|
public isEmptyDashboard(dashboard: Dashboard): boolean {
|
|
|
|
|
if (dashboard?.configuration?.widgets) {
|
|
|
|
|
return Object.keys(dashboard?.configuration?.widgets).length === 0;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-31 10:06:57 +02:00
|
|
|
public addWidgetToLayout(dashboard: Dashboard,
|
|
|
|
|
targetState: string,
|
|
|
|
|
targetLayout: DashboardLayoutId,
|
|
|
|
|
widget: Widget,
|
|
|
|
|
originalColumns?: number,
|
2023-05-30 12:37:47 +03:00
|
|
|
originalSize?: {sizeX: number; sizeY: number},
|
2019-10-31 10:06:57 +02:00
|
|
|
row?: number,
|
2024-08-05 00:49:43 +03:00
|
|
|
column?: number,
|
|
|
|
|
breakpoint = 'default'): void {
|
2019-10-31 10:06:57 +02:00
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const state = states[targetState];
|
2024-08-05 00:49:43 +03:00
|
|
|
let layout = state.layouts[targetLayout];
|
|
|
|
|
if (breakpoint !== 'default' && layout.breakpoints?.[breakpoint]) {
|
|
|
|
|
layout = layout.breakpoints[breakpoint];
|
|
|
|
|
}
|
2019-10-31 10:06:57 +02:00
|
|
|
const layoutCount = Object.keys(state.layouts).length;
|
|
|
|
|
if (!widget.id) {
|
|
|
|
|
widget.id = this.utils.guid();
|
|
|
|
|
}
|
|
|
|
|
if (!dashboardConfiguration.widgets[widget.id]) {
|
|
|
|
|
dashboardConfiguration.widgets[widget.id] = widget;
|
|
|
|
|
}
|
|
|
|
|
const widgetLayout: WidgetLayout = {
|
|
|
|
|
sizeX: originalSize ? originalSize.sizeX : widget.sizeX,
|
|
|
|
|
sizeY: originalSize ? originalSize.sizeY : widget.sizeY,
|
|
|
|
|
mobileOrder: widget.config.mobileOrder,
|
2021-07-22 15:44:40 +03:00
|
|
|
mobileHeight: widget.config.mobileHeight,
|
2022-11-20 00:32:32 +05:00
|
|
|
mobileHide: widget.config.mobileHide,
|
|
|
|
|
desktopHide: widget.config.desktopHide
|
2019-10-31 10:06:57 +02:00
|
|
|
};
|
|
|
|
|
if (isUndefined(originalColumns)) {
|
|
|
|
|
originalColumns = 24;
|
|
|
|
|
}
|
|
|
|
|
const gridSettings = layout.gridSettings;
|
2024-06-14 17:59:28 +03:00
|
|
|
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;
|
2019-10-31 10:06:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (row > -1 && column > - 1) {
|
|
|
|
|
widgetLayout.row = row;
|
|
|
|
|
widgetLayout.col = column;
|
|
|
|
|
} else {
|
|
|
|
|
row = 0;
|
|
|
|
|
for (const w of Object.keys(layout.widgets)) {
|
|
|
|
|
const existingLayout = layout.widgets[w];
|
|
|
|
|
const wRow = existingLayout.row ? existingLayout.row : 0;
|
|
|
|
|
const wSizeY = existingLayout.sizeY ? existingLayout.sizeY : 1;
|
|
|
|
|
const bottom = wRow + wSizeY;
|
|
|
|
|
row = Math.max(row, bottom);
|
|
|
|
|
}
|
|
|
|
|
widgetLayout.row = row;
|
|
|
|
|
widgetLayout.col = 0;
|
|
|
|
|
}
|
2020-11-11 15:13:59 +02:00
|
|
|
|
|
|
|
|
widgetLayout.sizeX = Math.floor(widgetLayout.sizeX);
|
|
|
|
|
widgetLayout.sizeY = Math.floor(widgetLayout.sizeY);
|
|
|
|
|
widgetLayout.row = Math.floor(widgetLayout.row);
|
|
|
|
|
widgetLayout.col = Math.floor(widgetLayout.col);
|
|
|
|
|
|
2019-10-31 10:06:57 +02:00
|
|
|
layout.widgets[widget.id] = widgetLayout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public removeWidgetFromLayout(dashboard: Dashboard,
|
|
|
|
|
targetState: string,
|
|
|
|
|
targetLayout: DashboardLayoutId,
|
2024-08-05 00:49:43 +03:00
|
|
|
widgetId: string,
|
|
|
|
|
breakpoint: string) {
|
2019-10-31 10:06:57 +02:00
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const state = states[targetState];
|
|
|
|
|
const layout = state.layouts[targetLayout];
|
2024-08-05 00:49:43 +03:00
|
|
|
if (layout.breakpoints[breakpoint]) {
|
|
|
|
|
delete layout.breakpoints[breakpoint].widgets[widgetId];
|
|
|
|
|
} else {
|
|
|
|
|
delete layout.widgets[widgetId];
|
|
|
|
|
}
|
2019-10-31 10:06:57 +02:00
|
|
|
this.removeUnusedWidgets(dashboard);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-30 12:37:47 +03:00
|
|
|
public isSingleLayoutDashboard(dashboard: Dashboard): {state: string; layout: DashboardLayoutId} {
|
2019-10-31 10:06:57 +02:00
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const stateKeys = Object.keys(states);
|
|
|
|
|
if (stateKeys.length === 1) {
|
|
|
|
|
const state = states[stateKeys[0]];
|
|
|
|
|
const layouts = state.layouts;
|
|
|
|
|
const layoutKeys = Object.keys(layouts);
|
|
|
|
|
if (layoutKeys.length === 1) {
|
|
|
|
|
return {
|
|
|
|
|
state: stateKeys[0],
|
|
|
|
|
layout: layoutKeys[0] as DashboardLayoutId
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public updateLayoutSettings(layout: DashboardLayout, gridSettings: GridSettings) {
|
|
|
|
|
const prevGridSettings = layout.gridSettings;
|
|
|
|
|
let prevColumns = prevGridSettings ? prevGridSettings.columns : 24;
|
|
|
|
|
if (!prevColumns) {
|
|
|
|
|
prevColumns = 24;
|
|
|
|
|
}
|
|
|
|
|
const columns = gridSettings.columns || 24;
|
|
|
|
|
const ratio = columns / prevColumns;
|
|
|
|
|
layout.gridSettings = gridSettings;
|
2024-06-14 17:59:28 +03:00
|
|
|
for (const w of Object.keys(layout.widgets)) {
|
|
|
|
|
const widget = layout.widgets[w];
|
|
|
|
|
if (!widget.sizeX) {
|
|
|
|
|
widget.sizeX = 1;
|
2024-06-11 18:44:50 +03:00
|
|
|
}
|
2024-06-14 17:59:28 +03:00
|
|
|
if (!widget.sizeY) {
|
|
|
|
|
widget.sizeY = 1;
|
2019-10-31 10:06:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-06-14 17:59:28 +03:00
|
|
|
for (const w of Object.keys(layout.widgets)) {
|
|
|
|
|
const widget = layout.widgets[w];
|
|
|
|
|
widget.row = Math.round(widget.row * ratio);
|
|
|
|
|
widget.col = Math.round(widget.col * ratio);
|
|
|
|
|
widget.sizeX = Math.round(widget.sizeX * ratio);
|
|
|
|
|
widget.sizeY = Math.round(widget.sizeY * ratio);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public moveWidgets(layout: DashboardLayout, cols: number, rows: number) {
|
|
|
|
|
cols = isDefinedAndNotNull(cols) ? Math.round(cols) : 0;
|
|
|
|
|
rows = isDefinedAndNotNull(rows) ? Math.round(rows) : 0;
|
|
|
|
|
for (const w of Object.keys(layout.widgets)) {
|
|
|
|
|
const widget = layout.widgets[w];
|
|
|
|
|
widget.col = Math.max(0, widget.col + cols);
|
|
|
|
|
widget.row = Math.max(0, widget.row + rows);
|
|
|
|
|
}
|
2019-10-31 10:06:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-04 15:47:36 +02:00
|
|
|
public removeUnusedWidgets(dashboard: Dashboard) {
|
2019-10-31 10:06:57 +02:00
|
|
|
const dashboardConfiguration = dashboard.configuration;
|
|
|
|
|
const states = dashboardConfiguration.states;
|
|
|
|
|
const widgets = dashboardConfiguration.widgets;
|
|
|
|
|
for (const widgetId of Object.keys(widgets)) {
|
|
|
|
|
let found = false;
|
|
|
|
|
for (const s of Object.keys(states)) {
|
|
|
|
|
const state = states[s];
|
|
|
|
|
for (const l of Object.keys(state.layouts)) {
|
2024-08-05 00:49:43 +03:00
|
|
|
const layout: DashboardLayout = state.layouts[l];
|
2019-10-31 10:06:57 +02:00
|
|
|
if (layout.widgets[widgetId]) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-05 00:49:43 +03:00
|
|
|
if (layout.breakpoints) {
|
|
|
|
|
for (const breakpoint of Object.keys(layout.breakpoints)) {
|
|
|
|
|
if (layout.breakpoints[breakpoint].widgets[widgetId]) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-31 10:06:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
delete dashboardConfiguration.widgets[widgetId];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 20:10:52 +03:00
|
|
|
private validateAndUpdateEntityAliases(configuration: DashboardConfiguration,
|
|
|
|
|
datasourcesByAliasId: {[aliasId: string]: Array<Datasource>},
|
2024-01-23 20:03:14 +02:00
|
|
|
targetDevicesByAliasId: {[aliasId: string]: Array<TargetDevice>}): DashboardConfiguration {
|
2019-09-19 20:10:52 +03:00
|
|
|
let entityAlias: EntityAlias;
|
|
|
|
|
if (isUndefined(configuration.entityAliases)) {
|
|
|
|
|
configuration.entityAliases = {};
|
|
|
|
|
if (configuration.deviceAliases) {
|
|
|
|
|
const deviceAliases = configuration.deviceAliases;
|
|
|
|
|
for (const aliasId of Object.keys(deviceAliases)) {
|
|
|
|
|
const deviceAlias = deviceAliases[aliasId];
|
|
|
|
|
entityAlias = this.validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId);
|
|
|
|
|
configuration.entityAliases[entityAlias.id] = entityAlias;
|
|
|
|
|
}
|
|
|
|
|
delete configuration.deviceAliases;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const entityAliases = configuration.entityAliases;
|
|
|
|
|
for (const aliasId of Object.keys(entityAliases)) {
|
|
|
|
|
entityAlias = entityAliases[aliasId];
|
|
|
|
|
entityAlias = this.validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId);
|
|
|
|
|
if (aliasId !== entityAlias.id) {
|
|
|
|
|
delete entityAliases[aliasId];
|
|
|
|
|
}
|
|
|
|
|
entityAliases[entityAlias.id] = entityAlias;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return configuration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private validateAndUpdateDeviceAlias(aliasId: string,
|
|
|
|
|
deviceAlias: any,
|
|
|
|
|
datasourcesByAliasId: {[aliasId: string]: Array<Datasource>},
|
2024-01-23 20:03:14 +02:00
|
|
|
targetDevicesByAliasId: {[aliasId: string]: Array<TargetDevice>}): EntityAlias {
|
2019-09-19 20:10:52 +03:00
|
|
|
aliasId = this.validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
|
|
|
|
|
const alias = deviceAlias.alias;
|
|
|
|
|
const entityAlias: EntityAlias = {
|
|
|
|
|
id: aliasId,
|
|
|
|
|
alias,
|
|
|
|
|
filter: {
|
|
|
|
|
type: null,
|
|
|
|
|
entityType: EntityType.DEVICE,
|
|
|
|
|
resolveMultiple: false
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
if (deviceAlias.deviceFilter) {
|
|
|
|
|
entityAlias.filter.type =
|
|
|
|
|
deviceAlias.deviceFilter.useFilter ? AliasFilterType.entityName : AliasFilterType.entityList;
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.entityList) {
|
|
|
|
|
entityAlias.filter.entityList = deviceAlias.deviceFilter.deviceList;
|
|
|
|
|
} else {
|
|
|
|
|
entityAlias.filter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
entityAlias.filter.type = AliasFilterType.entityList;
|
|
|
|
|
entityAlias.filter.entityList = [deviceAlias.deviceId];
|
|
|
|
|
}
|
|
|
|
|
return entityAlias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private validateAndUpdateEntityAlias(aliasId: string, entityAlias: EntityAlias,
|
|
|
|
|
datasourcesByAliasId: {[aliasId: string]: Array<Datasource>},
|
2024-01-23 20:03:14 +02:00
|
|
|
targetDevicesByAliasId: {[aliasId: string]: Array<TargetDevice>}): EntityAlias {
|
2019-09-19 20:10:52 +03:00
|
|
|
entityAlias.id = this.validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
|
|
|
|
|
if (!entityAlias.filter) {
|
|
|
|
|
entityAlias.filter = {
|
|
|
|
|
type: entityAlias.entityFilter.useFilter ? AliasFilterType.entityName : AliasFilterType.entityList,
|
|
|
|
|
entityType: entityAlias.entityType,
|
|
|
|
|
resolveMultiple: false
|
|
|
|
|
};
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.entityList) {
|
|
|
|
|
entityAlias.filter.entityList = entityAlias.entityFilter.entityList;
|
|
|
|
|
} else {
|
|
|
|
|
entityAlias.filter.entityNameFilter = entityAlias.entityFilter.entityNameFilter;
|
|
|
|
|
}
|
|
|
|
|
delete entityAlias.entityType;
|
|
|
|
|
delete entityAlias.entityFilter;
|
|
|
|
|
}
|
2023-03-03 10:17:42 +02:00
|
|
|
entityAlias = this.validateAndUpdateEntityAliasSingleTypeFilters(entityAlias);
|
|
|
|
|
return entityAlias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private validateAndUpdateEntityAliasSingleTypeFilters(entityAlias: EntityAlias): EntityAlias {
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.deviceType) {
|
|
|
|
|
if (entityAlias.filter.deviceType) {
|
|
|
|
|
if (!entityAlias.filter.deviceTypes) {
|
|
|
|
|
entityAlias.filter.deviceTypes = [];
|
|
|
|
|
}
|
|
|
|
|
entityAlias.filter.deviceTypes.push(entityAlias.filter.deviceType);
|
|
|
|
|
delete entityAlias.filter.deviceType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.assetType) {
|
|
|
|
|
if (entityAlias.filter.assetType) {
|
|
|
|
|
if (!entityAlias.filter.assetTypes) {
|
|
|
|
|
entityAlias.filter.assetTypes = [];
|
|
|
|
|
}
|
|
|
|
|
entityAlias.filter.assetTypes.push(entityAlias.filter.assetType);
|
|
|
|
|
delete entityAlias.filter.assetType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.entityViewType) {
|
|
|
|
|
if (entityAlias.filter.entityViewType) {
|
|
|
|
|
if (!entityAlias.filter.entityViewTypes) {
|
|
|
|
|
entityAlias.filter.entityViewTypes = [];
|
|
|
|
|
}
|
|
|
|
|
entityAlias.filter.entityViewTypes.push(entityAlias.filter.entityViewType);
|
|
|
|
|
delete entityAlias.filter.entityViewType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (entityAlias.filter.type === AliasFilterType.edgeType) {
|
|
|
|
|
if (entityAlias.filter.edgeType) {
|
|
|
|
|
if (!entityAlias.filter.edgeTypes) {
|
|
|
|
|
entityAlias.filter.edgeTypes = [];
|
|
|
|
|
}
|
|
|
|
|
entityAlias.filter.edgeTypes.push(entityAlias.filter.edgeType);
|
|
|
|
|
delete entityAlias.filter.edgeType;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-19 20:10:52 +03:00
|
|
|
return entityAlias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private validateAliasId(aliasId: string,
|
|
|
|
|
datasourcesByAliasId: {[aliasId: string]: Array<Datasource>},
|
2024-01-23 20:03:14 +02:00
|
|
|
targetDevicesByAliasId: {[aliasId: string]: Array<TargetDevice>}): string {
|
2019-09-19 20:10:52 +03:00
|
|
|
if (!aliasId || !isString(aliasId) || aliasId.length !== 36) {
|
|
|
|
|
const newAliasId = this.utils.guid();
|
|
|
|
|
const aliasDatasources = datasourcesByAliasId[aliasId];
|
|
|
|
|
if (aliasDatasources) {
|
|
|
|
|
aliasDatasources.forEach(
|
|
|
|
|
(datasource) => {
|
|
|
|
|
datasource.entityAliasId = newAliasId;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-01-23 20:03:14 +02:00
|
|
|
const targetDevicesList = targetDevicesByAliasId[aliasId];
|
|
|
|
|
if (targetDevicesList) {
|
|
|
|
|
targetDevicesList.forEach(
|
|
|
|
|
(targetDevice) => {
|
|
|
|
|
targetDevice.entityAliasId = newAliasId;
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return newAliasId;
|
|
|
|
|
} else {
|
|
|
|
|
return aliasId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-08 12:15:56 +03:00
|
|
|
replaceReferenceWithWidgetCopy(widget: Widget,
|
|
|
|
|
dashboard: Dashboard,
|
|
|
|
|
targetState: string,
|
|
|
|
|
targetLayout: DashboardLayoutId,
|
|
|
|
|
breakpointId: string,
|
|
|
|
|
isRemoveWidget: boolean): Widget {
|
|
|
|
|
|
|
|
|
|
const newWidget = deepClone(widget);
|
|
|
|
|
newWidget.id = this.utils.guid();
|
|
|
|
|
|
|
|
|
|
const originalColumns = this.getOriginalColumns(dashboard, targetState, targetLayout, breakpointId);
|
|
|
|
|
const originalSize = this.getOriginalSize(dashboard, targetState, targetLayout, widget, breakpointId);
|
|
|
|
|
|
|
|
|
|
const layout = this.getDashboardLayoutConfig(dashboard.configuration.states[targetState].layouts[targetLayout], breakpointId);
|
|
|
|
|
const widgetLayout = layout.widgets[widget.id];
|
|
|
|
|
const targetRow = widgetLayout.row;
|
|
|
|
|
const targetColumn = widgetLayout.col;
|
|
|
|
|
|
|
|
|
|
if (isRemoveWidget) {
|
|
|
|
|
this.removeWidgetFromLayout(dashboard, targetState, targetLayout, widget.id, breakpointId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.addWidgetToLayout(dashboard, targetState, targetLayout, newWidget, originalColumns, originalSize,
|
|
|
|
|
targetRow, targetColumn, breakpointId);
|
|
|
|
|
|
|
|
|
|
return newWidget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getDashboardLayoutConfig(layout: DashboardLayout, breakpointId: string): DashboardLayout {
|
|
|
|
|
if (breakpointId !== 'default') {
|
|
|
|
|
return layout.breakpoints[breakpointId];
|
|
|
|
|
}
|
|
|
|
|
return layout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getOriginalColumns(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId, breakpointId: string): number {
|
|
|
|
|
let originalColumns = 24;
|
|
|
|
|
let gridSettings = null;
|
|
|
|
|
const state = dashboard.configuration.states[sourceState];
|
|
|
|
|
const layoutCount = Object.keys(state.layouts).length;
|
|
|
|
|
if (state) {
|
|
|
|
|
const layout = this.getDashboardLayoutConfig(state.layouts[sourceLayout], breakpointId);
|
|
|
|
|
if (layout) {
|
|
|
|
|
gridSettings = layout.gridSettings;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (gridSettings && gridSettings.columns) {
|
|
|
|
|
originalColumns = gridSettings.columns;
|
|
|
|
|
}
|
|
|
|
|
originalColumns = originalColumns * layoutCount;
|
|
|
|
|
return originalColumns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getOriginalSize(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId,
|
|
|
|
|
widget: Widget, breakpointId: string): WidgetSize {
|
|
|
|
|
const layout = this.getDashboardLayoutConfig(dashboard.configuration.states[sourceState].layouts[sourceLayout], breakpointId);
|
|
|
|
|
const widgetLayout = layout.widgets[widget.id];
|
|
|
|
|
return {
|
|
|
|
|
sizeX: widgetLayout.sizeX,
|
|
|
|
|
sizeY: widgetLayout.sizeY
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-19 20:10:52 +03:00
|
|
|
}
|