UI: Implement basic config form for Entities table widget.
This commit is contained in:
parent
c71d29c507
commit
d992355a3c
@ -104,7 +104,7 @@
|
|||||||
"settingsDirective": "tb-simple-card-widget-settings",
|
"settingsDirective": "tb-simple-card-widget-settings",
|
||||||
"hasBasicMode": true,
|
"hasBasicMode": true,
|
||||||
"basicModeDirective": "tb-simple-card-basic-config",
|
"basicModeDirective": "tb-simple-card-basic-config",
|
||||||
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#ff5722\",\"color\":\"rgba(255, 255, 255, 0.87)\",\"padding\":\"16px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Simple card\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\"}"
|
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#ff5722\",\"color\":\"rgba(255, 255, 255, 0.87)\",\"padding\":\"16px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Simple card\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -143,7 +143,9 @@
|
|||||||
"dataKeySettingsSchema": "",
|
"dataKeySettingsSchema": "",
|
||||||
"settingsDirective": "tb-entities-table-widget-settings",
|
"settingsDirective": "tb-entities-table-widget-settings",
|
||||||
"dataKeySettingsDirective": "tb-entities-table-key-settings",
|
"dataKeySettingsDirective": "tb-entities-table-key-settings",
|
||||||
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"entitiesTitle\":\"\",\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"reserveSpaceForHiddenAction\":\"true\",\"displayEntityName\":true,\"entityNameColumnTitle\":\"\",\"displayEntityLabel\":false,\"displayEntityType\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"useRowStyleFunction\":false},\"title\":\"Entities table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"useCellContentFunction\":false,\"defaultColumnVisibility\":\"visible\",\"columnSelectionToDisplay\":\"enabled\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}]}"
|
"hasBasicMode": true,
|
||||||
|
"basicModeDirective": "tb-entities-table-basic-config",
|
||||||
|
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"reserveSpaceForHiddenAction\":\"true\",\"displayEntityName\":false,\"displayEntityLabel\":false,\"displayEntityType\":false,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"name\",\"useRowStyleFunction\":false,\"entitiesTitle\":\"Entities\"},\"title\":\"Entities table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Entity name\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return 'Simulated';\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Entity type\",\"color\":\"#607d8b\",\"settings\":{},\"_hash\":0.782057645776538,\"funcBody\":\"return 'Device';\",\"decimals\":null,\"aggregationType\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.904797781901171,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\",\"decimals\":0},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.1961430898042078,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\",\"decimals\":0},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.7678057538205878,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\",\"decimals\":2}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"displayTimewindow\":false,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"list\",\"iconColor\":null}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -816,7 +816,8 @@ export class EntityService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEntityKeysByEntityFilter(filter: EntityFilter, types: DataKeyType[], config?: RequestConfig): Observable<Array<DataKey>> {
|
public getEntityKeysByEntityFilter(filter: EntityFilter, types: DataKeyType[],
|
||||||
|
entityTypes?: EntityType[], config?: RequestConfig): Observable<Array<DataKey>> {
|
||||||
if (!types.length) {
|
if (!types.length) {
|
||||||
return of([]);
|
return of([]);
|
||||||
}
|
}
|
||||||
@ -832,7 +833,7 @@ export class EntityService {
|
|||||||
entitiesKeysByQuery$ = of({
|
entitiesKeysByQuery$ = of({
|
||||||
attribute: [],
|
attribute: [],
|
||||||
timeseries: [],
|
timeseries: [],
|
||||||
entityTypes: [],
|
entityTypes: entityTypes || [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return entitiesKeysByQuery$.pipe(
|
return entitiesKeysByQuery$.pipe(
|
||||||
|
|||||||
@ -366,23 +366,16 @@ export class DashboardUtilsService {
|
|||||||
}
|
}
|
||||||
const dataKeys = newDatasource.dataKeys;
|
const dataKeys = newDatasource.dataKeys;
|
||||||
newDatasource.dataKeys = [];
|
newDatasource.dataKeys = [];
|
||||||
|
if (widgetTypeDescriptor.type === widgetType.alarm) {
|
||||||
dataKeys.forEach(dataKey => {
|
dataKeys.forEach(dataKey => {
|
||||||
newDatasource.dataKeys.push(this.convertDataKeyFromWidgetType(widgetTypeDescriptor, config, dataKey));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return newDatasource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private convertDataKeyFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor, config: WidgetConfig, dataKey: DataKey): DataKey {
|
|
||||||
const newDataKey = deepClone(dataKey);
|
const newDataKey = deepClone(dataKey);
|
||||||
newDataKey.funcBody = null;
|
newDataKey.funcBody = null;
|
||||||
if (widgetTypeDescriptor.type === widgetType.alarm) {
|
|
||||||
newDataKey.type = DataKeyType.alarm;
|
newDataKey.type = DataKeyType.alarm;
|
||||||
} else {
|
newDatasource.dataKeys.push(newDataKey);
|
||||||
newDataKey.type = DataKeyType.timeseries;
|
});
|
||||||
newDataKey.name = newDataKey.label;
|
|
||||||
}
|
}
|
||||||
return newDataKey;
|
}
|
||||||
|
return newDatasource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateAndUpdateState(state: DashboardState) {
|
private validateAndUpdateState(state: DashboardState) {
|
||||||
|
|||||||
@ -51,6 +51,7 @@
|
|||||||
[widget]="widget"
|
[widget]="widget"
|
||||||
[widgetConfigMode]="widgetConfigMode"
|
[widgetConfigMode]="widgetConfigMode"
|
||||||
[hideHeader]="widgetConfigMode === widgetConfigModes.basic"
|
[hideHeader]="widgetConfigMode === widgetConfigModes.basic"
|
||||||
|
isAdd
|
||||||
formControlName="widgetConfig">
|
formControlName="widgetConfig">
|
||||||
</tb-widget-config>
|
</tb-widget-config>
|
||||||
<tb-widget-preview *ngIf="previewMode" class="tb-absolute-fill"
|
<tb-widget-preview *ngIf="previewMode" class="tb-absolute-fill"
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
addKeyTitle="{{ 'widgets.table.add-column' | translate }}"
|
addKeyTitle="{{ 'widgets.table.add-column' | translate }}"
|
||||||
removeKeyTitle="{{ 'widgets.table.remove-column' | translate }}"
|
removeKeyTitle="{{ 'widgets.table.remove-column' | translate }}"
|
||||||
noKeysText="{{ 'widgets.table.no-columns' | translate }}"
|
noKeysText="{{ 'widgets.table.no-columns' | translate }}"
|
||||||
|
hideDataKeyColor
|
||||||
[datasourceType]="datasource?.type"
|
[datasourceType]="datasource?.type"
|
||||||
[deviceId]="datasource?.deviceId"
|
[deviceId]="datasource?.deviceId"
|
||||||
[entityAliasId]="datasource?.entityAliasId"
|
[entityAliasId]="datasource?.entityAliasId"
|
||||||
@ -37,6 +38,29 @@
|
|||||||
</tb-data-keys-panel>
|
</tb-data-keys-panel>
|
||||||
<div class="tb-widget-config-panel">
|
<div class="tb-widget-config-panel">
|
||||||
<div class="tb-widget-config-panel-title" translate>widget-config.appearance</div>
|
<div class="tb-widget-config-panel-title" translate>widget-config.appearance</div>
|
||||||
|
<div class="tb-widget-config-row">
|
||||||
|
<mat-slide-toggle class="mat-slide" formControlName="showTitle">
|
||||||
|
{{ 'widget-config.card-title' | translate }}
|
||||||
|
</mat-slide-toggle>
|
||||||
|
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
|
||||||
|
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="tb-widget-config-row space-between same-padding">
|
||||||
|
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
|
||||||
|
{{ 'widget-config.card-icon' | translate }}
|
||||||
|
</mat-slide-toggle>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
|
||||||
|
<tb-material-icon-select asBoxInput
|
||||||
|
[color]="entitiesTableWidgetConfigForm.get('iconColor').value"
|
||||||
|
formControlName="titleIcon">
|
||||||
|
</tb-material-icon-select>
|
||||||
|
<mat-divider vertical></mat-divider>
|
||||||
|
<tb-color-input asBoxInput
|
||||||
|
formControlName="iconColor">
|
||||||
|
</tb-color-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="tb-widget-config-row space-between same-padding">
|
<div class="tb-widget-config-row space-between same-padding">
|
||||||
<div>{{ 'widget-config.text-color' | translate }}</div>
|
<div>{{ 'widget-config.text-color' | translate }}</div>
|
||||||
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
|
||||||
|
|||||||
@ -26,11 +26,13 @@ import {
|
|||||||
datasourcesHasAggregation,
|
datasourcesHasAggregation,
|
||||||
datasourcesHasOnlyComparisonAggregation
|
datasourcesHasOnlyComparisonAggregation
|
||||||
} from '@shared/models/widget.models';
|
} from '@shared/models/widget.models';
|
||||||
|
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
||||||
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entities-table-basic-config',
|
selector: 'tb-entities-table-basic-config',
|
||||||
templateUrl: './entities-table-basic-config.component.html',
|
templateUrl: './entities-table-basic-config.component.html',
|
||||||
styleUrls: ['../basic-config.scss', '../../widget-config.scss']
|
styleUrls: ['../basic-config.scss']
|
||||||
})
|
})
|
||||||
export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponent {
|
export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponent {
|
||||||
|
|
||||||
@ -56,14 +58,19 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen
|
|||||||
entitiesTableWidgetConfigForm: UntypedFormGroup;
|
entitiesTableWidgetConfigForm: UntypedFormGroup;
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
|
protected widgetConfigComponent: WidgetConfigComponent,
|
||||||
private fb: UntypedFormBuilder) {
|
private fb: UntypedFormBuilder) {
|
||||||
super(store);
|
super(store, widgetConfigComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configForm(): UntypedFormGroup {
|
protected configForm(): UntypedFormGroup {
|
||||||
return this.entitiesTableWidgetConfigForm;
|
return this.entitiesTableWidgetConfigForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setupDefaults(configData: WidgetConfigComponentData) {
|
||||||
|
this.setupDefaultDatasource(configData, [{ name: 'name', type: DataKeyType.entityField }]);
|
||||||
|
}
|
||||||
|
|
||||||
protected onConfigSet(configData: WidgetConfigComponentData) {
|
protected onConfigSet(configData: WidgetConfigComponentData) {
|
||||||
this.entitiesTableWidgetConfigForm = this.fb.group({
|
this.entitiesTableWidgetConfigForm = this.fb.group({
|
||||||
timewindowConfig: [{
|
timewindowConfig: [{
|
||||||
@ -73,6 +80,11 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen
|
|||||||
}, []],
|
}, []],
|
||||||
datasources: [configData.config.datasources, []],
|
datasources: [configData.config.datasources, []],
|
||||||
columns: [this.getColumns(configData.config.datasources), []],
|
columns: [this.getColumns(configData.config.datasources), []],
|
||||||
|
showTitle: [configData.config.showTitle, []],
|
||||||
|
title: [configData.config.settings?.entitiesTitle, []],
|
||||||
|
showTitleIcon: [configData.config.showTitleIcon, []],
|
||||||
|
titleIcon: [configData.config.titleIcon, []],
|
||||||
|
iconColor: [configData.config.iconColor, []],
|
||||||
color: [configData.config.color, []],
|
color: [configData.config.color, []],
|
||||||
backgroundColor: [configData.config.backgroundColor, []],
|
backgroundColor: [configData.config.backgroundColor, []],
|
||||||
actions: [configData.config.actions || {}, []]
|
actions: [configData.config.actions || {}, []]
|
||||||
@ -86,11 +98,46 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen
|
|||||||
this.widgetConfig.config.datasources = config.datasources;
|
this.widgetConfig.config.datasources = config.datasources;
|
||||||
this.setColumns(config.columns, this.widgetConfig.config.datasources);
|
this.setColumns(config.columns, this.widgetConfig.config.datasources);
|
||||||
this.widgetConfig.config.actions = config.actions;
|
this.widgetConfig.config.actions = config.actions;
|
||||||
|
this.widgetConfig.config.showTitle = config.showTitle;
|
||||||
|
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
|
||||||
|
this.widgetConfig.config.settings.entitiesTitle = config.title;
|
||||||
|
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
|
||||||
|
this.widgetConfig.config.titleIcon = config.titleIcon;
|
||||||
|
this.widgetConfig.config.iconColor = config.iconColor;
|
||||||
this.widgetConfig.config.color = config.color;
|
this.widgetConfig.config.color = config.color;
|
||||||
this.widgetConfig.config.backgroundColor = config.backgroundColor;
|
this.widgetConfig.config.backgroundColor = config.backgroundColor;
|
||||||
return this.widgetConfig;
|
return this.widgetConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected validatorTriggers(): string[] {
|
||||||
|
return ['showTitle', 'showTitleIcon'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updateValidators(emitEvent: boolean, trigger?: string) {
|
||||||
|
const showTitle: boolean = this.entitiesTableWidgetConfigForm.get('showTitle').value;
|
||||||
|
const showTitleIcon: boolean = this.entitiesTableWidgetConfigForm.get('showTitleIcon').value;
|
||||||
|
if (showTitle) {
|
||||||
|
this.entitiesTableWidgetConfigForm.get('title').enable();
|
||||||
|
this.entitiesTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
|
||||||
|
if (showTitleIcon) {
|
||||||
|
this.entitiesTableWidgetConfigForm.get('titleIcon').enable();
|
||||||
|
this.entitiesTableWidgetConfigForm.get('iconColor').enable();
|
||||||
|
} else {
|
||||||
|
this.entitiesTableWidgetConfigForm.get('titleIcon').disable();
|
||||||
|
this.entitiesTableWidgetConfigForm.get('iconColor').disable();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.entitiesTableWidgetConfigForm.get('title').disable();
|
||||||
|
this.entitiesTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
|
||||||
|
this.entitiesTableWidgetConfigForm.get('titleIcon').disable();
|
||||||
|
this.entitiesTableWidgetConfigForm.get('iconColor').disable();
|
||||||
|
}
|
||||||
|
this.entitiesTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent});
|
||||||
|
this.entitiesTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false});
|
||||||
|
this.entitiesTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent});
|
||||||
|
this.entitiesTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent});
|
||||||
|
}
|
||||||
|
|
||||||
private getColumns(datasources?: Datasource[]): DataKey[] {
|
private getColumns(datasources?: Datasource[]): DataKey[] {
|
||||||
if (datasources && datasources.length) {
|
if (datasources && datasources.length) {
|
||||||
return datasources[0].dataKeys || [];
|
return datasources[0].dataKeys || [];
|
||||||
|
|||||||
@ -23,13 +23,15 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models'
|
|||||||
import {
|
import {
|
||||||
Datasource,
|
Datasource,
|
||||||
datasourcesHasAggregation,
|
datasourcesHasAggregation,
|
||||||
datasourcesHasOnlyComparisonAggregation
|
datasourcesHasOnlyComparisonAggregation,
|
||||||
} from '@shared/models/widget.models';
|
} from '@shared/models/widget.models';
|
||||||
|
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
||||||
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-simple-card-basic-config',
|
selector: 'tb-simple-card-basic-config',
|
||||||
templateUrl: './simple-card-basic-config.component.html',
|
templateUrl: './simple-card-basic-config.component.html',
|
||||||
styleUrls: ['../basic-config.scss', '../../widget-config.scss']
|
styleUrls: ['../basic-config.scss']
|
||||||
})
|
})
|
||||||
export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
|
export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
|
||||||
|
|
||||||
@ -46,14 +48,19 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
|
|||||||
simpleCardWidgetConfigForm: UntypedFormGroup;
|
simpleCardWidgetConfigForm: UntypedFormGroup;
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
|
protected widgetConfigComponent: WidgetConfigComponent,
|
||||||
private fb: UntypedFormBuilder) {
|
private fb: UntypedFormBuilder) {
|
||||||
super(store);
|
super(store, widgetConfigComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configForm(): UntypedFormGroup {
|
protected configForm(): UntypedFormGroup {
|
||||||
return this.simpleCardWidgetConfigForm;
|
return this.simpleCardWidgetConfigForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setupDefaults(configData: WidgetConfigComponentData) {
|
||||||
|
this.setupDefaultDatasource(configData, [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]);
|
||||||
|
}
|
||||||
|
|
||||||
protected onConfigSet(configData: WidgetConfigComponentData) {
|
protected onConfigSet(configData: WidgetConfigComponentData) {
|
||||||
this.simpleCardWidgetConfigForm = this.fb.group({
|
this.simpleCardWidgetConfigForm = this.fb.group({
|
||||||
timewindowConfig: [{
|
timewindowConfig: [{
|
||||||
|
|||||||
@ -136,6 +136,21 @@
|
|||||||
<mat-form-field fxFlex class="tb-inline-field" appearance="outline" subscriptSizing="dynamic">
|
<mat-form-field fxFlex class="tb-inline-field" appearance="outline" subscriptSizing="dynamic">
|
||||||
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}">
|
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
<div *ngIf="!hideDataKeyColor" class="tb-color-field">
|
||||||
|
<tb-color-input asBoxInput
|
||||||
|
formControlName="color">
|
||||||
|
</tb-color-input>
|
||||||
|
</div>
|
||||||
|
<div class="tb-units-field">
|
||||||
|
<tb-widget-units *ngIf="displayUnitsOrDigits"
|
||||||
|
formControlName="units">
|
||||||
|
</tb-widget-units>
|
||||||
|
</div>
|
||||||
|
<div class="tb-decimals-field">
|
||||||
|
<mat-form-field *ngIf="displayUnitsOrDigits" appearance="outline" class="tb-inline-field center number" subscriptSizing="dynamic">
|
||||||
|
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #keyName>
|
<ng-template #keyName>
|
||||||
<ng-container *ngIf="dataKeyHasPostprocessing(); else keyName">
|
<ng-container *ngIf="dataKeyHasPostprocessing(); else keyName">
|
||||||
|
|||||||
@ -42,4 +42,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tb-color-field, .tb-units-field, .tb-decimals-field {
|
||||||
|
width: 60px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
place-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import {
|
|||||||
} from '@angular/forms';
|
} from '@angular/forms';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
||||||
import { DataKey, DatasourceType, JsonSettingsSchema, widgetType } from '@shared/models/widget.models';
|
import { DataKey, DatasourceType, JsonSettingsSchema, Widget, widgetType } from '@shared/models/widget.models';
|
||||||
import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component';
|
import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component';
|
||||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
import { AggregationType } from '@shared/models/time/time.models';
|
import { AggregationType } from '@shared/models/time/time.models';
|
||||||
@ -49,6 +49,13 @@ import { Observable, of } from 'rxjs';
|
|||||||
import { filter, map, mergeMap, publishReplay, refCount, share, tap } from 'rxjs/operators';
|
import { filter, map, mergeMap, publishReplay, refCount, share, tap } from 'rxjs/operators';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { TruncatePipe } from '@shared/pipe/truncate.pipe';
|
import { TruncatePipe } from '@shared/pipe/truncate.pipe';
|
||||||
|
import {
|
||||||
|
DataKeyConfigDialogComponent,
|
||||||
|
DataKeyConfigDialogData
|
||||||
|
} from '@home/components/widget/config/data-key-config-dialog.component';
|
||||||
|
import { deepClone } from '@core/utils';
|
||||||
|
import { Dashboard } from '@shared/models/dashboard.models';
|
||||||
|
import { IAliasController } from '@core/api/widget-api.models';
|
||||||
|
|
||||||
export const dataKeyRowValidator = (control: AbstractControl): ValidationErrors | null => {
|
export const dataKeyRowValidator = (control: AbstractControl): ValidationErrors | null => {
|
||||||
const dataKey: DataKey = control.value;
|
const dataKey: DataKey = control.value;
|
||||||
@ -63,7 +70,7 @@ export const dataKeyRowValidator = (control: AbstractControl): ValidationErrors
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-data-key-row',
|
selector: 'tb-data-key-row',
|
||||||
templateUrl: './data-key-row.component.html',
|
templateUrl: './data-key-row.component.html',
|
||||||
styleUrls: ['./data-key-row.component.scss', '../../data-keys.component.scss', '../../widget-config.scss'],
|
styleUrls: ['./data-key-row.component.scss', '../../data-keys.component.scss'],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@ -122,6 +129,10 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan
|
|||||||
return this.dataKeysPanelComponent.functionTypeKeys;
|
return this.dataKeysPanelComponent.functionTypeKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hideDataKeyColor(): boolean {
|
||||||
|
return this.dataKeysPanelComponent.hideDataKeyColor;
|
||||||
|
}
|
||||||
|
|
||||||
get widgetType(): widgetType {
|
get widgetType(): widgetType {
|
||||||
return this.widgetConfigComponent.widgetType;
|
return this.widgetConfigComponent.widgetType;
|
||||||
}
|
}
|
||||||
@ -130,14 +141,34 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan
|
|||||||
return this.widgetConfigComponent.widgetConfigCallbacks;
|
return this.widgetConfigComponent.widgetConfigCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get widget(): Widget {
|
||||||
|
return this.widgetConfigComponent.widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dashboard(): Dashboard {
|
||||||
|
return this.widgetConfigComponent.dashboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
get aliasController(): IAliasController {
|
||||||
|
return this.widgetConfigComponent.aliasController;
|
||||||
|
}
|
||||||
|
|
||||||
get datakeySettingsSchema(): JsonSettingsSchema {
|
get datakeySettingsSchema(): JsonSettingsSchema {
|
||||||
return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema;
|
return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get dataKeySettingsDirective(): string {
|
||||||
|
return this.widgetConfigComponent.modelValue?.dataKeySettingsDirective;
|
||||||
|
}
|
||||||
|
|
||||||
get isEntityDatasource(): boolean {
|
get isEntityDatasource(): boolean {
|
||||||
return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType);
|
return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get displayUnitsOrDigits() {
|
||||||
|
return this.modelValue.type && ![ DataKeyType.alarm, DataKeyType.entityField, DataKeyType.count ].includes(this.modelValue.type);
|
||||||
|
}
|
||||||
|
|
||||||
private propagateChange = (_val: any) => {};
|
private propagateChange = (_val: any) => {};
|
||||||
|
|
||||||
constructor(private fb: UntypedFormBuilder,
|
constructor(private fb: UntypedFormBuilder,
|
||||||
@ -261,7 +292,37 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan
|
|||||||
}
|
}
|
||||||
|
|
||||||
editKey() {
|
editKey() {
|
||||||
|
this.dialog.open<DataKeyConfigDialogComponent, DataKeyConfigDialogData, DataKey>(DataKeyConfigDialogComponent,
|
||||||
|
{
|
||||||
|
disableClose: true,
|
||||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
|
data: {
|
||||||
|
dataKey: deepClone(this.modelValue),
|
||||||
|
dataKeySettingsSchema: this.datakeySettingsSchema,
|
||||||
|
dataKeySettingsDirective: this.dataKeySettingsDirective,
|
||||||
|
dashboard: this.dashboard,
|
||||||
|
aliasController: this.aliasController,
|
||||||
|
widget: this.widget,
|
||||||
|
widgetType: this.widgetType,
|
||||||
|
deviceId: this.deviceId,
|
||||||
|
entityAliasId: this.entityAliasId,
|
||||||
|
showPostProcessing: this.widgetType !== widgetType.alarm,
|
||||||
|
callbacks: this.callbacks,
|
||||||
|
hideDataKeyLabel: false,
|
||||||
|
hideDataKeyColor: this.hideDataKeyColor,
|
||||||
|
hideDataKeyUnits: !this.displayUnitsOrDigits,
|
||||||
|
hideDataKeyDecimals: !this.displayUnitsOrDigits
|
||||||
|
}
|
||||||
|
}).afterClosed().subscribe((updatedDataKey) => {
|
||||||
|
if (updatedDataKey) {
|
||||||
|
this.modelValue = updatedDataKey;
|
||||||
|
this.keyRowFormGroup.get('label').patchValue(this.modelValue.label, {emitEvent: false});
|
||||||
|
this.keyRowFormGroup.get('color').patchValue(this.modelValue.color, {emitEvent: false});
|
||||||
|
this.keyRowFormGroup.get('units').patchValue(this.modelValue.units, {emitEvent: false});
|
||||||
|
this.keyRowFormGroup.get('decimals').patchValue(this.modelValue.decimals, {emitEvent: false});
|
||||||
|
this.updateModel();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeKey() {
|
removeKey() {
|
||||||
|
|||||||
@ -21,9 +21,10 @@
|
|||||||
<div class="tb-data-keys-header">
|
<div class="tb-data-keys-header">
|
||||||
<div class="tb-data-keys-header-cell" fxFlex translate>datakey.key</div>
|
<div class="tb-data-keys-header-cell" fxFlex translate>datakey.key</div>
|
||||||
<div class="tb-data-keys-header-cell" fxFlex translate>datakey.label</div>
|
<div class="tb-data-keys-header-cell" fxFlex translate>datakey.label</div>
|
||||||
<div class="tb-data-keys-header-cell" translate>datakey.color</div>
|
<div *ngIf="!hideDataKeyColor" class="tb-data-keys-header-cell tb-color-header" translate>datakey.color</div>
|
||||||
<div class="tb-data-keys-header-cell" translate>widget-config.units-short</div>
|
<div class="tb-data-keys-header-cell tb-units-header" translate>widget-config.units-short</div>
|
||||||
<div class="tb-data-keys-header-cell" translate>widget-config.decimals-short</div>
|
<div class="tb-data-keys-header-cell tb-decimals-header" translate>widget-config.decimals-short</div>
|
||||||
|
<div class="tb-data-keys-header-cell tb-actions-header"></div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="keysFormArray().controls.length; else noKeys" class="tb-data-keys-body tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
|
<div *ngIf="keysFormArray().controls.length; else noKeys" class="tb-data-keys-body tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
|
||||||
(cdkDropListDropped)="keyDrop($event)">
|
(cdkDropListDropped)="keyDrop($event)">
|
||||||
|
|||||||
@ -29,13 +29,18 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 12px;
|
|
||||||
.tb-data-keys-header-cell {
|
.tb-data-keys-header-cell {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
letter-spacing: 0.2px;
|
letter-spacing: 0.2px;
|
||||||
color: rgba(0, 0, 0, 0.54);
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
&.tb-color-header, &.tb-units-header, &.tb-decimals-header {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
&.tb-actions-header {
|
||||||
|
width: 76px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tb-data-keys-body {
|
.tb-data-keys-body {
|
||||||
|
|||||||
@ -44,11 +44,12 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
|||||||
import { alarmFields } from '@shared/models/alarm.models';
|
import { alarmFields } from '@shared/models/alarm.models';
|
||||||
import { UtilsService } from '@core/services/utils.service';
|
import { UtilsService } from '@core/services/utils.service';
|
||||||
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models';
|
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models';
|
||||||
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-data-keys-panel',
|
selector: 'tb-data-keys-panel',
|
||||||
templateUrl: './data-keys-panel.component.html',
|
templateUrl: './data-keys-panel.component.html',
|
||||||
styleUrls: ['./data-keys-panel.component.scss', '../../widget-config.scss'],
|
styleUrls: ['./data-keys-panel.component.scss'],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@ -89,6 +90,10 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC
|
|||||||
@Input()
|
@Input()
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
hideDataKeyColor = false;
|
||||||
|
|
||||||
dataKeyType: DataKeyType;
|
dataKeyType: DataKeyType;
|
||||||
alarmKeys: Array<DataKey>;
|
alarmKeys: Array<DataKey>;
|
||||||
functionTypeKeys: Array<DataKey>;
|
functionTypeKeys: Array<DataKey>;
|
||||||
@ -212,13 +217,11 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC
|
|||||||
|
|
||||||
addKey() {
|
addKey() {
|
||||||
const dataKey = this.callbacks.generateDataKey('', null, this.datakeySettingsSchema);
|
const dataKey = this.callbacks.generateDataKey('', null, this.datakeySettingsSchema);
|
||||||
|
dataKey.label = '';
|
||||||
|
dataKey.decimals = 0;
|
||||||
const keysArray = this.keysListFormGroup.get('keys') as UntypedFormArray;
|
const keysArray = this.keysListFormGroup.get('keys') as UntypedFormArray;
|
||||||
const keyControl = this.fb.control(dataKey, [dataKeyRowValidator]);
|
const keyControl = this.fb.control(dataKey, [dataKeyRowValidator]);
|
||||||
keysArray.push(keyControl);
|
keysArray.push(keyControl);
|
||||||
this.keysListFormGroup.updateValueAndValidity();
|
|
||||||
if (!this.keysListFormGroup.valid) {
|
|
||||||
this.propagateChange(this.keysListFormGroup.get('keys').value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private prepareKeysFormArray(keys: DataKey[] | undefined): UntypedFormArray {
|
private prepareKeysFormArray(keys: DataKey[] | undefined): UntypedFormArray {
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-widget-actions-panel',
|
selector: 'tb-widget-actions-panel',
|
||||||
templateUrl: './widget-actions-panel.component.html',
|
templateUrl: './widget-actions-panel.component.html',
|
||||||
styleUrls: ['../../widget-config.scss'],
|
styleUrls: [],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
|||||||
@ -155,6 +155,7 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con
|
|||||||
private dataKeySettingsData: JsonFormComponentData;
|
private dataKeySettingsData: JsonFormComponentData;
|
||||||
|
|
||||||
private alarmKeys: Array<DataKey>;
|
private alarmKeys: Array<DataKey>;
|
||||||
|
private functionTypeKeys: Array<DataKey>;
|
||||||
|
|
||||||
filteredKeys: Observable<Array<string>>;
|
filteredKeys: Observable<Array<string>>;
|
||||||
private latestKeySearchResult: Array<string> = null;
|
private latestKeySearchResult: Array<string> = null;
|
||||||
@ -183,6 +184,13 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con
|
|||||||
type: DataKeyType.alarm
|
type: DataKeyType.alarm
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.functionTypeKeys = [];
|
||||||
|
for (const type of this.utils.getPredefinedFunctionsList()) {
|
||||||
|
this.functionTypeKeys.push({
|
||||||
|
name: type,
|
||||||
|
type: DataKeyType.function
|
||||||
|
});
|
||||||
|
}
|
||||||
if (this.dataKeySettingsSchema && this.dataKeySettingsSchema.schema ||
|
if (this.dataKeySettingsSchema && this.dataKeySettingsSchema.schema ||
|
||||||
this.dataKeySettingsDirective && this.dataKeySettingsDirective.length) {
|
this.dataKeySettingsDirective && this.dataKeySettingsDirective.length) {
|
||||||
this.displayAdvanced = true;
|
this.displayAdvanced = true;
|
||||||
@ -396,6 +404,8 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con
|
|||||||
let fetchObservable: Observable<Array<DataKey>>;
|
let fetchObservable: Observable<Array<DataKey>>;
|
||||||
if (this.modelValue.type === DataKeyType.alarm) {
|
if (this.modelValue.type === DataKeyType.alarm) {
|
||||||
fetchObservable = of(this.alarmKeys);
|
fetchObservable = of(this.alarmKeys);
|
||||||
|
} else if (this.modelValue.type === DataKeyType.function) {
|
||||||
|
fetchObservable = of(this.functionTypeKeys);
|
||||||
} else {
|
} else {
|
||||||
if (this.deviceId || this.entityAliasId) {
|
if (this.deviceId || this.entityAliasId) {
|
||||||
const dataKeyTypes = [this.modelValue.type];
|
const dataKeyTypes = [this.modelValue.type];
|
||||||
|
|||||||
@ -46,7 +46,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-datasources',
|
selector: 'tb-datasources',
|
||||||
templateUrl: './datasources.component.html',
|
templateUrl: './datasources.component.html',
|
||||||
styleUrls: ['./datasources.component.scss', './widget-config.scss'],
|
styleUrls: ['./datasources.component.scss'],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export interface TimewindowConfigData {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-timewindow-config-panel',
|
selector: 'tb-timewindow-config-panel',
|
||||||
templateUrl: './timewindow-config-panel.component.html',
|
templateUrl: './timewindow-config-panel.component.html',
|
||||||
styleUrls: ['./widget-config.scss'],
|
styleUrls: [],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
|||||||
@ -23,12 +23,15 @@ import { PageComponent } from '@shared/components/page.component';
|
|||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
|
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
|
||||||
import { WidgetConfigMode } from '@shared/models/widget.models';
|
import { DataKey, DatasourceType, KeyInfo, WidgetConfigMode } from '@shared/models/widget.models';
|
||||||
|
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
||||||
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
|
|
||||||
export type WidgetConfigCallbacks = DatasourceCallbacks & WidgetActionCallbacks;
|
export type WidgetConfigCallbacks = DatasourceCallbacks & WidgetActionCallbacks;
|
||||||
|
|
||||||
export interface IBasicWidgetConfigComponent {
|
export interface IBasicWidgetConfigComponent {
|
||||||
|
isAdd: boolean;
|
||||||
widgetConfig: WidgetConfigComponentData;
|
widgetConfig: WidgetConfigComponentData;
|
||||||
widgetConfigChanged: Observable<WidgetConfigComponentData>;
|
widgetConfigChanged: Observable<WidgetConfigComponentData>;
|
||||||
validateConfig(): boolean;
|
validateConfig(): boolean;
|
||||||
@ -40,6 +43,8 @@ export interface IBasicWidgetConfigComponent {
|
|||||||
export abstract class BasicWidgetConfigComponent extends PageComponent implements
|
export abstract class BasicWidgetConfigComponent extends PageComponent implements
|
||||||
IBasicWidgetConfigComponent, OnInit, AfterViewInit {
|
IBasicWidgetConfigComponent, OnInit, AfterViewInit {
|
||||||
|
|
||||||
|
isAdd = false;
|
||||||
|
|
||||||
basicMode = WidgetConfigMode.basic;
|
basicMode = WidgetConfigMode.basic;
|
||||||
|
|
||||||
widgetConfigValue: WidgetConfigComponentData;
|
widgetConfigValue: WidgetConfigComponentData;
|
||||||
@ -56,7 +61,8 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement
|
|||||||
widgetConfigChangedEmitter = new EventEmitter<WidgetConfigComponentData>();
|
widgetConfigChangedEmitter = new EventEmitter<WidgetConfigComponentData>();
|
||||||
widgetConfigChanged = this.widgetConfigChangedEmitter.asObservable();
|
widgetConfigChanged = this.widgetConfigChangedEmitter.asObservable();
|
||||||
|
|
||||||
protected constructor(@Inject(Store) protected store: Store<AppState>) {
|
protected constructor(@Inject(Store) protected store: Store<AppState>,
|
||||||
|
protected widgetConfigComponent: WidgetConfigComponent) {
|
||||||
super(store);
|
super(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,12 +71,15 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement
|
|||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.validateConfig()) {
|
if (!this.validateConfig()) {
|
||||||
this.onConfigChanged(this.prepareOutputConfig(this.configForm().value));
|
this.onConfigChanged(this.prepareOutputConfig(this.configForm().getRawValue()));
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setupConfig(widgetConfig: WidgetConfigComponentData) {
|
protected setupConfig(widgetConfig: WidgetConfigComponentData) {
|
||||||
|
if (this.isAdd) {
|
||||||
|
this.setupDefaults(widgetConfig);
|
||||||
|
}
|
||||||
this.onConfigSet(widgetConfig);
|
this.onConfigSet(widgetConfig);
|
||||||
this.updateValidators(false);
|
this.updateValidators(false);
|
||||||
for (const trigger of this.validatorTriggers()) {
|
for (const trigger of this.validatorTriggers()) {
|
||||||
@ -83,11 +92,13 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement
|
|||||||
this.updateValidators(true, trigger);
|
this.updateValidators(true, trigger);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.configForm().valueChanges.subscribe((updated: any) => {
|
this.configForm().valueChanges.subscribe(() => {
|
||||||
this.onConfigChanged(this.prepareOutputConfig(updated));
|
this.onConfigChanged(this.prepareOutputConfig(this.configForm().getRawValue()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setupDefaults(configData: WidgetConfigComponentData) {}
|
||||||
|
|
||||||
protected updateValidators(emitEvent: boolean, trigger?: string) {
|
protected updateValidators(emitEvent: boolean, trigger?: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +119,41 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement
|
|||||||
return this.configForm().valid;
|
return this.configForm().valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setupDefaultDatasource(configData: WidgetConfigComponentData, keys?: DataKey[]) {
|
||||||
|
let datasources = configData.config.datasources;
|
||||||
|
if (!datasources || !datasources.length) {
|
||||||
|
datasources = [
|
||||||
|
{
|
||||||
|
type: DatasourceType.device,
|
||||||
|
dataKeys: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
configData.config.datasources = datasources;
|
||||||
|
}
|
||||||
|
let dataKeys = datasources[0].dataKeys;
|
||||||
|
if (!dataKeys) {
|
||||||
|
dataKeys = [];
|
||||||
|
datasources[0].dataKeys = dataKeys;
|
||||||
|
}
|
||||||
|
if (keys && keys.length) {
|
||||||
|
dataKeys.length = 0;
|
||||||
|
keys.forEach(key => {
|
||||||
|
const dataKey =
|
||||||
|
this.widgetConfigComponent.widgetConfigCallbacks.generateDataKey(key.name, key.type, configData.dataKeySettingsSchema);
|
||||||
|
if (key.label) {
|
||||||
|
dataKey.label = key.label;
|
||||||
|
}
|
||||||
|
if (key.units) {
|
||||||
|
dataKey.units = key.units;
|
||||||
|
}
|
||||||
|
if (isDefinedAndNotNull(key.decimals)) {
|
||||||
|
dataKey.decimals = key.decimals;
|
||||||
|
}
|
||||||
|
dataKeys.push(dataKey);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract configForm(): UntypedFormGroup;
|
protected abstract configForm(): UntypedFormGroup;
|
||||||
|
|
||||||
protected abstract onConfigSet(configData: WidgetConfigComponentData);
|
protected abstract onConfigSet(configData: WidgetConfigComponentData);
|
||||||
|
|||||||
@ -1,175 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright © 2016-2023 The Thingsboard Authors
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
.tb-widget-config-panel {
|
|
||||||
box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 16px;
|
|
||||||
gap: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
color: rgba(0, 0, 0, 0.87);
|
|
||||||
letter-spacing: 0.15px;
|
|
||||||
position: relative;
|
|
||||||
&.no-padding-bottom {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
&.stroked {
|
|
||||||
box-shadow: none;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tb-widget-config-panel-title {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.tb-widget-config-panel-hint {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
.tb-widget-config-row {
|
|
||||||
height: 56px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
padding-left: 16px;
|
|
||||||
padding-right: 12px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
border-radius: 6px;
|
|
||||||
&.same-padding {
|
|
||||||
padding-right: 16px;
|
|
||||||
}
|
|
||||||
&.space-between {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.mat-divider-vertical {
|
|
||||||
height: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tb-widget-config-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field {
|
|
||||||
&.mat-form-field-appearance-fill {
|
|
||||||
.mdc-text-field--filled:not(.mdc-text-field--disabled):before {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.mat-mdc-form-field-focus-overlay {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-mdc-text-field-wrapper {
|
|
||||||
&.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) {
|
|
||||||
padding-right: 12px;
|
|
||||||
padding-left: 12px;
|
|
||||||
&:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) {
|
|
||||||
.mdc-notched-outline__leading, .mdc-notched-outline__trailing {
|
|
||||||
border-color: rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-mdc-form-field-infix {
|
|
||||||
padding-top: 7px;
|
|
||||||
padding-bottom: 7px;
|
|
||||||
min-height: 38px;
|
|
||||||
width: 72px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.center {
|
|
||||||
.mat-mdc-text-field-wrapper {
|
|
||||||
.mat-mdc-form-field-infix {
|
|
||||||
.mdc-text-field__input {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.number {
|
|
||||||
.mat-mdc-text-field-wrapper {
|
|
||||||
padding-right: 4px;
|
|
||||||
.mat-mdc-form-field-infix {
|
|
||||||
width: 80px;
|
|
||||||
input.mdc-text-field__input[type=number]::-webkit-inner-spin-button,
|
|
||||||
input.mdc-text-field__input[type=number]::-webkit-outer-spin-button {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
:host ::ng-deep {
|
|
||||||
|
|
||||||
.mat-slide {
|
|
||||||
margin: 8px 0;
|
|
||||||
.mdc-form-field>label {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slide-block {
|
|
||||||
display: block;
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tb-widget-config-panel {
|
|
||||||
.mat-expansion-panel {
|
|
||||||
&.tb-settings {
|
|
||||||
box-shadow: none;
|
|
||||||
.mat-content {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.mat-expansion-panel-header {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
letter-spacing: 0.25px;
|
|
||||||
padding: 0;
|
|
||||||
.mat-content {
|
|
||||||
flex: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.mat-expansion-indicator {
|
|
||||||
height: 32px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-expansion-panel-header-description {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
> .mat-expansion-panel-content {
|
|
||||||
> .mat-expansion-panel-body {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tb-json-object-panel, .tb-css-content-panel {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-expansion-panel-content {
|
|
||||||
font: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,6 +15,6 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<mat-form-field appearance="outline" class="center" subscriptSizing="dynamic">
|
<mat-form-field appearance="outline" class="tb-inline-field center" subscriptSizing="dynamic">
|
||||||
<input matInput [formControl]="unitsFormControl" placeholder="{{ 'widget-config.set' | translate }}">
|
<input matInput [formControl]="unitsFormControl" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, UntypedFormBuilde
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-widget-units',
|
selector: 'tb-widget-units',
|
||||||
templateUrl: './widget-units.component.html',
|
templateUrl: './widget-units.component.html',
|
||||||
styleUrls: ['./widget-config.scss'],
|
styleUrls: [],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@ -43,6 +43,7 @@ export class WidgetUnitsComponent implements ControlValueAccessor, OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.unitsFormControl = this.fb.control('', []);
|
this.unitsFormControl = this.fb.control('', []);
|
||||||
|
this.unitsFormControl.valueChanges.subscribe(val => this.propagateChange(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
writeValue(units?: string): void {
|
writeValue(units?: string): void {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import { AppState } from '@core/core.state';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-simple-card-widget-settings',
|
selector: 'tb-simple-card-widget-settings',
|
||||||
templateUrl: './simple-card-widget-settings.component.html',
|
templateUrl: './simple-card-widget-settings.component.html',
|
||||||
styleUrls: ['../../../config/widget-config.scss']
|
styleUrls: []
|
||||||
})
|
})
|
||||||
export class SimpleCardWidgetSettingsComponent extends WidgetSettingsComponent {
|
export class SimpleCardWidgetSettingsComponent extends WidgetSettingsComponent {
|
||||||
|
|
||||||
|
|||||||
@ -215,7 +215,7 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr
|
|||||||
mergeMap((aliasInfo) => {
|
mergeMap((aliasInfo) => {
|
||||||
return this.entityService.getEntityKeysByEntityFilter(
|
return this.entityService.getEntityKeysByEntityFilter(
|
||||||
aliasInfo.entityFilter,
|
aliasInfo.entityFilter,
|
||||||
dataKeyTypes,
|
dataKeyTypes, [],
|
||||||
{ignoreLoading: true, ignoreErrors: true}
|
{ignoreLoading: true, ignoreErrors: true}
|
||||||
).pipe(
|
).pipe(
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
|
|||||||
@ -15,7 +15,13 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import { Component, ElementRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
import { Component, ElementRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
import {
|
||||||
|
ControlValueAccessor,
|
||||||
|
NG_VALUE_ACCESSOR,
|
||||||
|
UntypedFormBuilder,
|
||||||
|
UntypedFormGroup,
|
||||||
|
Validators
|
||||||
|
} from '@angular/forms';
|
||||||
import { PageComponent } from '@shared/components/page.component';
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
@ -27,6 +33,7 @@ import { catchError, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/op
|
|||||||
import { DataKey } from '@shared/models/widget.models';
|
import { DataKey } from '@shared/models/widget.models';
|
||||||
import { EntityService } from '@core/http/entity.service';
|
import { EntityService } from '@core/http/entity.service';
|
||||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-device-key-autocomplete',
|
selector: 'tb-device-key-autocomplete',
|
||||||
@ -199,7 +206,7 @@ export class DeviceKeyAutocompleteComponent extends PageComponent implements OnI
|
|||||||
mergeMap((aliasInfo) => {
|
mergeMap((aliasInfo) => {
|
||||||
return this.entityService.getEntityKeysByEntityFilter(
|
return this.entityService.getEntityKeysByEntityFilter(
|
||||||
aliasInfo.entityFilter,
|
aliasInfo.entityFilter,
|
||||||
dataKeyTypes,
|
dataKeyTypes, [EntityType.DEVICE],
|
||||||
{ignoreLoading: true, ignoreErrors: true}
|
{ignoreLoading: true, ignoreErrors: true}
|
||||||
).pipe(
|
).pipe(
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
|
|||||||
@ -236,7 +236,7 @@ export class ImageMapProviderSettingsComponent extends PageComponent implements
|
|||||||
mergeMap((aliasInfo) => {
|
mergeMap((aliasInfo) => {
|
||||||
return this.entityService.getEntityKeysByEntityFilter(
|
return this.entityService.getEntityKeysByEntityFilter(
|
||||||
aliasInfo.entityFilter,
|
aliasInfo.entityFilter,
|
||||||
dataKeyTypes,
|
dataKeyTypes, [],
|
||||||
{ignoreLoading: true, ignoreErrors: true}
|
{ignoreLoading: true, ignoreErrors: true}
|
||||||
).pipe(
|
).pipe(
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
|
|||||||
@ -81,8 +81,8 @@ import { FilterDialogComponent, FilterDialogData } from '@home/components/filter
|
|||||||
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
|
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
|
||||||
import { coerceBoolean } from '@shared/decorators/coercion';
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
|
import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
|
||||||
import Timeout = NodeJS.Timeout;
|
|
||||||
import { TimewindowConfigData } from '@home/components/widget/config/timewindow-config-panel.component';
|
import { TimewindowConfigData } from '@home/components/widget/config/timewindow-config-panel.component';
|
||||||
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
const emptySettingsSchema: JsonSchema = {
|
const emptySettingsSchema: JsonSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -96,7 +96,7 @@ const defaultSettingsForm = [
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-widget-config',
|
selector: 'tb-widget-config',
|
||||||
templateUrl: './widget-config.component.html',
|
templateUrl: './widget-config.component.html',
|
||||||
styleUrls: ['./widget-config.component.scss', './config/widget-config.scss'],
|
styleUrls: ['./widget-config.component.scss'],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@ -143,6 +143,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
|||||||
@coerceBoolean()
|
@coerceBoolean()
|
||||||
hideToggleHeader = false;
|
hideToggleHeader = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
isAdd = false;
|
||||||
|
|
||||||
@Input() disabled: boolean;
|
@Input() disabled: boolean;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@ -399,22 +403,22 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
|||||||
writeValue(value: WidgetConfigComponentData): void {
|
writeValue(value: WidgetConfigComponentData): void {
|
||||||
this.modelValue = value;
|
this.modelValue = value;
|
||||||
this.widgetType = this.modelValue?.widgetType;
|
this.widgetType = this.modelValue?.widgetType;
|
||||||
this.setupConfig();
|
this.setupConfig(this.isAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupConfig() {
|
private setupConfig(isAdd = false) {
|
||||||
if (this.modelValue) {
|
if (this.modelValue) {
|
||||||
this.destroyBasicModeComponent();
|
this.destroyBasicModeComponent();
|
||||||
this.removeChangeSubscriptions();
|
this.removeChangeSubscriptions();
|
||||||
if (this.hasBasicModeDirective && this.widgetConfigMode === WidgetConfigMode.basic) {
|
if (this.hasBasicModeDirective && this.widgetConfigMode === WidgetConfigMode.basic) {
|
||||||
this.setupBasicModeConfig();
|
this.setupBasicModeConfig(isAdd);
|
||||||
} else {
|
} else {
|
||||||
this.setupDefaultConfig();
|
this.setupDefaultConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupBasicModeConfig() {
|
private setupBasicModeConfig(isAdd = false) {
|
||||||
const componentType = basicWidgetConfigComponentsMap[this.modelValue.basicModeDirective];
|
const componentType = basicWidgetConfigComponentsMap[this.modelValue.basicModeDirective];
|
||||||
if (!componentType) {
|
if (!componentType) {
|
||||||
this.basicModeDirectiveError = this.translate.instant('widget-config.settings-component-not-found',
|
this.basicModeDirectiveError = this.translate.instant('widget-config.settings-component-not-found',
|
||||||
@ -425,6 +429,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
|||||||
this.createBasicModeComponentTimeout = null;
|
this.createBasicModeComponentTimeout = null;
|
||||||
this.basicModeComponentRef = this.basicModeContainer.createComponent(factory);
|
this.basicModeComponentRef = this.basicModeContainer.createComponent(factory);
|
||||||
this.basicModeComponent = this.basicModeComponentRef.instance;
|
this.basicModeComponent = this.basicModeComponentRef.instance;
|
||||||
|
this.basicModeComponent.isAdd = isAdd;
|
||||||
this.basicModeComponent.widgetConfig = this.modelValue;
|
this.basicModeComponent.widgetConfig = this.modelValue;
|
||||||
this.basicModeComponentChangeSubscription = this.basicModeComponent.widgetConfigChanged.subscribe((data) => {
|
this.basicModeComponentChangeSubscription = this.basicModeComponent.widgetConfigChanged.subscribe((data) => {
|
||||||
this.modelValue = data;
|
this.modelValue = data;
|
||||||
@ -826,7 +831,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
|||||||
const entityFilter = singleEntityFilterFromDeviceId(deviceId);
|
const entityFilter = singleEntityFilterFromDeviceId(deviceId);
|
||||||
return this.entityService.getEntityKeysByEntityFilter(
|
return this.entityService.getEntityKeysByEntityFilter(
|
||||||
entityFilter,
|
entityFilter,
|
||||||
dataKeyTypes,
|
dataKeyTypes, [EntityType.DEVICE],
|
||||||
{ignoreLoading: true, ignoreErrors: true}
|
{ignoreLoading: true, ignoreErrors: true}
|
||||||
).pipe(
|
).pipe(
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
@ -837,7 +842,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
|
|||||||
return this.aliasController.getAliasInfo(entityAliasId).pipe(
|
return this.aliasController.getAliasInfo(entityAliasId).pipe(
|
||||||
mergeMap((aliasInfo) => this.entityService.getEntityKeysByEntityFilter(
|
mergeMap((aliasInfo) => this.entityService.getEntityKeysByEntityFilter(
|
||||||
aliasInfo.entityFilter,
|
aliasInfo.entityFilter,
|
||||||
dataKeyTypes,
|
dataKeyTypes, [],
|
||||||
{ignoreLoading: true, ignoreErrors: true}
|
{ignoreLoading: true, ignoreErrors: true}
|
||||||
).pipe(
|
).pipe(
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
|
|||||||
@ -4125,6 +4125,7 @@
|
|||||||
"title-tooltip": "Title Tooltip",
|
"title-tooltip": "Title Tooltip",
|
||||||
"general-settings": "General settings",
|
"general-settings": "General settings",
|
||||||
"display-title": "Display widget title",
|
"display-title": "Display widget title",
|
||||||
|
"card-title": "Card title",
|
||||||
"drop-shadow": "Drop shadow",
|
"drop-shadow": "Drop shadow",
|
||||||
"enable-fullscreen": "Enable fullscreen",
|
"enable-fullscreen": "Enable fullscreen",
|
||||||
"background-color": "Background color",
|
"background-color": "Background color",
|
||||||
@ -4179,6 +4180,7 @@
|
|||||||
"delete-action-text": "Are you sure you want delete widget action with name '{{actionName}}'?",
|
"delete-action-text": "Are you sure you want delete widget action with name '{{actionName}}'?",
|
||||||
"title-icon": "Title icon",
|
"title-icon": "Title icon",
|
||||||
"display-icon": "Display title icon",
|
"display-icon": "Display title icon",
|
||||||
|
"card-icon": "Card icon",
|
||||||
"icon-color": "Icon color",
|
"icon-color": "Icon color",
|
||||||
"icon-size": "Icon size",
|
"icon-size": "Icon size",
|
||||||
"advanced-settings": "Advanced settings",
|
"advanced-settings": "Advanced settings",
|
||||||
|
|||||||
@ -1183,4 +1183,166 @@ mat-label {
|
|||||||
.mat-expansion-panel {
|
.mat-expansion-panel {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget config
|
||||||
|
|
||||||
|
.tb-widget-config-panel {
|
||||||
|
box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
gap: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
letter-spacing: 0.15px;
|
||||||
|
position: relative;
|
||||||
|
&.no-padding-bottom {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
&.stroked {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.mat-expansion-panel {
|
||||||
|
&.tb-settings {
|
||||||
|
box-shadow: none;
|
||||||
|
.mat-content {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.mat-expansion-panel-header {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
letter-spacing: 0.25px;
|
||||||
|
padding: 0;
|
||||||
|
.mat-content {
|
||||||
|
flex: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.mat-expansion-indicator {
|
||||||
|
height: 32px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-expansion-panel-header-description {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
> .mat-expansion-panel-content {
|
||||||
|
> .mat-expansion-panel-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tb-json-object-panel, .tb-css-content-panel {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-expansion-panel-content {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-slide {
|
||||||
|
margin: 8px 0;
|
||||||
|
.mdc-form-field>label {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-widget-config-panel-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.tb-widget-config-panel-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
.tb-widget-config-row {
|
||||||
|
height: 56px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 12px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 6px;
|
||||||
|
&.same-padding {
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
&.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.mat-divider-vertical {
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
.mat-mdc-form-field {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-widget-config-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field {
|
||||||
|
&.mat-form-field-appearance-fill {
|
||||||
|
.mdc-text-field--filled:not(.mdc-text-field--disabled) {
|
||||||
|
&:before {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.mdc-line-ripple::before {
|
||||||
|
border-bottom-color: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-mdc-form-field-focus-overlay {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-mdc-text-field-wrapper {
|
||||||
|
&.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) {
|
||||||
|
padding-right: 12px;
|
||||||
|
padding-left: 12px;
|
||||||
|
&:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) {
|
||||||
|
.mdc-notched-outline__leading, .mdc-notched-outline__trailing {
|
||||||
|
border-color: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-mdc-form-field-infix {
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
min-height: 38px;
|
||||||
|
width: auto;
|
||||||
|
.mdc-text-field__input, .mat-mdc-select {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.center {
|
||||||
|
.mat-mdc-text-field-wrapper {
|
||||||
|
.mat-mdc-form-field-infix {
|
||||||
|
.mdc-text-field__input {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.number {
|
||||||
|
.mat-mdc-text-field-wrapper {
|
||||||
|
padding-right: 4px;
|
||||||
|
.mat-mdc-form-field-infix {
|
||||||
|
input.mdc-text-field__input[type=number]::-webkit-inner-spin-button,
|
||||||
|
input.mdc-text-field__input[type=number]::-webkit-outer-spin-button {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user