- @if (resourcesFormArray.length) {
- @for (resourceControl of resourcesControls; track resourceControl; let i = $index) {
-
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.scss
index d2385459e0..c2db82139d 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.scss
@@ -14,15 +14,115 @@
* limitations under the License.
*/
- :host {
- &.tb-html-container-settings {
+.tb-html-container-settings {
+ height: 100%;
+}
+
+.tb-html-container-settings .tb-html-container-settings-panel, .tb-html-container-settings-panel {
+ position: relative;
+ background: #fff;
+ .mat-mdc-tab-body-wrapper {
+ position: relative;
+ top: 0;
+ flex: 1;
+ }
+ .tb-action-expand-button {
+ position: absolute;
+ top: 4px;
+ right: 0;
+ z-index: 2;
+ }
+ .gutter {
+ display: none;
+ background-color: #eee;
+ background-repeat: no-repeat;
+ background-position: 50%;
+ &.gutter-horizontal {
+ cursor: col-resize;
+ background-image: url("../../../../../../../../../assets/split.js/grips/vertical.png");
+ }
+ }
+ .tb-js-func {
+ &:not(.tb-fullscreen) {
+ &.tb-hide-brackets {
+ padding-bottom: 0;
+ }
+ }
+ }
+ .tb-html {
+ position: relative;
+ &:not(.tb-fullscreen) {
+ padding-bottom: 0;
+ }
+ .tb-html-toolbar {
+ position: absolute;
+ top: 0;
+ right: 8px;
+ z-index: 8;
+ .tb-title {
+ display: none;
+ }
+ }
+ .tb-html-content-panel {
+ border-top: none;
+ height: 100%;
+ }
+ }
+ .tb-css {
+ position: relative;
+ &:not(.tb-fullscreen) {
+ .tb-css-content-panel {
+ margin: 0;
+ }
+ }
+ .tb-css-toolbar {
+ position: absolute;
+ top: 0;
+ right: 8px;
+ z-index: 8;
+ .tb-title {
+ display: none;
+ }
+ }
+ .tb-css-content-panel {
+ border-top: none;
height: 100%;
- ::ng-deep {
- .mat-mdc-tab-body-wrapper {
- position: relative;
- top: 0;
- flex: 1;
+ }
+ }
+ &.tb-fullscreen {
+ padding: 8px;
+ gap: 8px;
+ .tb-action-expand-button {
+ position: relative;
+ top: 0;
+ right: 0;
+ }
+ .gutter {
+ display: block;
+ }
+ .tb-content {
+ border: 1px solid #c0c0c0;
+ .tb-html {
+ .tb-html-content-panel {
+ border: none;
+ }
+ }
+ .tb-css {
+ .tb-css-content-panel {
+ border: none;
+ }
+ }
+ .tb-js-func {
+ padding-top: 8px;
+ .tb-js-func-toolbar {
+ padding: 0 5px;
+ }
+ .tb-js-func-panel {
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
}
}
}
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.ts
index 116d69d468..121362ef57 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/html/html-container-settings.component.ts
@@ -14,7 +14,18 @@
/// limitations under the License.
///
-import { Component, DestroyRef, forwardRef, HostBinding, Input, OnInit } from '@angular/core';
+import {
+ AfterViewInit,
+ Component,
+ DestroyRef,
+ ElementRef,
+ forwardRef,
+ HostBinding,
+ Input,
+ OnInit,
+ ViewChild,
+ ViewEncapsulation
+} from '@angular/core';
import { WidgetResource } from '@shared/models/widget.models';
import {
ControlValueAccessor,
@@ -28,7 +39,8 @@ import {
Validators
} from '@angular/forms';
import {
- ContainerFunctionEditorCompleter,
+ AngularContainerFunctionEditorCompleter,
+ HTMLContainerFunctionEditorCompleter,
HtmlContainerWidgetSettings,
HtmlContainerWidgetType
} from '@home/components/widget/lib/html/html-container-widget.models';
@@ -52,23 +64,39 @@ import { WidgetService } from '@core/http/widget.service';
multi: true,
}
],
+ encapsulation: ViewEncapsulation.None,
standalone: false
})
-export class HtmlContainerSettingsComponent implements OnInit, ControlValueAccessor, Validator {
+export class HtmlContainerSettingsComponent implements OnInit, AfterViewInit, ControlValueAccessor, Validator {
HtmlContainerWidgetType = HtmlContainerWidgetType;
functionScopeVariables = this.widgetService.getWidgetScopeVariables();
- containerFunctionEditorCompleter = ContainerFunctionEditorCompleter;
+ get containerFunctionEditorCompleter() {
+ return this.htmlContainerSettingsForm.get('type').value === HtmlContainerWidgetType.ANGULAR
+ ? AngularContainerFunctionEditorCompleter
+ : HTMLContainerFunctionEditorCompleter;
+ }
@HostBinding('class')
hostClass = 'tb-html-container-settings';
+ @ViewChild('leftPanel', { read: ElementRef })
+ leftPanelElmRef!: ElementRef;
+
+ @ViewChild('rightPanel', { read: ElementRef })
+ rightPanelElmRef!: ElementRef;
+
@Input()
disabled: boolean;
+ fullscreen = false;
+
+ tabsAnimationDuration = '500ms';
+
htmlContainerSettingsForm: UntypedFormGroup;
+
private modelValue: HtmlContainerWidgetSettings;
constructor(private fb: UntypedFormBuilder,
@@ -102,11 +130,26 @@ export class HtmlContainerSettingsComponent implements OnInit, ControlValueAcces
});
}
+ ngAfterViewInit(): void {
+ if (this.leftPanelElmRef && this.rightPanelElmRef) {
+ this.initSplitLayout(this.leftPanelElmRef.nativeElement,
+ this.rightPanelElmRef.nativeElement);
+ }
+ }
+
+ private initSplitLayout(leftPanel: any, rightPanel: any) {
+ Split([leftPanel, rightPanel], {
+ sizes: [50, 50],
+ gutterSize: 8,
+ cursor: 'col-resize'
+ });
+ }
+
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
- registerOnTouched(fn: any): void {
+ registerOnTouched(_fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
@@ -150,7 +193,15 @@ export class HtmlContainerSettingsComponent implements OnInit, ControlValueAcces
this.resourcesFormArray.removeAt(index);
}
- private propagateChange = (v: any) => { };
+ toggleFullScreen(): void {
+ this.fullscreen = !this.fullscreen;
+ this.tabsAnimationDuration = '0ms';
+ setTimeout(() => {
+ this.tabsAnimationDuration = '500ms';
+ });
+ }
+
+ private propagateChange = (_v: any) => { };
private updateModel() {
this.modelValue = this.htmlContainerSettingsForm.value;
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..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
@@ -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,14 @@ const getMapDataLayersDatasources = (settings: MapDataLayerSettings[],
return datasources;
};
-const getMapLatestDataLayersDatasources = (settings: BaseMapSettings): Datasource[] => {
+const getMapDataLayersDatasources = (settings: BaseMapSettings,
+ layerTypes: readonly 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 69f6fd02f1..1d82139050 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,11 @@ export const defaultBaseDataLayerSettings = (mapType: MapType): Partial {
if (!dataLayer.dsType || ![DatasourceType.function, DatasourceType.device, DatasourceType.entity].includes(dataLayer.dsType)) {