From 1a3dc833666c380100482330b055a083086e39ac Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Tue, 5 May 2026 16:42:48 +0300 Subject: [PATCH 1/2] Map widget: fix data aggregation for additional data keys and import/export widget JSON for polylines layer --- .../widget/maps/map-model.definition.ts | 119 ++++++------------ .../shared/models/widget/maps/map.models.ts | 2 + 2 files changed, 42 insertions(+), 79 deletions(-) diff --git a/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts b/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts index 38cc0b52f4..681722c0c3 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts @@ -27,8 +27,10 @@ import { import { additionalMapDataSourcesToDatasources, BaseMapSettings, + latestMapDataLayerTypes, MapDataLayerSettings, MapDataLayerType, + mapDataLayerTypes, MapDataSourceSettings, mapDataSourceSettingsToDatasource, MapType @@ -46,30 +48,21 @@ interface MapDataLayerDsInfo extends AliasFilterPair { type ExportDataSourceInfo = {[dataLayerIndex: number]: MapDataLayerDsInfo}; -interface MapDatasourcesInfo { - trips?: ExportDataSourceInfo; - markers?: ExportDataSourceInfo; - polygons?: ExportDataSourceInfo; - circles?: ExportDataSourceInfo; +type MapDatasourcesInfo = { + [K in MapDataLayerType]?: ExportDataSourceInfo; +} & { additionalDataSources?: ExportDataSourceInfo; -} +}; export const MapModelDefinition: WidgetModelDefinition = { testWidget(widget: Widget): boolean { if (widget?.config?.settings) { const settings = widget.config.settings; if (settings.mapType && [MapType.image, MapType.geoMap].includes(settings.mapType)) { - if (settings.trips && Array.isArray(settings.trips)) { - return true; - } - if (settings.markers && Array.isArray(settings.markers)) { - return true; - } - if (settings.polygons && Array.isArray(settings.polygons)) { - return true; - } - if (settings.circles && Array.isArray(settings.circles)) { - return true; + for (const layerType of mapDataLayerTypes) { + if (Array.isArray(settings[layerType])) { + return true; + } } } } @@ -78,17 +71,11 @@ export const MapModelDefinition: WidgetModelDefinition = { prepareExportInfo(dashboard: Dashboard, widget: Widget): MapDatasourcesInfo { const settings: BaseMapSettings = widget.config.settings as BaseMapSettings; const info: MapDatasourcesInfo = {}; - if (settings.trips?.length) { - info.trips = prepareExportDataSourcesInfo(dashboard, settings.trips); - } - if (settings.markers?.length) { - info.markers = prepareExportDataSourcesInfo(dashboard, settings.markers); - } - if (settings.polygons?.length) { - info.polygons = prepareExportDataSourcesInfo(dashboard, settings.polygons); - } - if (settings.circles?.length) { - info.circles = prepareExportDataSourcesInfo(dashboard, settings.circles); + for (const layerType of mapDataLayerTypes) { + const dataLayerSettings = settings[layerType]; + if (dataLayerSettings?.length) { + info[layerType] = prepareExportDataSourcesInfo(dashboard, dataLayerSettings); + } } if (settings.additionalDataSources?.length) { info.additionalDataSources = prepareExportDataSourcesInfo(dashboard, settings.additionalDataSources); @@ -96,59 +83,36 @@ export const MapModelDefinition: WidgetModelDefinition = { return info; }, updateFromExportInfo(widget: Widget, entityAliases: EntityAliases, filters: Filters, info: MapDatasourcesInfo): void { - const settings: BaseMapSettings = widget.config.settings as BaseMapSettings; - if (info?.trips) { - updateMapDatasourceFromExportInfo(entityAliases, filters, settings.trips, info.trips); - } - if (info?.markers) { - updateMapDatasourceFromExportInfo(entityAliases, filters, settings.markers, info.markers); - } - if (info?.polygons) { - updateMapDatasourceFromExportInfo(entityAliases, filters, settings.polygons, info.polygons); - } - if (info?.circles) { - updateMapDatasourceFromExportInfo(entityAliases, filters, settings.circles, info.circles); - } - if (info?.additionalDataSources) { - updateMapDatasourceFromExportInfo(entityAliases, filters, settings.additionalDataSources, info.additionalDataSources); + if (info && Object.keys(info).length) { + const settings: BaseMapSettings = widget.config.settings as BaseMapSettings; + for (const layerType of mapDataLayerTypes) { + const layerInfo = info[layerType]; + const dataLayerSettings = settings[layerType]; + if (layerInfo && dataLayerSettings) { + updateMapDatasourceFromExportInfo(entityAliases, filters, dataLayerSettings, layerInfo); + } + } + if (info.additionalDataSources) { + updateMapDatasourceFromExportInfo(entityAliases, filters, settings.additionalDataSources, info.additionalDataSources); + } } }, datasources(widget: Widget): Datasource[] { - const settings: BaseMapSettings = widget.config.settings as BaseMapSettings; - const datasources: Datasource[] = []; - if (settings.trips?.length) { - datasources.push(...getMapDataLayersDatasources(settings.trips)); - } - if (settings.markers?.length) { - datasources.push(...getMapDataLayersDatasources(settings.markers)); - } - if (settings.polygons?.length) { - datasources.push(...getMapDataLayersDatasources(settings.polygons)); - } - if (settings.circles?.length) { - datasources.push(...getMapDataLayersDatasources(settings.circles)); - } - if (settings.additionalDataSources?.length) { - datasources.push(...additionalMapDataSourcesToDatasources(settings.additionalDataSources)); - } - return datasources; + return getMapDataLayersDatasources(widget.config.settings as BaseMapSettings, mapDataLayerTypes); }, hasTimewindow(widget: Widget): boolean { const settings: BaseMapSettings = widget.config.settings as BaseMapSettings; - if (settings.trips?.length) { + const timeSeriesDataLayerTypes = mapDataLayerTypes.filter(t => !latestMapDataLayerTypes.includes(t)); + if (timeSeriesDataLayerTypes.some(layerType => settings[layerType]?.length)) { return true; - } else { - const datasources: Datasource[] = getMapLatestDataLayersDatasources(settings); - return datasourcesHasAggregation(datasources); } + return datasourcesHasAggregation(getMapDataLayersDatasources(settings, latestMapDataLayerTypes, true)); }, datasourcesHasAggregation(widget: Widget): boolean { - const datasources: Datasource[] = getMapLatestDataLayersDatasources(widget.config.settings as BaseMapSettings); - return datasourcesHasAggregation(datasources); + return datasourcesHasAggregation(getMapDataLayersDatasources(widget.config.settings as BaseMapSettings, latestMapDataLayerTypes, true)); }, datasourcesHasOnlyComparisonAggregation(widget: Widget): boolean { - const datasources: Datasource[] = getMapLatestDataLayersDatasources(widget.config.settings as BaseMapSettings); - return datasourcesHasOnlyComparisonAggregation(datasources); + return datasourcesHasOnlyComparisonAggregation(getMapDataLayersDatasources(widget.config.settings as BaseMapSettings, latestMapDataLayerTypes, true)); } }; @@ -236,7 +200,7 @@ const prepareAliasAndFilterPair = (dashboard: Dashboard, settings: MapDataSource } } -const getMapDataLayersDatasources = (settings: MapDataLayerSettings[], +const getMapDataLayerDatasources = (settings: MapDataLayerSettings[], includeDataKeys = false, dataLayerType?: MapDataLayerType): Datasource[] => { const datasources: Datasource[] = []; settings.forEach((dsSettings) => { @@ -255,16 +219,13 @@ const getMapDataLayersDatasources = (settings: MapDataLayerSettings[], return datasources; }; -const getMapLatestDataLayersDatasources = (settings: BaseMapSettings): Datasource[] => { +const getMapDataLayersDatasources = (settings: BaseMapSettings, layerTypes: MapDataLayerType[], includeDataKeys = false): Datasource[] => { const datasources: Datasource[] = []; - if (settings.markers?.length) { - datasources.push(...getMapDataLayersDatasources(settings.markers, true, 'markers')); - } - if (settings.polygons?.length) { - datasources.push(...getMapDataLayersDatasources(settings.polygons, true, 'polygons')); - } - if (settings.circles?.length) { - datasources.push(...getMapDataLayersDatasources(settings.circles, true, 'circles')); + for (const layerType of layerTypes) { + const dataLayerSettings = settings[layerType]; + if (dataLayerSettings?.length) { + datasources.push(...getMapDataLayerDatasources(dataLayerSettings, includeDataKeys, layerType)); + } } if (settings.additionalDataSources?.length) { datasources.push(...additionalMapDataSourcesToDatasources(settings.additionalDataSources)); diff --git a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts index 0f1c979425..c846bd0522 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts @@ -204,6 +204,8 @@ export type MapDataLayerType = 'trips' | 'markers' | 'polygons' | 'circles' | 'p export const mapDataLayerTypes: MapDataLayerType[] = ['trips', 'markers', 'polygons', 'circles', 'polylines']; +export const latestMapDataLayerTypes: MapDataLayerType[] = ['markers', 'polygons', 'circles', 'polylines']; + export const mapDataLayerValid = (dataLayer: MapDataLayerSettings, type: MapDataLayerType): boolean => { if (!dataLayer.dsType || ![DatasourceType.function, DatasourceType.device, DatasourceType.entity].includes(dataLayer.dsType)) { return false; From 0c2ab1276b67274d409aea9d854f68515d433746 Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Tue, 5 May 2026 17:12:26 +0300 Subject: [PATCH 2/2] Map widget: derive mapDataLayerTypes from list of supported map data layers --- .../src/app/shared/models/widget/maps/map-model.definition.ts | 3 ++- ui-ngx/src/app/shared/models/widget/maps/map.models.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts b/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts index 681722c0c3..94eced7fcf 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/map-model.definition.ts @@ -219,7 +219,8 @@ const getMapDataLayerDatasources = (settings: MapDataLayerSettings[], return datasources; }; -const getMapDataLayersDatasources = (settings: BaseMapSettings, layerTypes: MapDataLayerType[], includeDataKeys = false): Datasource[] => { +const getMapDataLayersDatasources = (settings: BaseMapSettings, + layerTypes: readonly MapDataLayerType[], includeDataKeys = false): Datasource[] => { const datasources: Datasource[] = []; for (const layerType of layerTypes) { const dataLayerSettings = settings[layerType]; diff --git a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts index c846bd0522..edfe03cc05 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts @@ -200,9 +200,9 @@ export const defaultBaseDataLayerSettings = (mapType: MapType): Partial