UI: Prevent deleting an entity alias/filter that’s still used in map widgets
This commit is contained in:
parent
18b6a9557d
commit
429f9c7cc9
@ -31,7 +31,8 @@ import {
|
||||
DashboardLayoutsInfo,
|
||||
DashboardState,
|
||||
DashboardStateLayouts,
|
||||
GridSettings, LayoutType,
|
||||
GridSettings,
|
||||
LayoutType,
|
||||
WidgetLayout
|
||||
} from '@shared/models/dashboard.models';
|
||||
import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined } from '@core/utils';
|
||||
@ -61,6 +62,7 @@ import { MediaBreakpoints } from '@shared/models/constants';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DashboardPageLayout } from '@home/components/dashboard-page/dashboard-page.models';
|
||||
import { maxGridsterCol, maxGridsterRow } from '@home/models/dashboard-component.models';
|
||||
import { findWidgetModelDefinition } from '@shared/models/widget/widget-model.definition';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -398,6 +400,14 @@ export class DashboardUtilsService {
|
||||
return datasources;
|
||||
}
|
||||
|
||||
public getWidgetDatasources(widget: Widget): Datasource[] {
|
||||
const widgetDefinition = findWidgetModelDefinition(widget);
|
||||
if (widgetDefinition) {
|
||||
return widgetDefinition.datasources(widget);
|
||||
}
|
||||
return this.validateAndUpdateDatasources(widget.config.datasources);
|
||||
}
|
||||
|
||||
public createDefaultLayoutData(): DashboardLayout {
|
||||
return {
|
||||
widgets: {},
|
||||
|
||||
@ -35,7 +35,7 @@ import { FcRuleNode, ruleNodeTypeDescriptors } from '@shared/models/rule-node.mo
|
||||
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||
import { RuleChainImport } from '@shared/models/rule-chain.models';
|
||||
import { Filter, FilterInfo, Filters, FiltersInfo, getFilterId } from '@shared/models/query/query.models';
|
||||
import { getWidgetExportDefinition } from '@shared/models/widget/widget-export.models';
|
||||
import { findWidgetModelDefinition } from '@shared/models/widget/widget-model.definition';
|
||||
|
||||
const WIDGET_ITEM = 'widget_item';
|
||||
const WIDGET_REFERENCE = 'widget_reference';
|
||||
@ -142,7 +142,7 @@ export class ItemBufferService {
|
||||
}
|
||||
}
|
||||
let widgetExportInfo: any;
|
||||
const exportDefinition = getWidgetExportDefinition(widget);
|
||||
const exportDefinition = findWidgetModelDefinition(widget);
|
||||
if (exportDefinition) {
|
||||
widgetExportInfo = exportDefinition.prepareExportInfo(dashboard, widget);
|
||||
}
|
||||
@ -270,7 +270,7 @@ export class ItemBufferService {
|
||||
let callFilterUpdateFunction = false;
|
||||
let newEntityAliases: EntityAliases;
|
||||
let newFilters: Filters;
|
||||
const exportDefinition = getWidgetExportDefinition(widget);
|
||||
const exportDefinition = findWidgetModelDefinition(widget);
|
||||
if (exportDefinition && widgetExportInfo || aliasesInfo) {
|
||||
newEntityAliases = deepClone(dashboard.configuration.entityAliases);
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, DestroyRef, Inject, OnInit, SkipSelf } from '@angular/core';
|
||||
import { Component, DestroyRef, Inject, SkipSelf } from '@angular/core';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
@ -60,7 +60,7 @@ export interface EntityAliasesDialogData {
|
||||
styleUrls: ['./entity-aliases-dialog.component.scss']
|
||||
})
|
||||
export class EntityAliasesDialogComponent extends DialogComponent<EntityAliasesDialogComponent, EntityAliases>
|
||||
implements OnInit, ErrorStateMatcher {
|
||||
implements ErrorStateMatcher {
|
||||
|
||||
title: string;
|
||||
disableAdd: boolean;
|
||||
@ -107,8 +107,7 @@ export class EntityAliasesDialogComponent extends DialogComponent<EntityAliasesD
|
||||
this.addWidgetTitleToWidgetsMap(widget.config.alarmSource.entityAliasId, widget.config.title);
|
||||
}
|
||||
} else {
|
||||
const datasources = this.dashboardUtils.validateAndUpdateDatasources(widget.config.datasources);
|
||||
datasources.forEach((datasource) => {
|
||||
this.dashboardUtils.getWidgetDatasources(widget).forEach((datasource) => {
|
||||
if ([DatasourceType.entity, DatasourceType.entityCount, DatasourceType.alarmCount].includes(datasource.type)
|
||||
&& datasource.entityAliasId) {
|
||||
this.addWidgetTitleToWidgetsMap(datasource.entityAliasId, widget.config.title);
|
||||
@ -143,8 +142,10 @@ export class EntityAliasesDialogComponent extends DialogComponent<EntityAliasesD
|
||||
widgetsTitleList = [];
|
||||
this.aliasToWidgetsMap[aliasId] = widgetsTitleList;
|
||||
}
|
||||
if (!widgetsTitleList.includes(widgetTitle)) {
|
||||
widgetsTitleList.push(widgetTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private createEntityAliasFormControl(aliasId: string, entityAlias: EntityAlias): AbstractControl {
|
||||
const aliasFormControl = this.fb.group({
|
||||
@ -166,9 +167,6 @@ export class EntityAliasesDialogComponent extends DialogComponent<EntityAliasesD
|
||||
return this.entityAliasesFormGroup.get('entityAliases') as UntypedFormArray;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
||||
|
||||
@ -14,19 +14,19 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
|
||||
import { Component, Inject, SkipSelf } from '@angular/core';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormGroupDirective,
|
||||
NgForm,
|
||||
UntypedFormArray,
|
||||
UntypedFormBuilder,
|
||||
UntypedFormControl,
|
||||
UntypedFormGroup,
|
||||
FormGroupDirective,
|
||||
NgForm,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
@ -58,7 +58,7 @@ export interface FiltersDialogData {
|
||||
styleUrls: ['./filters-dialog.component.scss']
|
||||
})
|
||||
export class FiltersDialogComponent extends DialogComponent<FiltersDialogComponent, Filters>
|
||||
implements OnInit, ErrorStateMatcher {
|
||||
implements ErrorStateMatcher {
|
||||
|
||||
title: string;
|
||||
disableAdd: boolean;
|
||||
@ -96,16 +96,17 @@ export class FiltersDialogComponent extends DialogComponent<FiltersDialogCompone
|
||||
}
|
||||
} else {
|
||||
this.data.widgets.forEach((widget) => {
|
||||
const datasources = this.dashboardUtils.validateAndUpdateDatasources(widget.config.datasources);
|
||||
datasources.forEach((datasource) => {
|
||||
if (datasource.type === DatasourceType.entity && datasource.filterId) {
|
||||
this.dashboardUtils.getWidgetDatasources(widget).forEach((datasource) => {
|
||||
if (datasource.type !== DatasourceType.function && datasource.filterId) {
|
||||
widgetsTitleList = this.filterToWidgetsMap[datasource.filterId];
|
||||
if (!widgetsTitleList) {
|
||||
widgetsTitleList = [];
|
||||
this.filterToWidgetsMap[datasource.filterId] = widgetsTitleList;
|
||||
}
|
||||
if (!widgetsTitleList.includes(widget.config.title)) {
|
||||
widgetsTitleList.push(widget.config.title);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -140,9 +141,6 @@ export class FiltersDialogComponent extends DialogComponent<FiltersDialogCompone
|
||||
return this.filtersFormGroup.get('filters') as UntypedFormArray;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
||||
|
||||
@ -17,14 +17,15 @@
|
||||
import { EntityAliases, EntityAliasInfo, getEntityAliasId } from '@shared/models/alias.models';
|
||||
import { FilterInfo, Filters, getFilterId } from '@shared/models/query/query.models';
|
||||
import { Dashboard } from '@shared/models/dashboard.models';
|
||||
import { DatasourceType, Widget } from '@shared/models/widget.models';
|
||||
import { Datasource, DatasourceType, Widget } from '@shared/models/widget.models';
|
||||
import {
|
||||
BaseMapSettings,
|
||||
MapDataLayerSettings,
|
||||
MapDataSourceSettings,
|
||||
mapDataSourceSettingsToDatasource,
|
||||
MapType
|
||||
} from '@shared/models/widget/maps/map.models';
|
||||
import { WidgetExportDefinition } from '@shared/models/widget/widget-export.models';
|
||||
import { WidgetModelDefinition } from '@shared/models/widget/widget-model.definition';
|
||||
|
||||
interface AliasFilterPair {
|
||||
alias?: EntityAliasInfo,
|
||||
@ -45,7 +46,7 @@ interface MapDatasourcesInfo {
|
||||
additionalDataSources?: ExportDataSourceInfo;
|
||||
}
|
||||
|
||||
export const MapExportDefinition: WidgetExportDefinition<MapDatasourcesInfo> = {
|
||||
export const MapModelDefinition: WidgetModelDefinition<MapDatasourcesInfo> = {
|
||||
testWidget(widget: Widget): boolean {
|
||||
if (widget?.config?.settings) {
|
||||
const settings = widget.config.settings;
|
||||
@ -103,6 +104,26 @@ export const MapExportDefinition: WidgetExportDefinition<MapDatasourcesInfo> = {
|
||||
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(...getMapDataLayersDatasources(settings.additionalDataSources));
|
||||
}
|
||||
return datasources;
|
||||
}
|
||||
};
|
||||
|
||||
@ -189,3 +210,16 @@ const prepareAliasAndFilterPair = (dashboard: Dashboard, settings: MapDataSource
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const getMapDataLayersDatasources = (settings: MapDataLayerSettings[] | MapDataSourceSettings[]): Datasource[] => {
|
||||
const datasources: Datasource[] = [];
|
||||
settings.forEach((dsSettings) => {
|
||||
datasources.push(mapDataSourceSettingsToDatasource(dsSettings));
|
||||
if ((dsSettings as MapDataLayerSettings).additionalDataSources?.length) {
|
||||
(dsSettings as MapDataLayerSettings).additionalDataSources.forEach((ds) => {
|
||||
datasources.push(mapDataSourceSettingsToDatasource(ds));
|
||||
});
|
||||
}
|
||||
});
|
||||
return datasources;
|
||||
};
|
||||
@ -14,22 +14,23 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Widget } from '@shared/models/widget.models';
|
||||
import { Datasource, Widget } from '@shared/models/widget.models';
|
||||
import { Dashboard } from '@shared/models/dashboard.models';
|
||||
import { EntityAliases } from '@shared/models/alias.models';
|
||||
import { Filters } from '@shared/models/query/query.models';
|
||||
import { MapExportDefinition } from '@shared/models/widget/maps/map-export.models';
|
||||
import { MapModelDefinition } from '@shared/models/widget/maps/map-model.definition';
|
||||
|
||||
export interface WidgetExportDefinition<T = any> {
|
||||
export interface WidgetModelDefinition<T = any> {
|
||||
testWidget(widget: Widget): boolean;
|
||||
prepareExportInfo(dashboard: Dashboard, widget: Widget): T;
|
||||
updateFromExportInfo(widget: Widget, entityAliases: EntityAliases, filters: Filters, info: T): void;
|
||||
datasources(widget: Widget): Datasource[];
|
||||
}
|
||||
|
||||
const widgetExportDefinitions: WidgetExportDefinition[] = [
|
||||
MapExportDefinition
|
||||
const widgetModelRegistry: WidgetModelDefinition[] = [
|
||||
MapModelDefinition
|
||||
];
|
||||
|
||||
export const getWidgetExportDefinition = (widget: Widget): WidgetExportDefinition => {
|
||||
return widgetExportDefinitions.find(def => def.testWidget(widget));
|
||||
export const findWidgetModelDefinition = (widget: Widget): WidgetModelDefinition => {
|
||||
return widgetModelRegistry.find(def => def.testWidget(widget));
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user