Browse Source

UI: Settings forms for Timeseries table widget

pull/6545/head
Igor Kulikov 5 years ago
parent
commit
ac56d06a55
  1. 15
      application/src/main/data/json/system/widget_bundles/cards.json
  2. 2
      ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts
  3. 16
      ui-ngx/src/app/modules/home/components/widget/lib/settings/qrcode-widget-settings.component.html
  4. 23
      ui-ngx/src/app/modules/home/components/widget/lib/settings/qrcode-widget-settings.component.ts
  5. 67
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-key-settings.component.html
  6. 80
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-key-settings.component.ts
  7. 74
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-latest-key-settings.component.html
  8. 96
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-latest-key-settings.component.ts
  9. 95
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-widget-settings.component.html
  10. 98
      ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-widget-settings.component.ts
  11. 24
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  12. 113
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss
  13. 4
      ui-ngx/src/app/modules/home/components/widget/widget-settings.component.ts
  14. 6
      ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html
  15. 7
      ui-ngx/src/app/shared/components/js-func.component.html
  16. 5
      ui-ngx/src/app/shared/components/js-func.component.scss
  17. 2
      ui-ngx/src/app/shared/components/js-func.component.ts
  18. 9
      ui-ngx/src/app/shared/models/widget.models.ts
  19. 27
      ui-ngx/src/assets/locale/locale.constant-en_US.json

15
application/src/main/data/json/system/widget_bundles/cards.json

@ -55,10 +55,13 @@
"templateHtml": "<tb-timeseries-table-widget \n [ctx]=\"ctx\">\n</tb-timeseries-table-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n",
"settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}",
"dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n }\n ]\n}",
"latestDataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"LatestDataKeySettings\",\n \"properties\": {\n \"show\": {\n \"title\": \"Show latest data column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"order\": {\n \"title\": \"Latest data column order\",\n \"type\": \"number\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"show\",\n {\n \"key\": \"order\",\n \"condition\": \"model.show === true\"\n },\n {\n \"key\": \"useCellStyleFunction\",\n \"condition\": \"model.show === true\"\n },\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_style_fn\",\n \"condition\": \"model.show === true && model.useCellStyleFunction === true\"\n },\n {\n \"key\": \"useCellContentFunction\",\n \"condition\": \"model.show === true\"\n },\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/timeseries/cell_content_fn\",\n \"condition\": \"model.show === true && model.useCellContentFunction === true\"\n }\n ]\n}",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\"}"
"settingsSchema": "",
"dataKeySettingsSchema": "",
"latestDataKeySettingsSchema": "",
"settingsDirective": "tb-timeseries-table-widget-settings",
"dataKeySettingsDirective": "tb-timeseries-table-key-settings",
"latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true}"
}
},
{
@ -164,8 +167,8 @@
"templateHtml": "<tb-qrcode-widget \n [ctx]=\"ctx\">\n</tb-qrcode-widget>",
"templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
"controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n",
"settingsSchema": "{}\n",
"dataKeySettingsSchema": "{}\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "tb-qrcode-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data[0] ? data[0]['entityName'] : '';\"},\"title\":\"QR Code\"}"
}

2
ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts

@ -287,7 +287,7 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con
}
};
}
if (this.displayAdvanced && !this.dataKeySettingsFormGroup.valid) {
if (this.displayAdvanced && (!this.dataKeySettingsFormGroup.valid || !this.modelValue.settings)) {
return {
dataKeySettings: {
valid: false

16
ui-ngx/src/app/modules/home/components/widget/lib/settings/qrcode-widget-settings.component.html

@ -15,22 +15,22 @@
limitations under the License.
-->
<section [formGroup]="qrCodeWidgetSettingsForm" fxLayout="column">
<mat-checkbox formControlName="useQrCodeTextFunction" style="padding-bottom: 16px;">
<section class="tb-widget-settings" [formGroup]="qrCodeWidgetSettingsForm" fxLayout="column">
<mat-slide-toggle class="mat-slide" formControlName="useQrCodeTextFunction">
{{ 'widgets.qr-code.use-qr-code-text-function' | translate }}
</mat-checkbox>
<mat-form-field [fxShow]="qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value === false">
</mat-slide-toggle>
<mat-form-field [fxShow]="!qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value">
<mat-label translate>widgets.qr-code.qr-code-text-pattern</mat-label>
<input required matInput formControlName="qrCodeTextPattern">
<mat-error *ngIf="qrCodeWidgetSettingsForm.get('qrCodeTextPattern').hasError('required')">
{{ 'widgets.qr-code.qr-code-text-pattern-required' | translate }}
</mat-error>
</mat-form-field>
<section fxLayout="column" [fxShow]="qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value === true">
<label translate class="tb-title no-padding">widgets.qr-code.qr-code-text-function</label>
<tb-js-func #qrCodeTextFunctionComponent
formControlName="qrCodeTextFunction"
<section fxLayout="column" [fxShow]="qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value">
<tb-js-func formControlName="qrCodeTextFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['data']"
functionTitle="{{ 'widgets.qr-code.qr-code-text-function' | translate }}"
helpId="widget/lib/qrcode/qrcode_text_fn">
</tb-js-func>
</section>

23
ui-ngx/src/app/modules/home/components/widget/lib/settings/qrcode-widget-settings.component.ts

@ -14,22 +14,19 @@
/// limitations under the License.
///
import { Component, ViewChild } from '@angular/core';
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { JsFuncComponent } from '@shared/components/js-func.component';
@Component({
selector: 'tb-qrcode-widget-settings',
templateUrl: './qrcode-widget-settings.component.html',
styleUrls: []
styleUrls: ['./widget-settings.scss']
})
export class QrCodeWidgetSettingsComponent extends WidgetSettingsComponent {
@ViewChild('qrCodeTextFunctionComponent', {static: true}) qrCodeTextFunctionComponent: JsFuncComponent;
qrCodeWidgetSettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
@ -51,8 +48,8 @@ export class QrCodeWidgetSettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) {
this.qrCodeWidgetSettingsForm = this.fb.group({
qrCodeTextPattern: [settings.qrCodeTextPattern, []],
useQrCodeTextFunction: [settings.useQrCodeTextFunction, []],
qrCodeTextPattern: [settings.qrCodeTextPattern, [Validators.required]],
useQrCodeTextFunction: [settings.useQrCodeTextFunction, [Validators.required]],
qrCodeTextFunction: [settings.qrCodeTextFunction, []]
});
}
@ -64,13 +61,11 @@ export class QrCodeWidgetSettingsComponent extends WidgetSettingsComponent {
protected updateValidators(emitEvent: boolean) {
const useQrCodeTextFunction: boolean = this.qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value;
if (useQrCodeTextFunction) {
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').setValidators([]);
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').setValidators([Validators.required,
(control: AbstractControl) => this.qrCodeTextFunctionComponent.validate(control as FormControl)
]);
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').disable();
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').enable();
} else {
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').setValidators([Validators.required]);
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').setValidators([]);
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').enable();
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').disable();
}
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').updateValueAndValidity({emitEvent});
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').updateValueAndValidity({emitEvent});

67
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-key-settings.component.html

@ -0,0 +1,67 @@
<!--
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.
-->
<section class="tb-widget-settings" [formGroup]="timeseriesTableKeySettingsForm" fxLayout="column">
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.table.cell-style</legend>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableKeySettingsForm.get('useCellStyleFunction').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useCellStyleFunction" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.table.use-cell-style-function' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="cellStyleFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'rowData', 'ctx']"
functionTitle="{{ 'widgets.table.cell-style-function' | translate }}"
helpId="widget/lib/timeseries/cell_style_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.table.cell-content</legend>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableKeySettingsForm.get('useCellContentFunction').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useCellContentFunction" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.table.use-cell-content-function' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="cellContentFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'rowData', 'ctx']"
functionTitle="{{ 'widgets.table.cell-content-function' | translate }}"
helpId="widget/lib/timeseries/cell_content_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

80
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-key-settings.component.ts

@ -0,0 +1,80 @@
///
/// 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 } from '@angular/core';
import { 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';
@Component({
selector: 'tb-timeseries-table-key-settings',
templateUrl: './timeseries-table-key-settings.component.html',
styleUrls: ['./widget-settings.scss']
})
export class TimeseriesTableKeySettingsComponent extends WidgetSettingsComponent {
timeseriesTableKeySettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.timeseriesTableKeySettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
useCellStyleFunction: false,
cellStyleFunction: '',
useCellContentFunction: false,
cellContentFunction: ''
};
}
protected onSettingsSet(settings: WidgetSettings) {
this.timeseriesTableKeySettingsForm = this.fb.group({
useCellStyleFunction: [settings.useCellStyleFunction, []],
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
useCellContentFunction: [settings.useCellContentFunction, []],
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
});
}
protected validatorTriggers(): string[] {
return ['useCellStyleFunction', 'useCellContentFunction'];
}
protected updateValidators(emitEvent: boolean) {
const useCellStyleFunction: boolean = this.timeseriesTableKeySettingsForm.get('useCellStyleFunction').value;
const useCellContentFunction: boolean = this.timeseriesTableKeySettingsForm.get('useCellContentFunction').value;
if (useCellStyleFunction) {
this.timeseriesTableKeySettingsForm.get('cellStyleFunction').enable();
} else {
this.timeseriesTableKeySettingsForm.get('cellStyleFunction').disable();
}
if (useCellContentFunction) {
this.timeseriesTableKeySettingsForm.get('cellContentFunction').enable();
} else {
this.timeseriesTableKeySettingsForm.get('cellContentFunction').disable();
}
this.timeseriesTableKeySettingsForm.get('cellStyleFunction').updateValueAndValidity({emitEvent});
this.timeseriesTableKeySettingsForm.get('cellContentFunction').updateValueAndValidity({emitEvent});
}
}

74
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-latest-key-settings.component.html

@ -0,0 +1,74 @@
<!--
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.
-->
<section class="tb-widget-settings" [formGroup]="timeseriesTableLatestKeySettingsForm" fxLayout="column">
<mat-slide-toggle class="mat-slide" formControlName="show">
{{ 'widgets.table.show-latest-data-column' | translate }}
</mat-slide-toggle>
<mat-form-field [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" fxFlex class="mat-block">
<mat-label translate>widgets.table.latest-data-column-order</mat-label>
<input matInput type="number" step="1" formControlName="order">
</mat-form-field>
<fieldset [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.table.cell-style</legend>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableLatestKeySettingsForm.get('useCellStyleFunction').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useCellStyleFunction" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.table.use-cell-style-function' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="cellStyleFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'rowData', 'ctx']"
functionTitle="{{ 'widgets.table.cell-style-function' | translate }}"
helpId="widget/lib/timeseries/cell_style_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.table.cell-content</legend>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableLatestKeySettingsForm.get('useCellContentFunction').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useCellContentFunction" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.table.use-cell-content-function' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="cellContentFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'rowData', 'ctx']"
functionTitle="{{ 'widgets.table.cell-content-function' | translate }}"
helpId="widget/lib/timeseries/cell_content_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

96
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-latest-key-settings.component.ts

@ -0,0 +1,96 @@
///
/// 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 } from '@angular/core';
import { 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';
@Component({
selector: 'tb-timeseries-table-latest-key-settings',
templateUrl: './timeseries-table-latest-key-settings.component.html',
styleUrls: ['./widget-settings.scss']
})
export class TimeseriesTableLatestKeySettingsComponent extends WidgetSettingsComponent {
timeseriesTableLatestKeySettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.timeseriesTableLatestKeySettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
show: true,
useCellStyleFunction: false,
cellStyleFunction: '',
useCellContentFunction: false,
cellContentFunction: ''
};
}
protected onSettingsSet(settings: WidgetSettings) {
this.timeseriesTableLatestKeySettingsForm = this.fb.group({
show: [settings.show, []],
order: [settings.order, []],
useCellStyleFunction: [settings.useCellStyleFunction, []],
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
useCellContentFunction: [settings.useCellContentFunction, []],
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
});
}
protected validatorTriggers(): string[] {
return ['show', 'useCellStyleFunction', 'useCellContentFunction'];
}
protected updateValidators(emitEvent: boolean) {
const show: boolean = this.timeseriesTableLatestKeySettingsForm.get('show').value;
if (show) {
this.timeseriesTableLatestKeySettingsForm.get('order').enable();
this.timeseriesTableLatestKeySettingsForm.get('useCellStyleFunction').enable({emitEvent: false});
this.timeseriesTableLatestKeySettingsForm.get('useCellContentFunction').enable({emitEvent: false});
const useCellStyleFunction: boolean = this.timeseriesTableLatestKeySettingsForm.get('useCellStyleFunction').value;
const useCellContentFunction: boolean = this.timeseriesTableLatestKeySettingsForm.get('useCellContentFunction').value;
if (useCellStyleFunction) {
this.timeseriesTableLatestKeySettingsForm.get('cellStyleFunction').enable();
} else {
this.timeseriesTableLatestKeySettingsForm.get('cellStyleFunction').disable();
}
if (useCellContentFunction) {
this.timeseriesTableLatestKeySettingsForm.get('cellContentFunction').enable();
} else {
this.timeseriesTableLatestKeySettingsForm.get('cellContentFunction').disable();
}
} else {
this.timeseriesTableLatestKeySettingsForm.get('order').disable();
this.timeseriesTableLatestKeySettingsForm.get('useCellStyleFunction').disable({emitEvent: false});
this.timeseriesTableLatestKeySettingsForm.get('cellStyleFunction').disable();
this.timeseriesTableLatestKeySettingsForm.get('useCellContentFunction').disable({emitEvent: false});
this.timeseriesTableLatestKeySettingsForm.get('cellContentFunction').disable();
}
this.timeseriesTableLatestKeySettingsForm.get('order').updateValueAndValidity({emitEvent});
this.timeseriesTableLatestKeySettingsForm.get('cellStyleFunction').updateValueAndValidity({emitEvent});
this.timeseriesTableLatestKeySettingsForm.get('cellContentFunction').updateValueAndValidity({emitEvent});
}
}

95
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-widget-settings.component.html

@ -0,0 +1,95 @@
<!--
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.
-->
<section class="tb-widget-settings" [formGroup]="timeseriesTableWidgetSettingsForm" fxLayout="column">
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.table.common-table-settings</legend>
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<section fxLayout="column" fxFlex>
<mat-checkbox formControlName="enableSearch" style="margin-bottom: 16px;">
{{ 'widgets.table.enable-search' | translate }}
</mat-checkbox>
</section>
<section fxLayout="column" fxFlex>
<mat-checkbox formControlName="enableStickyHeader" style="margin-bottom: 16px;">
{{ 'widgets.table.enable-sticky-header' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="enableStickyAction" style="margin-bottom: 16px;">
{{ 'widgets.table.enable-sticky-action' | translate }}
</mat-checkbox>
</section>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.table.hidden-cell-button-display-mode</mat-label>
<mat-select formControlName="reserveSpaceForHiddenAction">
<mat-option [value]="'true'">
{{ 'widgets.table.show-empty-space-hidden-action' | translate }}
</mat-option>
<mat-option [value]="'false'">
{{ 'widgets.table.dont-reserve-space-hidden-action' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<section fxLayout="column" fxLayoutGap="8px">
<mat-slide-toggle formControlName="showTimestamp">
{{ 'widgets.table.display-timestamp' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="showMilliseconds">
{{ 'widgets.table.display-milliseconds' | translate }}
</mat-slide-toggle>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<mat-slide-toggle fxFlex formControlName="displayPagination">
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.table.default-page-size</mat-label>
<input matInput type="number" min="1" step="1" formControlName="defaultPageSize">
</mat-form-field>
</section>
<mat-slide-toggle formControlName="useEntityLabel">
{{ 'widgets.table.use-entity-label-tab-name' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="hideEmptyLines">
{{ 'widgets.table.hide-empty-lines' | translate }}
</mat-slide-toggle>
</section>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.table.row-style</legend>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableWidgetSettingsForm.get('useRowStyleFunction').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="useRowStyleFunction" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.table.use-row-style-function' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="rowStyleFunction"
[globalVariables]="functionScopeVariables"
[functionArgs]="['rowData', 'ctx']"
functionTitle="{{ 'widgets.table.row-style-function' | translate }}"
helpId="widget/lib/timeseries/row_style_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

98
ui-ngx/src/app/modules/home/components/widget/lib/settings/timeseries-table-widget-settings.component.ts

@ -0,0 +1,98 @@
///
/// 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 } from '@angular/core';
import { 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';
@Component({
selector: 'tb-timeseries-table-widget-settings',
templateUrl: './timeseries-table-widget-settings.component.html',
styleUrls: ['./widget-settings.scss']
})
export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsComponent {
timeseriesTableWidgetSettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.timeseriesTableWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
enableSearch: true,
enableStickyHeader: true,
enableStickyAction: true,
reserveSpaceForHiddenAction: 'true',
showTimestamp: true,
showMilliseconds: false,
displayPagination: true,
useEntityLabel: false,
defaultPageSize: 10,
hideEmptyLines: false,
disableStickyHeader: false,
useRowStyleFunction: false,
rowStyleFunction: ''
};
}
protected onSettingsSet(settings: WidgetSettings) {
this.timeseriesTableWidgetSettingsForm = this.fb.group({
enableSearch: [settings.enableSearch, []],
enableStickyHeader: [settings.enableStickyHeader, []],
enableStickyAction: [settings.enableStickyAction, []],
reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []],
showTimestamp: [settings.showTimestamp, []],
showMilliseconds: [settings.showMilliseconds, []],
displayPagination: [settings.displayPagination, []],
useEntityLabel: [settings.useEntityLabel, []],
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
hideEmptyLines: [settings.hideEmptyLines, []],
disableStickyHeader: [settings.disableStickyHeader, []],
useRowStyleFunction: [settings.useRowStyleFunction, []],
rowStyleFunction: [settings.rowStyleFunction, [Validators.required]]
});
}
protected validatorTriggers(): string[] {
return ['useRowStyleFunction', 'displayPagination'];
}
protected updateValidators(emitEvent: boolean) {
const useRowStyleFunction: boolean = this.timeseriesTableWidgetSettingsForm.get('useRowStyleFunction').value;
const displayPagination: boolean = this.timeseriesTableWidgetSettingsForm.get('displayPagination').value;
if (useRowStyleFunction) {
this.timeseriesTableWidgetSettingsForm.get('rowStyleFunction').enable();
} else {
this.timeseriesTableWidgetSettingsForm.get('rowStyleFunction').disable();
}
if (displayPagination) {
this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').enable();
} else {
this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').disable();
}
this.timeseriesTableWidgetSettingsForm.get('rowStyleFunction').updateValueAndValidity({emitEvent});
this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').updateValueAndValidity({emitEvent});
}
}

24
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -20,10 +20,22 @@ import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
import { IWidgetSettingsComponent } from '@shared/models/widget.models';
import {
TimeseriesTableWidgetSettingsComponent
} from '@home/components/widget/lib/settings/timeseries-table-widget-settings.component';
import {
TimeseriesTableKeySettingsComponent
} from '@home/components/widget/lib/settings/timeseries-table-key-settings.component';
import {
TimeseriesTableLatestKeySettingsComponent
} from '@home/components/widget/lib/settings/timeseries-table-latest-key-settings.component';
@NgModule({
declarations: [
QrCodeWidgetSettingsComponent
QrCodeWidgetSettingsComponent,
TimeseriesTableWidgetSettingsComponent,
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent
],
imports: [
CommonModule,
@ -31,12 +43,18 @@ import { IWidgetSettingsComponent } from '@shared/models/widget.models';
SharedHomeComponentsModule
],
exports: [
QrCodeWidgetSettingsComponent
QrCodeWidgetSettingsComponent,
TimeseriesTableWidgetSettingsComponent,
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent
]
})
export class WidgetSettingsModule {
}
export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsComponent>} = {
'tb-qrcode-widget-settings': QrCodeWidgetSettingsComponent
'tb-qrcode-widget-settings': QrCodeWidgetSettingsComponent,
'tb-timeseries-table-widget-settings': TimeseriesTableWidgetSettingsComponent,
'tb-timeseries-table-key-settings': TimeseriesTableKeySettingsComponent,
'tb-timeseries-table-latest-key-settings': TimeseriesTableLatestKeySettingsComponent
};

113
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss

@ -0,0 +1,113 @@
/**
* 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.
*/
:host {
.tb-widget-settings {
.fields-group {
padding: 0 16px 8px;
margin-bottom: 10px;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
legend {
color: rgba(0, 0, 0, .7);
width: fit-content;
}
legend + * {
margin-top: 16px;
}
&.fields-group-slider {
padding: 0;
legend {
margin-left: 16px;
}
.tb-settings {
margin-top: 0;
padding: 0 16px 8px;
}
}
}
}
}
:host ::ng-deep {
.tb-widget-settings {
.mat-checkbox-label {
white-space: normal;
}
.mat-expansion-panel {
&.tb-settings {
box-shadow: none;
.mat-content {
overflow: visible;
}
.mat-expansion-panel-header {
padding: 0;
&:hover {
background: none;
}
.mat-expansion-indicator {
padding: 2px;
}
}
.mat-expansion-panel-header-description {
align-items: center;
}
.mat-expansion-panel-body {
padding: 0;
}
.mat-checkbox-layout {
margin: 5px 0;
}
.mat-checkbox-inner-container {
margin-right: 12px;
}
}
.mat-expansion-panel-content {
font: inherit;
}
}
.mat-slide {
margin: 8px 0;
}
.slide-block {
display: block;
&:not(:last-child) {
margin-bottom: 8px;
}
}
.mat-slide-toggle-content {
white-space: normal;
}
}
}

4
ui-ngx/src/app/modules/home/components/widget/widget-settings.component.ts

@ -43,6 +43,7 @@ import { JsonFormComponentData } from '@shared/components/json-form/json-form-co
import { IWidgetSettingsComponent, Widget, WidgetSettings } from '@shared/models/widget.models';
import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module';
import { Dashboard } from '@shared/models/dashboard.models';
import { WidgetService } from '@core/http/widget.service';
@Component({
selector: 'tb-widget-settings',
@ -100,6 +101,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
constructor(private translate: TranslateService,
private cfr: ComponentFactoryResolver,
private widgetService: WidgetService,
private fb: FormBuilder) {
this.widgetSettingsFormGroup = this.fb.group({
settings: [null, Validators.required]
@ -143,6 +145,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
if (this.definedSettingsComponent) {
this.definedSettingsComponent.dashboard = this.dashboard;
this.definedSettingsComponent.widget = this.widget;
this.definedSettingsComponent.functionScopeVariables = this.widgetService.getWidgetScopeVariables();
this.definedSettingsComponent.settings = this.widgetSettingsFormData.model;
this.changeSubscription = this.definedSettingsComponent.settingsChanged.subscribe((settings) => {
this.updateModel(settings);
@ -196,6 +199,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
this.definedSettingsComponent = this.definedSettingsComponentRef.instance;
this.definedSettingsComponent.dashboard = this.dashboard;
this.definedSettingsComponent.widget = this.widget;
this.definedSettingsComponent.functionScopeVariables = this.widgetService.getWidgetScopeVariables();
this.changeSubscription = this.definedSettingsComponent.settingsChanged.subscribe((settings) => {
this.updateModel(settings);
});

6
ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html

@ -265,6 +265,12 @@
[(ngModel)]="widget.dataKeySettingsDirective"
(ngModelChange)="isDirty = true"/>
</mat-form-field>
<mat-form-field *ngIf="widget.type === widgetTypes.timeseries" class="mat-block">
<mat-label translate>widget.latest-data-key-settings-form-selector</mat-label>
<input matInput
[(ngModel)]="widget.latestDataKeySettingsDirective"
(ngModelChange)="isDirty = true"/>
</mat-form-field>
</div>
</div>
</mat-tab>

7
ui-ngx/src/app/shared/components/js-func.component.html

@ -19,7 +19,8 @@
tb-fullscreen
[fullscreen]="fullscreen" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" class="tb-js-func-toolbar">
<label class="tb-title no-padding">{{'function ' + (functionName ? functionName : '') + '(' + functionArgsString + ') {'}}</label>
<label *ngIf="functionTitle" class="tb-title no-padding">{{functionTitle + ': f(' + functionArgsString + ')' }}</label>
<label *ngIf="!functionTitle" class="tb-title no-padding">{{'function ' + (functionName ? functionName : '') + '(' + functionArgsString + ') {'}}</label>
<span fxFlex></span>
<button type='button' *ngIf="!disabled" mat-button class="tidy" (click)="beautifyJs()">
{{'js-func.tidy' | translate }}
@ -36,10 +37,10 @@
</div>
</fieldset>
</div>
<div id="tb-javascript-panel" class="tb-js-func-panel" fxLayout="column" tb-toast toastTarget="{{toastTargetId}}">
<div id="tb-javascript-panel" class="tb-js-func-panel" [ngClass]="{'tb-js-func-title': functionTitle}" fxLayout="column" tb-toast toastTarget="{{toastTargetId}}">
<div #javascriptEditor id="tb-javascript-input" [ngClass]="{'fill-height': fillHeight}"></div>
</div>
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;">
<label class="tb-title no-padding">}</label>
<label *ngIf="!functionTitle" class="tb-title no-padding">}</label>
</div>
</div>

5
ui-ngx/src/app/shared/components/js-func.component.scss

@ -26,9 +26,12 @@
.tb-js-func-panel {
height: calc(100% - 80px);
margin-left: 15px;
border: 1px solid #c0c0c0;
&:not(.tb-js-func-title) {
margin-left: 15px;
}
#tb-javascript-input {
width: 100%;
min-width: 200px;

2
ui-ngx/src/app/shared/components/js-func.component.ts

@ -69,6 +69,8 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
toastTargetId = `jsFuncEditor-${guid()}`;
@Input() functionTitle: string;
@Input() functionName: string;
@Input() functionArgs: Array<string>;

9
ui-ngx/src/app/shared/models/widget.models.ts

@ -615,6 +615,7 @@ export interface WidgetSize {
export interface IWidgetSettingsComponent {
dashboard: Dashboard;
widget: Widget;
functionScopeVariables: string[];
settings: WidgetSettings;
settingsChanged: Observable<WidgetSettings>;
validate();
@ -630,12 +631,18 @@ export abstract class WidgetSettingsComponent extends PageComponent implements
widget: Widget;
functionScopeVariables: string[];
settingsValue: WidgetSettings;
private settingsSet = false;
set settings(value: WidgetSettings) {
this.settingsValue = value || this.defaultSettings();
if (!value) {
this.settingsValue = this.defaultSettings();
} else {
this.settingsValue = {...this.defaultSettings(), ...value};
}
if (!this.settingsSet) {
this.settingsSet = true;
this.setupSettings(this.settingsValue);

27
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3001,6 +3001,7 @@
"image-preview": "Image preview",
"settings-form-selector": "Settings form selector",
"data-key-settings-form-selector": "Data key settings form selector",
"latest-data-key-settings-form-selector": "Latest data key settings form selector",
"javascript": "Javascript",
"js": "JS",
"remove-widget-type-title": "Are you sure you want to remove the widget type '{{widgetName}}'?",
@ -3366,6 +3367,32 @@
"drawCircleMarkerButton": "Create circle marker",
"rotateButton": "Rotate polygon"
}
},
"table": {
"common-table-settings": "Common Table Settings",
"enable-search": "Enable search",
"enable-sticky-header": "Always display header",
"enable-sticky-action": "Always display actions column",
"hidden-cell-button-display-mode": "Hidden cell button actions display mode",
"show-empty-space-hidden-action": "Show empty space instead of hidden cell button action",
"dont-reserve-space-hidden-action": "Don't reserve space for hidden action buttons",
"display-timestamp": "Display timestamp column",
"display-milliseconds": "Display timestamp milliseconds",
"display-pagination": "Display pagination",
"default-page-size": "Default page size",
"use-entity-label-tab-name": "Use entity label in tab name",
"hide-empty-lines": "Hide empty lines",
"row-style": "Row style",
"use-row-style-function": "Use row style function",
"row-style-function": "Row style function",
"cell-style": "Cell style",
"use-cell-style-function": "Use cell style function",
"cell-style-function": "Cell style function",
"cell-content": "Cell content",
"use-cell-content-function": "Use cell content function",
"cell-content-function": "Cell content function",
"show-latest-data-column": "Show latest data column",
"latest-data-column-order": "Latest data column order"
}
},
"icon": {

Loading…
Cancel
Save