diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index f421f48b61..05a008080e 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -207,8 +207,9 @@ "templateHtml": "\n\n
\n
Dashboard state widget
\n
(Specify dashboard state id in the advanced widget settings)
\n
\n", "templateCss": ".dashboard-state-widget-prompt {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: 32px;\n font-weight: 500;\n color: #999;\n}\n\n.dashboard-state-widget-prompt .title {\n font-size: 32px;\n font-weight: 500;\n color: #999;\n}\n\n.dashboard-state-widget-prompt .subtitle {\n font-size: 24px;\n font-weight: normal;\n color: #999;\n text-align: center;\n}", "controllerScript": "self.onInit = function() {\n var $injector = self.ctx.$scope.$injector;\n self.ctx.$scope.stateId = self.ctx.settings.stateId || \"\";\n self.ctx.$scope.defaultAutofillLayout = self.ctx.settings.defaultAutofillLayout;\n self.ctx.$scope.defaultMargin = self.ctx.settings.defaultMargin;\n self.ctx.$scope.defaultBackgroundColor = self.ctx.settings.defaultBackgroundColor;\n self.ctx.$scope.syncParentStateParams = self.ctx.settings.syncParentStateParams !== false;\n}\n\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"required\": [],\n \"properties\": {\n \"stateId\": {\n \"title\": \"Dashboard state id\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultAutofillLayout\": {\n \"title\": \"Autofill state layout height by default\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultMargin\": {\n \"title\": \"Default widgets margin\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"defaultBackgroundColor\": {\n \"title\": \"Default background color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"syncParentStateParams\": {\n \"title\": \"Sync state params with parent dashboard\",\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n },\n \"form\": [\n \"stateId\",\n \"defaultAutofillLayout\",\n \"defaultMargin\",\n {\n \"key\": \"defaultBackgroundColor\",\n \"type\": \"color\"\n },\n \"syncParentStateParams\"\n ]\n}", - "dataKeySettingsSchema": "{}\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-dashboard-state-widget-settings", "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"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;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"syncParentStateParams\":true,\"defaultAutofillLayout\":true,\"defaultMargin\":0,\"defaultBackgroundColor\":\"#fff\"},\"title\":\"Dashboard state widget\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"noDataDisplayMessage\":\"\",\"showLegend\":false}" } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.html new file mode 100644 index 0000000000..a17d3a7a35 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.html @@ -0,0 +1,64 @@ + +
+
+ widgets.dashboard-state.dashboard-state-settings + + + + + + + + + + + + + widget-config.advanced-settings + + + + + {{ 'widgets.dashboard-state.autofill-state-layout' | translate }} + + + widgets.dashboard-state.default-margin + + + + + + {{ 'widgets.dashboard-state.sync-parent-state-params' | translate }} + + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.ts new file mode 100644 index 0000000000..7d2a11e9cc --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/dashboard-state-widget-settings.component.ts @@ -0,0 +1,99 @@ +/// +/// Copyright © 2016-2022 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. +/// + +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { WidgetActionType, WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Observable, of } from 'rxjs'; +import { map, mergeMap, startWith } from 'rxjs/operators'; + +@Component({ + selector: 'tb-dashboard-state-widget-settings', + templateUrl: './dashboard-state-widget-settings.component.html', + styleUrls: ['./widget-settings.scss'] +}) +export class DashboardStateWidgetSettingsComponent extends WidgetSettingsComponent { + + @ViewChild('dashboardStateInput') dashboardStateInput: ElementRef; + + dashboardStateWidgetSettingsForm: FormGroup; + + filteredDashboardStates: Observable>; + dashboardStateSearchText = ''; + + constructor(protected store: Store, + private fb: FormBuilder) { + super(store); + } + + protected settingsForm(): FormGroup { + return this.dashboardStateWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return { + stateId: '', + defaultAutofillLayout: true, + defaultMargin: 0, + defaultBackgroundColor: '#fff', + syncParentStateParams: true + }; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.dashboardStateWidgetSettingsForm = this.fb.group({ + stateId: [settings.stateId, []], + defaultAutofillLayout: [settings.defaultAutofillLayout, []], + defaultMargin: [settings.defaultMargin, [Validators.min(0)]], + defaultBackgroundColor: [settings.defaultBackgroundColor, []], + syncParentStateParams: [settings.syncParentStateParams, []] + }); + this.dashboardStateSearchText = ''; + this.filteredDashboardStates = this.dashboardStateWidgetSettingsForm.get('stateId').valueChanges + .pipe( + startWith(''), + map(value => value ? value : ''), + mergeMap(name => this.fetchDashboardStates(name) ) + ); + } + + public clearDashboardState(value: string = '') { + this.dashboardStateInput.nativeElement.value = value; + this.dashboardStateWidgetSettingsForm.get('stateId').patchValue(value, {emitEvent: true}); + setTimeout(() => { + this.dashboardStateInput.nativeElement.blur(); + this.dashboardStateInput.nativeElement.focus(); + }, 0); + } + + private fetchDashboardStates(searchText?: string): Observable> { + this.dashboardStateSearchText = searchText; + const stateIds = Object.keys(this.dashboard.configuration.states); + const result = searchText ? stateIds.filter(this.createFilterForDashboardState(searchText)) : stateIds; + if (result && result.length) { + return of(result); + } else { + return of([searchText]); + } + } + + private createFilterForDashboardState(query: string): (stateId: string) => boolean { + const lowercaseQuery = query.toLowerCase(); + return stateId => stateId.toLowerCase().indexOf(lowercaseQuery) === 0; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 577738dbdb..13510dcd93 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -38,6 +38,9 @@ import { LabelWidgetSettingsComponent } from '@home/components/widget/lib/settin import { SimpleCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/simple-card-widget-settings.component'; +import { + DashboardStateWidgetSettingsComponent +} from '@home/components/widget/lib/settings/dashboard-state-widget-settings.component'; @NgModule({ declarations: [ @@ -49,7 +52,8 @@ import { LabelWidgetFontComponent, LabelWidgetLabelComponent, LabelWidgetSettingsComponent, - SimpleCardWidgetSettingsComponent + SimpleCardWidgetSettingsComponent, + DashboardStateWidgetSettingsComponent ], imports: [ CommonModule, @@ -65,7 +69,8 @@ import { LabelWidgetFontComponent, LabelWidgetLabelComponent, LabelWidgetSettingsComponent, - SimpleCardWidgetSettingsComponent + SimpleCardWidgetSettingsComponent, + DashboardStateWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -78,5 +83,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type