Browse Source

UI: Timeseries line chart config.

pull/8881/head
Igor Kulikov 3 years ago
parent
commit
ea56b2a168
  1. 14
      ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html
  2. 10
      ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss
  3. 8
      ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
  4. 4
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html
  5. 7
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts
  6. 4
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html
  7. 7
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts
  8. 5
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html
  9. 18
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts
  10. 113
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html
  11. 167
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts
  12. 2
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html
  13. 3
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts
  14. 6
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts
  15. 20
      ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html
  16. 107
      ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss
  17. 2
      ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts
  18. 17
      ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts
  19. 11
      ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts
  20. 2
      ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html
  21. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html
  22. 14
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html
  23. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html
  24. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html
  25. 20
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html
  26. 257
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html
  27. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts
  28. 74
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html
  29. 62
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss
  30. 15
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts
  31. 496
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html
  32. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts
  33. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts
  34. 56
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html
  35. 57
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts
  36. 32
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  37. 38
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  38. 41
      ui-ngx/src/styles.scss

14
ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html

@ -54,11 +54,13 @@
</button>
</div>
</tb-widget-config>
<tb-widget-preview *ngIf="previewMode" class="widget-preview-section"
[aliasController]="aliasController"
[stateController]="stateController"
[widget]="widget"
[widgetConfig]="widgetFormGroup.get('widgetConfig').value.config">
</tb-widget-preview>
<div *ngIf="previewMode" class="widget-preview-background">
<tb-widget-preview class="widget-preview-section"
[aliasController]="aliasController"
[stateController]="stateController"
[widget]="widget"
[widgetConfig]="widgetFormGroup.get('widgetConfig').value.config">
</tb-widget-preview>
</div>
</fieldset>
</form>

10
ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss

@ -14,9 +14,17 @@
* limitations under the License.
*/
:host {
.widget-preview-section {
.widget-preview-background {
position: absolute;
top: 72px;
left: 0;
right: 0;
bottom: 0;
background: #fff;
}
.widget-preview-section {
position: absolute;
top: 0;
left: 16px;
right: 16px;
bottom: 16px;

8
ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts

@ -33,6 +33,8 @@ import { DataKeyRowComponent } from '@home/components/widget/config/basic/common
import {
TimeseriesTableBasicConfigComponent
} from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component';
import { FlotBasicConfigComponent } from '@home/components/widget/config/basic/chart/flot-basic-config.component';
import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module';
@NgModule({
declarations: [
@ -40,12 +42,14 @@ import {
SimpleCardBasicConfigComponent,
EntitiesTableBasicConfigComponent,
TimeseriesTableBasicConfigComponent,
FlotBasicConfigComponent,
DataKeyRowComponent,
DataKeysPanelComponent
],
imports: [
CommonModule,
SharedModule,
WidgetSettingsModule,
WidgetConfigComponentsModule
],
exports: [
@ -53,6 +57,7 @@ import {
SimpleCardBasicConfigComponent,
EntitiesTableBasicConfigComponent,
TimeseriesTableBasicConfigComponent,
FlotBasicConfigComponent,
DataKeyRowComponent,
DataKeysPanelComponent
]
@ -63,5 +68,6 @@ export class BasicWidgetConfigModule {
export const basicWidgetConfigComponentsMap: {[key: string]: Type<IBasicWidgetConfigComponent>} = {
'tb-simple-card-basic-config': SimpleCardBasicConfigComponent,
'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent,
'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent
'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent,
'tb-flot-basic-config': FlotBasicConfigComponent
};

4
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html

@ -40,7 +40,7 @@
<div class="tb-widget-config-panel">
<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">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
@ -63,7 +63,7 @@
</div>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.table.show-card-buttons</div>
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="search">{{ 'action.search' | translate }}</mat-chip-option>
<mat-chip-option value="columnsToDisplay">{{ 'widgets.table.columns-to-display' | translate }}</mat-chip-option>

7
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts

@ -29,6 +29,7 @@ import {
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { isUndefined } from '@core/utils';
import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component';
@Component({
selector: 'tb-entities-table-basic-config',
@ -74,11 +75,7 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen
protected onConfigSet(configData: WidgetConfigComponentData) {
this.entitiesTableWidgetConfigForm = this.fb.group({
timewindowConfig: [{
useDashboardTimewindow: configData.config.useDashboardTimewindow,
displayTimewindow: configData.config.displayTimewindow,
timewindow: configData.config.timewindow
}, []],
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
columns: [this.getColumns(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],

4
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html

@ -31,7 +31,7 @@
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widget-config.appearance</div>
<div class="tb-widget-config-row">
<div translate>widgets.simple-card.label</div>
<div class="fixed-title-width" translate>widgets.simple-card.label</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
@ -57,7 +57,7 @@
</div>
<div class="tb-widget-config-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>

7
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts

@ -27,6 +27,7 @@ import {
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component';
@Component({
selector: 'tb-simple-card-basic-config',
@ -63,11 +64,7 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
protected onConfigSet(configData: WidgetConfigComponentData) {
this.simpleCardWidgetConfigForm = this.fb.group({
timewindowConfig: [{
useDashboardTimewindow: configData.config.useDashboardTimewindow,
displayTimewindow: configData.config.useDashboardTimewindow,
timewindow: configData.config.timewindow
}, []],
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
label: [this.getDataKeyLabel(configData.config.datasources), []],
labelPosition: [configData.config.settings?.labelPosition, []],

5
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html

@ -21,6 +21,7 @@
<tb-datasources
[configMode]="basicMode"
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
@ -39,7 +40,7 @@
<div class="tb-widget-config-panel">
<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">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
@ -62,7 +63,7 @@
</div>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.table.show-card-buttons</div>
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="search">{{ 'action.search' | translate }}</mat-chip-option>
<mat-chip-option value="columnsToDisplay">{{ 'widgets.table.columns-to-display' | translate }}</mat-chip-option>

18
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts

@ -20,15 +20,11 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation, WidgetConfig
} from '@shared/models/widget.models';
import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { deepClone, isUndefined } from '@core/utils';
import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component';
@Component({
selector: 'tb-timeseries-table-basic-config',
@ -65,11 +61,7 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon
protected onConfigSet(configData: WidgetConfigComponentData) {
this.timeseriesTableWidgetConfigForm = this.fb.group({
timewindowConfig: [{
useDashboardTimewindow: configData.config.useDashboardTimewindow,
displayTimewindow: configData.config.displayTimewindow,
timewindow: configData.config.timewindow
}, []],
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
columns: [this.getColumns(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
@ -92,11 +84,11 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon
this.setColumns(config.columns, this.widgetConfig.config.datasources);
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.title = config.title;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.color = config.color;
this.widgetConfig.config.backgroundColor = config.backgroundColor;

113
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html

@ -0,0 +1,113 @@
<!--
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.
-->
<ng-container [formGroup]="flotWidgetConfigForm">
<tb-timewindow-config-panel formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideSourceSelection
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide fixed-title-width" 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]="flotWidgetConfigForm.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">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widget-config.background-color' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="backgroundColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.chart.chart-appearance</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="verticalLines">
{{ 'widgets.chart.vertical-grid-lines' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="horizontalLines">
{{ 'widgets.chart.horizontal-grid-lines' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="flotWidgetConfigForm.get('showLegend').value" [disabled]="!flotWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-legend-config formControlName="legendConfig">
</tb-legend-config>
</ng-template>
</mat-expansion-panel>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

167
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts

@ -0,0 +1,167 @@
///
/// 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.
///
import { Component } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { isUndefined } from '@core/utils';
import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component';
@Component({
selector: 'tb-flot-basic-config',
templateUrl: './flot-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class FlotBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.flotWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
flotWidgetConfigForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.flotWidgetConfigForm;
}
protected setupDefaults(configData: WidgetConfigComponentData) {
this.setupDefaultDatasource(configData,
[{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
this.flotWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
cardButtons: [this.getCardButtons(configData.config), []],
color: [configData.config.color, []],
backgroundColor: [configData.config.backgroundColor, []],
verticalLines: [configData.config.settings?.grid?.verticalLines, []],
horizontalLines: [configData.config.settings?.grid?.horizontalLines, []],
showLegend: [configData.config.settings?.showLegend, []],
legendConfig: [configData.config.settings?.legendConfig, []],
actions: [configData.config.actions || {}, []]
});
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow;
this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow;
this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow;
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.actions = config.actions;
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.widgetConfig.config.settings.grid = this.widgetConfig.config.settings.grid || {};
this.widgetConfig.config.settings.grid.verticalLines = config.verticalLines;
this.widgetConfig.config.settings.grid.horizontalLines = config.horizontalLines;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendConfig = config.legendConfig;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLegend'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.flotWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.flotWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.flotWidgetConfigForm.get('showLegend').value;
if (showTitle) {
this.flotWidgetConfigForm.get('title').enable();
this.flotWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.flotWidgetConfigForm.get('titleIcon').enable();
this.flotWidgetConfigForm.get('iconColor').enable();
} else {
this.flotWidgetConfigForm.get('titleIcon').disable();
this.flotWidgetConfigForm.get('iconColor').disable();
}
} else {
this.flotWidgetConfigForm.get('title').disable();
this.flotWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.flotWidgetConfigForm.get('titleIcon').disable();
this.flotWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.flotWidgetConfigForm.get('legendConfig').enable();
} else {
this.flotWidgetConfigForm.get('legendConfig').disable();
}
this.flotWidgetConfigForm.get('title').updateValueAndValidity({emitEvent});
this.flotWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false});
this.flotWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent});
this.flotWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent});
this.flotWidgetConfigForm.get('legendConfig').updateValueAndValidity({emitEvent});
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
}

2
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html

@ -153,7 +153,7 @@
</tb-widget-units>
</div>
<div class="tb-decimals-field">
<mat-form-field *ngIf="displayUnitsOrDigits" appearance="outline" class="tb-inline-field center number" subscriptSizing="dynamic">
<mat-form-field *ngIf="displayUnitsOrDigits" appearance="outline" class="tb-inline-field number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>

3
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts

@ -154,8 +154,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan
}
get hasAdditionalLatestDataKeys(): boolean {
return this.widgetConfigComponent.widgetType === widgetType.timeseries &&
this.widgetConfigComponent.modelValue?.typeParameters?.hasAdditionalLatestDataKeys;
return this.dataKeysPanelComponent.hasAdditionalLatestDataKeys;
}
get widget(): Widget {

6
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts

@ -100,6 +100,10 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC
@coerceBoolean()
hideDataKeyColor = false;
@Input()
@coerceBoolean()
hideSourceSelection = false;
dataKeyType: DataKeyType;
alarmKeys: Array<DataKey>;
functionTypeKeys: Array<DataKey>;
@ -117,7 +121,7 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC
}
get hasAdditionalLatestDataKeys(): boolean {
return this.widgetConfigComponent.widgetType === widgetType.timeseries &&
return !this.hideSourceSelection && this.widgetConfigComponent.widgetType === widgetType.timeseries &&
this.widgetConfigComponent.modelValue?.typeParameters?.hasAdditionalLatestDataKeys;
}

20
ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div class="tb-datakey-config" *ngIf="dataKeyConfigMode === dataKeyConfigModes.general; else advanced"
<div *ngIf="dataKeyConfigMode === dataKeyConfigModes.general; else advanced"
[formGroup]="dataKeyFormGroup">
<div class="mat-padding" fxLayout="column" style="gap: 16px;">
<div class="tb-widget-config-panel">
@ -54,7 +54,7 @@
</div>
<div class="tb-widget-config-row space-between" *ngIf="!hideDataKeyDecimals">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
@ -182,14 +182,12 @@
</div>
</div>
<ng-template #advanced>
<div class="tb-datakey-config" [formGroup]="dataKeySettingsFormGroup">
<div class="mat-padding" fxLayout="column">
<tb-widget-settings
[dashboard]="dashboard"
[aliasController]="aliasController"
[widget]="widget"
formControlName="settings">
</tb-widget-settings>
</div>
<div class="mat-padding" fxLayout="column" [formGroup]="dataKeySettingsFormGroup">
<tb-widget-settings
[dashboard]="dashboard"
[aliasController]="aliasController"
[widget]="widget"
formControlName="settings">
</tb-widget-settings>
</div>
</ng-template>

107
ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss

@ -1,107 +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.
*/
@import '../../../../../../scss/constants';
:host {
.tb-datakey-config {
.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 + * {
display: block;
margin-top: 16px;
}
&.fields-group-slider {
padding: 0;
legend {
margin-left: 16px;
}
> .tb-settings {
margin-top: 0;
padding: 0 16px 8px;
}
}
}
.tb-hint.after-fields {
margin-top: -0.75em;
max-width: fit-content;
line-height: 15px;
}
}
}
:host ::ng-deep {
.tb-datakey-config {
.mat-expansion-panel {
&.tb-settings {
box-shadow: none;
.mat-content {
overflow: visible;
}
.mat-expansion-panel-header {
padding: 0;
color: rgba(0, 0, 0, 0.87);
&:hover {
background: none;
}
.mat-expansion-indicator {
padding: 2px;
}
}
&.comparison {
.mat-expansion-panel-header {
height: fit-content;
}
}
.mat-expansion-panel-header-description {
align-items: center;
}
> .mat-expansion-panel-content {
> .mat-expansion-panel-body {
padding: 0;
}
}
}
.mat-expansion-panel-content {
font: inherit;
}
}
.mat-slide {
margin: 8px 0;
}
}
}

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

@ -57,7 +57,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
@Component({
selector: 'tb-data-key-config',
templateUrl: './data-key-config.component.html',
styleUrls: ['./data-key-config.component.scss'],
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,

17
ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts

@ -69,7 +69,7 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
}
public get maxDatasources(): number {
return this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources;
return this.forceSingleDatasource ? 1 : this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources;
}
public get singleDatasource(): boolean {
@ -108,6 +108,10 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
@coerceBoolean()
hideDataKeys = false;
@Input()
@coerceBoolean()
forceSingleDatasource = false;
@Input()
configMode: WidgetConfigMode;
@ -175,13 +179,20 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
this.datasourcesMode = this.detectDatasourcesMode(datasources);
let changed = false;
if (datasources) {
datasources.forEach((datasource) => {
let length;
if (this.maxDatasources === -1) {
length = datasources.length;
} else {
length = Math.min(this.maxDatasources, datasources.length);
}
for (let i = 0; i < length; i++) {
const datasource = datasources[i];
if (this.basicMode && datasource.type !== this.datasourcesMode) {
datasource.type = this.datasourcesMode;
changed = true;
}
this.datasourcesFormArray.push(this.fb.control(datasource, []), {emitEvent: false});
});
}
}
if (this.singleDatasource && !this.datasourcesFormArray.length) {
this.addDatasource(false);

11
ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts

@ -17,10 +17,11 @@
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { widgetType } from '@shared/models/widget.models';
import { WidgetConfig, widgetType } from '@shared/models/widget.models';
import { Timewindow } from '@shared/models/time/time.models';
import { TranslateService } from '@ngx-translate/core';
import { coerceBoolean } from '@shared/decorators/coercion';
import { isDefined } from '@core/utils';
export interface TimewindowConfigData {
useDashboardTimewindow: boolean;
@ -28,6 +29,14 @@ export interface TimewindowConfigData {
timewindow: Timewindow;
}
export const getTimewindowConfig = (config: WidgetConfig): TimewindowConfigData => ({
useDashboardTimewindow: isDefined(config.useDashboardTimewindow) ?
config.useDashboardTimewindow : true,
displayTimewindow: isDefined(config.displayTimewindow) ?
config.displayTimewindow : true,
timewindow: config.timewindow
});
@Component({
selector: 'tb-timewindow-config-panel',
templateUrl: './timewindow-config-panel.component.html',

2
ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html

@ -15,6 +15,6 @@
limitations under the License.
-->
<mat-form-field appearance="outline" class="tb-inline-field center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="tb-inline-field" subscriptSizing="dynamic">
<input matInput [formControl]="unitsFormControl" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>

8
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html

@ -19,20 +19,20 @@
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.column-settings</div>
<div class="tb-widget-config-row">
<div>{{ 'widgets.table.custom-title' | translate }}</div>
<div class="fixed-title-width">{{ 'widgets.table.custom-title' | translate }}</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="customTitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.column-width' | translate }}</div>
<mat-form-field appearance="outline" class="center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="columnWidth" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.default-column-visibility' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="defaultColumnVisibility">
<mat-option [value]="'visible'">
{{ 'widgets.table.column-visibility-visible' | translate }}
@ -48,7 +48,7 @@
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.column-selection-to-display' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="columnSelectionToDisplay">
<mat-option [value]="'enabled'">
{{ 'widgets.table.column-selection-to-display-enabled' | translate }}

14
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html

@ -19,7 +19,7 @@
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.table-header</div>
<div class="tb-widget-config-row">
<div>{{ 'widgets.table.entities-table-title' | translate }}</div>
<div class="fixed-title-width">{{ 'widgets.table.entities-table-title' | translate }}</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="entitiesTitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
@ -31,10 +31,10 @@
</div>
<div class="tb-widget-config-panel stroked">
<div class="tb-widget-config-panel-title" translate>widgets.table.header-buttons</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableSearch">
<mat-slide-toggle class="mat-slide" formControlName="enableSearch">
{{ 'widgets.table.enable-search' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableSelectColumnDisplay">
<mat-slide-toggle class="mat-slide" formControlName="enableSelectColumnDisplay">
{{ 'widgets.table.enable-select-column-display' | translate }}
</mat-slide-toggle>
</div>
@ -42,7 +42,7 @@
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.columns</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="displayEntityName">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="displayEntityName">
{{ 'widgets.table.display-entity-name' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
@ -50,7 +50,7 @@
</mat-form-field>
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="displayEntityName">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="displayEntityName">
{{ 'widgets.table.display-entity-label' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
@ -85,12 +85,12 @@
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.pagination</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="displayPagination">
<mat-slide-toggle class="mat-slide" formControlName="displayPagination">
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-widget-config-row space-between">
<div translate>widgets.table.default-page-size</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="defaultPageSize" type="number" min="1" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>

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

@ -20,7 +20,7 @@
<div class="tb-widget-config-panel-title" translate>widgets.table.column-settings</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.default-column-visibility' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="defaultColumnVisibility">
<mat-option [value]="'visible'">
{{ 'widgets.table.column-visibility-visible' | translate }}
@ -36,7 +36,7 @@
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.column-selection-to-display' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="columnSelectionToDisplay">
<mat-option [value]="'enabled'">
{{ 'widgets.table.column-selection-to-display-enabled' | translate }}

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

@ -18,18 +18,18 @@
<ng-container [formGroup]="timeseriesTableLatestKeySettingsForm">
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.column-settings</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="show">
<mat-slide-toggle class="mat-slide" formControlName="show">
{{ 'widgets.table.show-latest-data-column' | translate }}
</mat-slide-toggle>
<div [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" class="tb-widget-config-row space-between">
<div translate>widgets.table.latest-data-column-order</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="order" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.default-column-visibility' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="defaultColumnVisibility">
<mat-option [value]="'visible'">
{{ 'widgets.table.column-visibility-visible' | translate }}
@ -45,7 +45,7 @@
</div>
<div [fxShow]="timeseriesTableLatestKeySettingsForm.get('show').value" class="tb-widget-config-row space-between">
<div>{{ 'widgets.table.column-selection-to-display' | translate }}</div>
<mat-form-field style="width: 220px;" appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="columnSelectionToDisplay">
<mat-option [value]="'enabled'">
{{ 'widgets.table.column-selection-to-display-enabled' | translate }}

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

@ -18,25 +18,25 @@
<ng-container [formGroup]="timeseriesTableWidgetSettingsForm">
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.table-header</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableStickyHeader">
<mat-slide-toggle class="mat-slide" formControlName="enableStickyHeader">
{{ 'widgets.table.enable-sticky-header' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableSearch">
<mat-slide-toggle class="mat-slide" formControlName="enableSearch">
{{ 'widgets.table.enable-search' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableSelectColumnDisplay">
<mat-slide-toggle class="mat-slide" formControlName="enableSelectColumnDisplay">
{{ 'widgets.table.enable-select-column-display' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.columns</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="showTimestamp">
<mat-slide-toggle class="mat-slide" formControlName="showTimestamp">
{{ 'widgets.table.display-timestamp' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide no-margin" formControlName="showMilliseconds">
<mat-slide-toggle class="mat-slide" formControlName="showMilliseconds">
{{ 'widgets.table.display-milliseconds' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide no-margin" formControlName="enableStickyAction">
<mat-slide-toggle class="mat-slide" formControlName="enableStickyAction">
{{ 'widgets.table.enable-sticky-action' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex subscriptSizing="dynamic">
@ -53,25 +53,25 @@
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.pagination</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="displayPagination">
<mat-slide-toggle class="mat-slide" formControlName="displayPagination">
{{ 'widgets.table.display-pagination' | translate }}
</mat-slide-toggle>
<div class="tb-widget-config-row space-between">
<div translate>widgets.table.default-page-size</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="defaultPageSize" type="number" min="1" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.table.table-tabs</div>
<mat-slide-toggle class="mat-slide no-margin" formControlName="useEntityLabel">
<mat-slide-toggle class="mat-slide" formControlName="useEntityLabel">
{{ 'widgets.table.use-entity-label-tab-name' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-panel tb-slide-toggle">
<div class="tb-widget-config-panel-title" style="padding-bottom: 16px;" translate>widgets.table.rows</div>
<mat-slide-toggle class="mat-slide no-margin" style="padding-left: 16px;" formControlName="hideEmptyLines">
<mat-slide-toggle class="mat-slide" style="padding-left: 16px;" formControlName="hideEmptyLines">
{{ 'widgets.table.hide-empty-lines' | translate }}
</mat-slide-toggle>
<mat-expansion-panel class="tb-settings" [expanded]="timeseriesTableWidgetSettingsForm.get('useRowStyleFunction').value">

257
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html

@ -15,81 +15,85 @@
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="flotKeySettingsFormGroup" fxLayout="column">
<fieldset class="fields-group" fxLayout="column">
<legend class="group-title" translate>widgets.chart.common-settings</legend>
<mat-checkbox formControlName="hideDataByDefault">
<ng-container [formGroup]="flotKeySettingsFormGroup">
<div class="tb-widget-config-panel">
<mat-slide-toggle class="mat-slide" formControlName="hideDataByDefault">
{{ 'widgets.chart.data-is-hidden-by-default' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="disableDataHiding">
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="disableDataHiding">
{{ 'widgets.chart.disable-data-hiding' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="removeFromLegend">
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="removeFromLegend">
{{ 'widgets.chart.remove-from-legend' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="excludeFromStacking">
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="excludeFromStacking">
{{ 'widgets.chart.exclude-from-stacking' | translate }}
</mat-checkbox>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.line-settings</legend>
</mat-slide-toggle>
</div>
<div class="tb-widget-config-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('showLines').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showLines" (click)="$event.stopPropagation()"
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="showLines" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-line' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxFlex fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-width</mat-label>
<input matInput type="number" min="0" formControlName="lineWidth">
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.line-width' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="lineWidth" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<mat-checkbox formControlName="fillLines">
{{ 'widgets.chart.fill-line' | translate }}
</mat-checkbox>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.fill-line-opacity</mat-label>
<input matInput type="number" min="0" max="1" step="0.1" formControlName="fillLinesOpacity">
</div>
<mat-slide-toggle class="mat-slide" formControlName="fillLines">
{{ 'widgets.chart.fill-line' | translate }}
</mat-slide-toggle>
<div [fxShow]="flotKeySettingsFormGroup.get('fillLines').value" class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.fill-line-opacity' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="fillLinesOpacity" type="number" min="0" max="1" step="0.1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</section>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.points-settings</legend>
</div>
<div class="tb-widget-config-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('showPoints').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showPoints" (click)="$event.stopPropagation()"
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="showPoints" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-points' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<section fxFlex fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.points-line-width</mat-label>
<input matInput type="number" min="0" formControlName="showPointsLineWidth">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.points-radius</mat-label>
<input matInput type="number" min="0" formControlName="showPointsRadius">
</mat-form-field>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.point-shape</mat-label>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.points-line-width' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="showPointsLineWidth" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.points-radius' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="showPointsRadius" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.point-shape' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="showPointShape">
<mat-option [value]="'circle'">
{{ 'widgets.chart.point-shape-circle' | translate }}
@ -111,19 +115,19 @@
</mat-option>
</mat-select>
</mat-form-field>
<tb-js-func [fxShow]="flotKeySettingsFormGroup.get('showPointShape').value === 'custom'"
formControlName="pointShapeFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['ctx', 'x', 'y', 'radius', 'shadow']"
functionTitle="{{ 'widgets.chart.point-shape-draw-function' | translate }}"
helpId="widget/lib/flot/point_shape_format_fn">
</tb-js-func>
</section>
</div>
<tb-js-func [fxShow]="flotKeySettingsFormGroup.get('showPointShape').value === 'custom'"
formControlName="pointShapeFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['ctx', 'x', 'y', 'radius', 'shadow']"
functionTitle="{{ 'widgets.chart.point-shape-draw-function' | translate }}"
helpId="widget/lib/flot/point_shape_format_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.tooltip-settings</legend>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.chart.tooltip-settings</div>
<tb-js-func
formControlName="tooltipValueFormatter"
[globalVariables]="functionScopeVariables"
@ -131,49 +135,57 @@
functionTitle="{{ 'widgets.chart.tooltip-value-format-function' | translate }}"
helpId="widget/lib/flot/tooltip_value_format_fn">
</tb-js-func>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.yaxis-settings</legend>
<mat-slide-toggle formControlName="showSeparateAxis" class="slide-block">
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.chart.vertical-axis</div>
<mat-slide-toggle class="mat-slide" formControlName="showSeparateAxis">
{{ 'widgets.chart.show-separate-axis' | translate }}
</mat-slide-toggle>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-title</mat-label>
<input matInput formControlName="axisTitle">
</mat-form-field>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.min-scale-value</mat-label>
<input matInput type="number" formControlName="axisMin">
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widgets.chart.axis-title</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="axisTitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.max-scale-value</mat-label>
<input matInput type="number" formControlName="axisMax">
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.min-scale-value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-position</mat-label>
<mat-select formControlName="axisPosition">
<mat-option [value]="'left'">
{{ 'widgets.chart.axis-position-left' | translate }}
</mat-option>
<mat-option [value]="'right'">
{{ 'widgets.chart.axis-position-right' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.yaxis-tick-labels-settings</legend>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.tick-step-size</mat-label>
<input matInput type="number" formControlName="axisTickSize">
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.max-scale-value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.axis-position' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="axisPosition">
<mat-option [value]="'left'">
{{ 'widgets.chart.axis-position-left' | translate }}
</mat-option>
<mat-option [value]="'right'">
{{ 'widgets.chart.axis-position-right' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-widget-config-panel stroked">
<div class="tb-widget-config-panel-title" translate>widgets.chart.ticks</div>
<div class="tb-widget-config-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisTickDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.number-of-decimals</mat-label>
<input matInput type="number" min="0" formControlName="axisTickDecimals">
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.tick-step-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisTickSize" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</section>
</div>
<tb-js-func
formControlName="axisTicksFormatter"
[globalVariables]="functionScopeVariables"
@ -181,36 +193,31 @@
functionTitle="{{ 'widgets.chart.ticks-formatter-function' | translate }}"
helpId="widget/lib/flot/ticks_formatter_fn">
</tb-js-func>
</fieldset>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.thresholds</legend>
<div fxLayout="column">
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="thresholdDrop($event)">
<div cdkDrag class="tb-draggable" *ngFor="let thresholdControl of thresholdsFormArray().controls; trackBy: trackByThreshold;
let $index = index; last as isLast;"
fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<tb-flot-threshold [formControl]="thresholdControl"
[expanded]="thresholdControl.new"
[aliasController]="aliasController"
(removeThreshold)="removeThreshold($index)">
</tb-flot-threshold>
</div>
</div>
<div *ngIf="!thresholdsFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">widgets.chart.no-thresholds</span>
</div>
<div style="padding-top: 16px;">
<button mat-raised-button color="primary"
type="button"
(click)="addThreshold()">
<span translate>widgets.chart.add-threshold</span>
</button>
</div>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" fxLayout="row" fxLayoutAlign="space-between center">
<div translate>widgets.chart.thresholds</div>
<button mat-stroked-button
color="primary"
type="button" (click)="addThreshold()">
<span translate>widgets.chart.add-threshold</span>
</button>
</div>
<div *ngIf="thresholdsFormArray().length" class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="thresholdDrop($event)" fxLayout="column" fxLayoutGap="12px">
<div cdkDrag class="tb-draggable" *ngFor="let thresholdControl of thresholdsFormArray().controls; trackBy: trackByThreshold;
let $index = index;">
<tb-flot-threshold [formControl]="thresholdControl"
[expanded]="thresholdControl.new"
[aliasController]="aliasController"
(removeThreshold)="removeThreshold($index)">
</tb-flot-threshold>
</div>
</div>
</fieldset>
</div>
</ng-container>
<section class="tb-widget-settings" [formGroup]="flotKeySettingsFormGroup" fxLayout="column">
<fieldset class="fields-group fields-group-slider" formGroupName="comparisonSettings" >
<legend class="group-title" translate>widgets.chart.comparison-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').value">

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts

@ -225,6 +225,7 @@ export class FlotKeySettingsComponent extends PageComponent implements OnInit, C
this.flotKeySettingsFormGroup.disable({emitEvent: false});
} else {
this.flotKeySettingsFormGroup.enable({emitEvent: false});
this.updateValidators(false);
}
}

74
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html

@ -15,44 +15,38 @@
limitations under the License.
-->
<mat-expansion-panel class="flot-threshold" fxFlex [formGroup]="thresholdFormGroup" [(expanded)]="expanded">
<mat-expansion-panel-header>
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-panel-title>
<div fxLayout="row" fxFlex fxLayoutAlign="start center">
<div>{{ thresholdText() }}</div>
<div class="tb-color-preview" style="margin-left: 6px;">
<div class="tb-color-result" [ngStyle]="{background: thresholdFormGroup.get('color').value}"></div>
</div>
</div>
</mat-panel-title>
<span fxFlex></span>
<button *ngIf="!disabled" mat-icon-button style="min-width: 40px;"
type="button"
(click)="removeThreshold.emit()"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="0.5em">
<mat-divider></mat-divider>
<section class="tb-widget-settings" fxLayout="column">
<tb-value-source [aliasController]="aliasController" formControlName="valueSource"></tb-value-source>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-width</mat-label>
<input type="number" min="0" matInput formControlName="lineWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.chart.color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<div class="tb-flot-threshold">
<mat-expansion-panel class="tb-settings" fxFlex [formGroup]="thresholdFormGroup" [(expanded)]="expanded">
<mat-expansion-panel-header class="fill-width">
<div class="tb-threshold-header">
<div class="tb-threshold-text">{{ thresholdText() }}</div>
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="color">
</tb-color-input>
<mat-divider vertical></mat-divider>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-value-source [aliasController]="aliasController" formControlName="valueSource"></tb-value-source>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-width</mat-label>
<input type="number" min="0" matInput formControlName="lineWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.chart.color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
</div>
</ng-template>
</mat-expansion-panel>
</ng-template>
</mat-expansion-panel>
<button *ngIf="!disabled" mat-icon-button
type="button"
(click)="removeThreshold.emit()"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>

62
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss

@ -13,28 +13,58 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
display: block;
.tb-flot-threshold {
display: flex;
flex-direction: row;
align-items: start;
gap: 4px;
.mat-expansion-panel {
box-shadow: none;
&.flot-threshold {
border: 1px groove rgba(0, 0, 0, .25);
.mat-expansion-panel-header {
padding: 0 24px 0 8px;
&.mat-expanded {
height: 48px;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.12);
.mat-expansion-panel-header {
height: 56px;
border-radius: 0;
display: flex;
flex-direction: row;
align-items: stretch;
.tb-threshold-header {
flex: 1;
display: flex;
flex-direction: row;
gap: 16px;
align-items: center;
padding-left: 16px;
.mat-divider-vertical {
height: 100%;
}
}
.tb-threshold-text {
flex: 1;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 16px;
letter-spacing: 0.15px;
}
.mat-expansion-indicator {
margin-right: 22px;
margin-left: 22px;
margin-top: 12px;
}
}
}
}
:host ::ng-deep {
.mat-expansion-panel {
&.flot-threshold {
.mat-expansion-panel-body {
padding: 0 8px 8px;
.mat-expansion-panel-body {
padding: 0 8px 8px;
}
&.mat-expanded {
.mat-expansion-panel-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
}
}
.mdc-icon-button {
margin-top: 4px;
color: rgba(0, 0, 0, 0.54);
}
}

15
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts

@ -15,8 +15,14 @@
///
import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component';
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
Validators
} from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -28,14 +34,15 @@ import { TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.mode
@Component({
selector: 'tb-flot-threshold',
templateUrl: './flot-threshold.component.html',
styleUrls: ['./flot-threshold.component.scss', './../widget-settings.scss'],
styleUrls: ['./flot-threshold.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FlotThresholdComponent),
multi: true
}
]
],
encapsulation: ViewEncapsulation.None
})
export class FlotThresholdComponent extends PageComponent implements OnInit, ControlValueAccessor {

496
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html

@ -15,35 +15,33 @@
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="flotSettingsFormGroup" fxLayout="column">
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.common-settings</legend>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px" style="margin-bottom: 16px;">
<mat-checkbox fxFlex formControlName="stack">
{{ 'widgets.chart.enable-stacking-mode' | translate }}
</mat-checkbox>
<mat-checkbox fxFlex formControlName="enableSelection">
{{ 'widgets.chart.enable-selection-mode' | translate }}
</mat-checkbox>
</section>
<section *ngIf="chartType === 'graph'" fxLayout="column" fxLayout.gt-xs="row"
fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.line-shadow-size</mat-label>
<input matInput type="number" min="0" formControlName="shadowSize">
<ng-container [formGroup]="flotSettingsFormGroup">
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.chart.common-settings</div>
<mat-slide-toggle class="mat-slide" formControlName="stack">
{{ 'widgets.chart.enable-stacking-mode' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="enableSelection">
{{ 'widgets.chart.enable-selection-mode' | translate }}
</mat-slide-toggle>
<mat-slide-toggle *ngIf="chartType === 'graph'" class="mat-slide" formControlName="smoothLines">
{{ 'widgets.chart.display-smooth-lines' | translate }}
</mat-slide-toggle>
<div *ngIf="chartType === 'graph'" class="tb-widget-config-row space-between">
<div translate>widgets.chart.line-shadow-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="shadowSize" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-checkbox fxFlex formControlName="smoothLines">
{{ 'widgets.chart.display-smooth-lines' | translate }}
</mat-checkbox>
</section>
<section *ngIf="chartType === 'bar'" fxLayout="column" fxLayout.gt-xs="row"
fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.default-bar-width</mat-label>
<input matInput type="number" min="0" formControlName="defaultBarWidth">
</div>
<div *ngIf="chartType === 'bar'" class="tb-widget-config-row space-between">
<div translate>widgets.chart.default-bar-width</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="defaultBarWidth" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.bar-alignment</mat-label>
</div>
<div *ngIf="chartType === 'bar'" class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.bar-alignment' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="barAlignment">
<mat-option [value]="'left'">
{{ 'widgets.chart.bar-alignment-left' | translate }}
@ -56,211 +54,255 @@
</mat-option>
</mat-select>
</mat-form-field>
</section>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.default-font-size</mat-label>
<input matInput type="number" min="0" formControlName="fontSize">
</div>
<div *ngIf="chartType === 'graph' || chartType === 'bar'" class="tb-widget-config-row space-between">
<div translate>widgets.chart.thresholds-line-width</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="thresholdsLineWidth" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input fxFlex
formControlName="fontColor"
icon="format_color_fill"
label="{{ 'widgets.chart.default-font-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<mat-form-field *ngIf="chartType === 'graph' || chartType === 'bar'" fxFlex class="mat-block">
<mat-label translate>widgets.chart.thresholds-line-width</mat-label>
<input matInput type="number" min="0" formControlName="thresholdsLineWidth">
</mat-form-field>
</fieldset>
<fieldset *ngIf="chartType === 'graph' || chartType === 'bar'" class="fields-group fields-group-slider">
<legend class="group-title" translate>widget-config.legend</legend>
</div>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widgets.chart.default-font' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="fontSize" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="fontColor">
</tb-color-input>
</div>
</div>
</div>
<div *ngIf="chartType === 'graph' || chartType === 'bar'" class="tb-widget-config-panel tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widget-config.legend</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row" style="min-height: 48px;">
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center" style="height: 100%;">
{{ 'widget-config.display-legend' | translate }}
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxFlex="40" style="white-space: nowrap;" fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-legend-config formControlName="legendConfig"></tb-legend-config>
<tb-legend-config formControlName="legendConfig">
</tb-legend-config>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.tooltip-settings</legend>
</div>
<div class="tb-widget-config-panel">
<div class="tb-widget-config-panel-title" translate>widgets.chart.axis</div>
<div class="tb-widget-config-panel stroked" formGroupName="yaxis">
<div class="tb-widget-config-panel-title" translate>widgets.chart.vertical-axis</div>
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widgets.chart.axis-title</div>
<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">
<div translate>widgets.chart.min-scale-value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="min" type="number" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.max-scale-value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="max" type="number" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-panel stroked tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widgets.chart.ticks</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('yaxis.showLabels').value">
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="showLabels" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.ticks' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widget-config.color' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="color">
</tb-color-input>
</div>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tickDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.tick-step-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tickSize" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<tb-js-func
formControlName="ticksFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value']"
functionTitle="{{ 'widgets.chart.ticks-formatter-function' | translate }}"
helpId="widget/lib/flot/ticks_formatter_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</div>
</div>
<div class="tb-widget-config-panel stroked" formGroupName="xaxis">
<div class="tb-widget-config-panel-title" translate>widgets.chart.horizontal-axis</div>
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widgets.chart.axis-title</div>
<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-panel stroked tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widgets.chart.ticks</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('xaxis.showLabels').value">
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="showLabels" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.ticks' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widget-config.color' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="color">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
</div>
</div>
<div class="tb-widget-config-panel" formGroupName="grid">
<div class="tb-widget-config-panel-title" translate>widgets.chart.chart-background</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="verticalLines">
{{ 'widgets.chart.vertical-grid-lines' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="horizontalLines">
{{ 'widgets.chart.horizontal-grid-lines' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widgets.chart.grid-lines-color' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="tickColor">
</tb-color-input>
</div>
</div>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widgets.chart.border' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="outlineWidth" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="color">
</tb-color-input>
</div>
</div>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widgets.chart.background-color' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<mat-divider vertical></mat-divider>
<tb-color-input asBoxInput
formControlName="backgroundColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-widget-config-panel tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widgets.chart.tooltip</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showTooltip" (click)="$event.stopPropagation()"
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-tooltip' | translate }}
{{ 'widgets.chart.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-slide-toggle formControlName="tooltipIndividual" class="slide-block">
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipIndividual">
{{ 'widgets.chart.hover-individual-points' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="tooltipCumulative" class="slide-block">
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipCumulative">
{{ 'widgets.chart.show-cumulative-values' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="hideZeros" class="slide-block">
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="hideZeros">
{{ 'widgets.chart.hide-zero-false-values' | translate }}
</mat-slide-toggle>
<tb-js-func
formControlName="tooltipValueFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'latestData']"
functionTitle="{{ 'widgets.chart.tooltip-value-format-function' | translate }}"
helpId="widget/lib/flot/tooltip_value_format_fn">
</tb-js-func>
</section>
</div>
<tb-js-func
formControlName="tooltipValueFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value', 'latestData']"
functionTitle="{{ 'widgets.chart.tooltip-value-format-function' | translate }}"
helpId="widget/lib/flot/tooltip_value_format_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group" formGroupName="grid">
<legend class="group-title" translate>widgets.chart.grid-settings</legend>
<mat-checkbox formControlName="verticalLines">
{{ 'widgets.chart.show-vertical-lines' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="horizontalLines">
{{ 'widgets.chart.show-horizontal-lines' | translate }}
</mat-checkbox>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.grid-outline-border-width</mat-label>
<input matInput type="number" min="0" formControlName="outlineWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.chart.primary-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<tb-color-input fxFlex
formControlName="backgroundColor"
icon="format_color_fill"
label="{{ 'widgets.chart.background-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<tb-color-input fxFlex
formControlName="tickColor"
icon="format_color_fill"
label="{{ 'widgets.chart.ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</fieldset>
<fieldset class="fields-group" formGroupName="xaxis">
<legend class="group-title" translate>widgets.chart.xaxis-settings</legend>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-title</mat-label>
<input matInput formControlName="title">
</mat-form-field>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.xaxis-tick-labels-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('xaxis.showLabels').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showLabels" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-tick-labels' | 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-color-input fxFlex
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.chart.ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</ng-template>
</mat-expansion-panel>
</fieldset>
</fieldset>
<fieldset class="fields-group" formGroupName="yaxis">
<legend class="group-title" translate>widgets.chart.yaxis-settings</legend>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-title</mat-label>
<input matInput formControlName="title">
</mat-form-field>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.min-scale-value</mat-label>
<input matInput type="number" formControlName="min">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.max-scale-value</mat-label>
<input matInput type="number" formControlName="max">
</mat-form-field>
</section>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.yaxis-tick-labels-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('yaxis.showLabels').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showLabels" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-tick-labels' | 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-color-input fxFlex
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.chart.ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.tick-step-size</mat-label>
<input matInput type="number" formControlName="tickSize">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.number-of-decimals</mat-label>
<input matInput type="number" min="0" formControlName="tickDecimals">
</mat-form-field>
</section>
<tb-js-func
formControlName="ticksFormatter"
[globalVariables]="functionScopeVariables"
[functionArgs]="['value']"
functionTitle="{{ 'widgets.chart.ticks-formatter-function' | translate }}"
helpId="widget/lib/flot/ticks_formatter_fn">
</tb-js-func>
</ng-template>
</mat-expansion-panel>
</fieldset>
</fieldset>
<fieldset *ngIf="chartType === 'graph' || chartType === 'bar'" class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.comparison-settings</legend>
</div>
<div *ngIf="chartType === 'graph' || chartType === 'bar'" class="tb-widget-config-panel tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widgets.chart.comparison-settings</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('comparisonEnabled').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="comparisonEnabled" (click)="$event.stopPropagation()"
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle class="mat-slide" formControlName="comparisonEnabled" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.enable-comparison' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.time-for-comparison</mat-label>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.time-for-comparison' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="timeForComparison">
<mat-option [value]="'previousInterval'">
{{ 'widgets.chart.time-for-comparison-previous-interval' | translate }}
@ -282,18 +324,29 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [fxShow]="flotSettingsFormGroup.get('timeForComparison').value === 'customInterval'" fxFlex class="mat-block">
<mat-label translate>widgets.chart.custom-interval-value</mat-label>
<input matInput type="number" min="0" formControlName="comparisonCustomIntervalValue">
</div>
<div [fxShow]="flotSettingsFormGroup.get('timeForComparison').value === 'customInterval'" class="tb-widget-config-row space-between">
<div translate>widgets.chart.custom-interval-value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="comparisonCustomIntervalValue" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<fieldset class="fields-group" formGroupName="xaxisSecond">
<legend class="group-title" translate>widgets.chart.comparison-x-axis-settings</legend>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-title</mat-label>
<input matInput formControlName="title">
</div>
<div class="tb-widget-config-panel stroked" formGroupName="xaxisSecond">
<div class="tb-widget-config-panel-title" translate>widgets.chart.comparison-x-axis-settings</div>
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widgets.chart.axis-title</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.axis-position</mat-label>
</div>
<div class="tb-widget-config-row">
<mat-slide-toggle class="mat-slide" formControlName="showLabels">
{{ 'widgets.chart.show-tick-labels' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widgets.chart.axis-position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="axisPosition">
<mat-option [value]="'top'">
{{ 'widgets.chart.axis-position-top' | translate }}
@ -303,31 +356,28 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-slide-toggle formControlName="showLabels" class="slide-block">
{{ 'widgets.chart.show-tick-labels' | translate }}
</mat-slide-toggle>
</fieldset>
</section>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset *ngIf="chartType === 'graph' || chartType === 'bar'" class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.chart.custom-legend-settings</legend>
</div>
<div *ngIf="chartType === 'graph' || chartType === 'bar'" class="tb-widget-config-panel tb-slide-toggle">
<div class="tb-widget-config-panel-title" translate>widgets.chart.custom-legend-settings</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotSettingsFormGroup.get('customLegendEnabled').value">
<mat-expansion-panel-header fxLayout="row" style="height: max-content; min-height: 48px;">
<mat-expansion-panel-header fxLayout="row wrap" class="fill-width">
<mat-panel-title fxFlex="60">
<mat-slide-toggle formControlName="customLegendEnabled" (click)="$event.stopPropagation()"
fxLayoutAlign="center" style="height: 100%;">
<mat-slide-toggle class="mat-slide" formControlName="customLegendEnabled" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.enable-custom-legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxFlex="40" style="white-space: nowrap;" fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.chart.label-keys-list</legend>
<div class="tb-widget-config-panel stroked">
<div class="tb-widget-config-panel-title" translate>widgets.chart.label-keys-list</div>
<div fxLayout="column">
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="labelDataKeyDrop($event)">
@ -353,8 +403,8 @@
</button>
</div>
</div>
</fieldset>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>
</div>
</ng-container>

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

@ -284,6 +284,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit
this.flotSettingsFormGroup.disable({emitEvent: false});
} else {
this.flotSettingsFormGroup.enable({emitEvent: false});
this.updateValidators(false);
}
}
@ -379,9 +380,11 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit
} else {
this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent});
}
this.flotSettingsFormGroup.get('xaxisSecond').enable({emitEvent: false});
} else {
this.flotSettingsFormGroup.get('timeForComparison').disable({emitEvent: false});
this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent});
this.flotSettingsFormGroup.get('xaxisSecond').disable({emitEvent: false});
}
if (customLegendEnabled) {
this.flotSettingsFormGroup.get('dataKeysListForLabels').enable({emitEvent});
@ -392,6 +395,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit
this.flotSettingsFormGroup.get('legendConfig').updateValueAndValidity({emitEvent: false});
this.flotSettingsFormGroup.get('timeForComparison').updateValueAndValidity({emitEvent: false});
this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').updateValueAndValidity({emitEvent: false});
this.flotSettingsFormGroup.get('xaxisSecond').updateValueAndValidity({emitEvent: false});
this.flotSettingsFormGroup.get('dataKeysListForLabels').updateValueAndValidity({emitEvent: false});
}
}

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts

@ -47,7 +47,7 @@ export function labelDataKeyValidator(control: AbstractControl): ValidationError
@Component({
selector: 'tb-label-data-key',
templateUrl: './label-data-key.component.html',
styleUrls: ['./label-data-key.component.scss', './../widget-settings.scss'],
styleUrls: ['./label-data-key.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,

56
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html

@ -15,20 +15,21 @@
limitations under the License.
-->
<form [formGroup]="legendConfigForm">
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label translate>legend.direction</mat-label>
<mat-select matInput formControlName="direction">
<ng-container [formGroup]="legendConfigForm">
<div class="tb-widget-config-row space-between">
<div>{{ 'legend.direction' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="direction">
<mat-option *ngFor="let direction of legendDirections" [value]="direction">
{{ legendDirectionTranslations.get(legendDirection[direction]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>legend.position</mat-label>
<mat-select matInput formControlName="position">
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="position">
<mat-option *ngFor="let pos of legendPositions" [value]="pos"
[disabled]="legendConfigForm.get('direction').value === legendDirection.row &&
(pos === legendPosition.left || pos === legendPosition.right)">
@ -37,28 +38,17 @@
</mat-select>
</mat-form-field>
</div>
<div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<mat-checkbox formControlName="showMin" fxFlex>
{{ 'legend.show-min' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="showMax" fxFlex>
{{ 'legend.show-max' | translate }}
</mat-checkbox>
</div>
<div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<mat-checkbox formControlName="showAvg" fxFlex>
{{ 'legend.show-avg' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="showTotal" fxFlex>
{{ 'legend.show-total' | translate }}
</mat-checkbox>
</div>
<div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<mat-checkbox formControlName="showLatest" fxFlex>
{{ 'legend.show-latest' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="sortDataKeys" fxFlex>
{{ 'legend.sort-legend' | translate }}
</mat-checkbox>
<div class="tb-widget-config-row space-between">
<div translate>legend.show-values</div>
<mat-chip-listbox multiple formControlName="showValues">
<mat-chip-option value="min">{{ 'legend.min-option' | translate }}</mat-chip-option>
<mat-chip-option value="max">{{ 'legend.max-option' | translate }}</mat-chip-option>
<mat-chip-option value="average">{{ 'legend.average-option' | translate }}</mat-chip-option>
<mat-chip-option value="total">{{ 'legend.total-option' | translate }}</mat-chip-option>
<mat-chip-option value="latest">{{ 'legend.latest-option' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
</form>
<mat-slide-toggle class="mat-slide" formControlName="sortDataKeys">
{{ 'legend.sort-legend' | translate }}
</mat-slide-toggle>
</ng-container>

57
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts

@ -15,7 +15,7 @@
///
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { isDefined } from '@core/utils';
import {
LegendConfig,
@ -30,7 +30,7 @@ import { Subscription } from 'rxjs';
@Component({
selector: 'tb-legend-config',
templateUrl: './legend-config.component.html',
styleUrls: [],
styleUrls: ['./../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -62,12 +62,8 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc
this.legendConfigForm = this.fb.group({
direction: [null, []],
position: [null, []],
sortDataKeys: [null, []],
showMin: [null, []],
showMax: [null, []],
showAvg: [null, []],
showTotal: [null, []],
showLatest: [null, []]
showValues: [[], []],
sortDataKeys: [null, []]
});
this.legendSettingsFormDirectionChanges$ = this.legendConfigForm.get('direction').valueChanges
.subscribe((direction: LegendDirection) => {
@ -121,18 +117,49 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc
this.legendConfigForm.patchValue({
direction: legendConfig.direction,
position: legendConfig.position,
sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false,
showMin: isDefined(legendConfig.showMin) ? legendConfig.showMin : false,
showMax: isDefined(legendConfig.showMax) ? legendConfig.showMax : false,
showAvg: isDefined(legendConfig.showAvg) ? legendConfig.showAvg : false,
showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false,
showLatest: isDefined(legendConfig.showLatest) ? legendConfig.showLatest : false
showValues: this.getShowValues(legendConfig),
sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false
}, {emitEvent: false});
}
this.onDirectionChanged(legendConfig.direction);
}
private legendConfigUpdated() {
this.propagateChange(this.legendConfigForm.value);
const configValue = this.legendConfigForm.value;
const legendConfig: Partial<LegendConfig> = {
direction: configValue.direction,
position: configValue.position,
sortDataKeys: configValue.sortDataKeys
};
this.setShowValues(configValue.showValues, legendConfig);
this.propagateChange(legendConfig);
}
private getShowValues(legendConfig: LegendConfig): string[] {
const showValues: string[] = [];
if (isDefined(legendConfig.showMin) && legendConfig.showMin) {
showValues.push('min');
}
if (isDefined(legendConfig.showMax) && legendConfig.showMax) {
showValues.push('max');
}
if (isDefined(legendConfig.showAvg) && legendConfig.showAvg) {
showValues.push('average');
}
if (isDefined(legendConfig.showTotal) && legendConfig.showTotal) {
showValues.push('total');
}
if (isDefined(legendConfig.showLatest) && legendConfig.showLatest) {
showValues.push('latest');
}
return showValues;
}
private setShowValues(showValues: string[], legendConfig: Partial<LegendConfig>) {
legendConfig.showMin = showValues.includes('min');
legendConfig.showMax = showValues.includes('max');
legendConfig.showAvg = showValues.includes('average');
legendConfig.showTotal = showValues.includes('total');
legendConfig.showLatest = showValues.includes('latest');
}
}

32
ui-ngx/src/app/modules/home/components/widget/widget-config.component.html

@ -36,14 +36,16 @@
<mat-slide-toggle class="mat-slide" formControlName="showTitle">
{{ 'widget-config.display-title' | translate }}
</mat-slide-toggle>
<div fxLayout.xs="column" fxLayout="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex>
<mat-label translate>widget-config.title</mat-label>
<input matInput formControlName="title">
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widget-config.title</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widget-config.title-tooltip</mat-label>
<input matInput formControlName="titleTooltip">
</div>
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widget-config.title-tooltip</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="titleTooltip" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between same-padding">
@ -55,7 +57,7 @@
[color]="widgetSettings.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<mat-form-field appearance="outline" subscriptSizing="dynamic" style="width: 60px;">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="iconSize">
</mat-form-field>
<mat-divider vertical></mat-divider>
@ -102,13 +104,13 @@
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widget-config.padding' | translate }}</div>
<mat-form-field appearance="outline" class="center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div>{{ 'widget-config.margin' | translate }}</div>
<mat-form-field appearance="outline" class="center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="margin" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
@ -166,13 +168,13 @@
<div class="tb-widget-config-panel">
<div class="tb-widget-config-row space-between">
<div translate>widget-config.order</div>
<mat-form-field appearance="outline" class="number center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="mobileOrder" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-widget-config-row space-between">
<div translate>widget-config.height</div>
<mat-form-field appearance="outline" class="number center" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="mobileHeight" type="number" min="1" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
@ -241,7 +243,7 @@
<div class="tb-widget-config-panel-title" translate>widget-config.limits</div>
<div class="tb-widget-config-row space-between">
<div translate>widget-config.data-page-size</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="pageSize" type="number" min="1" step="1">
</mat-form-field>
</div>
@ -258,12 +260,12 @@
</div>
<div *ngIf="displayUnitsConfig" class="tb-widget-config-row space-between">
<div translate>widget-config.decimals</div>
<mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="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 *ngIf="displayNoDataDisplayMessageConfig" class="tb-widget-config-row">
<div translate>widget-config.no-data-display-message</div>
<div class="fixed-title-width" translate>widget-config.no-data-display-message</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="noDataDisplayMessage" placeholder="{{ 'widget-config.set-message' | translate }}">
</mat-form-field>

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

@ -2782,8 +2782,14 @@
"left-side": "Left side layout"
},
"legend": {
"direction": "Legend direction",
"position": "Legend position",
"direction": "Direction",
"position": "Position",
"show-values": "Show values",
"min-option": "Min",
"max-option": "Max",
"average-option": "Average",
"total-option": "Total",
"latest-option": "Latest",
"sort-legend": "Sort datakeys in legend",
"show-max": "Show max value",
"show-min": "Show min value",
@ -4250,7 +4256,10 @@
"text": "Text",
"background": "Background",
"advanced-widget-style": "Advanced widget style",
"card-buttons": "Card buttons"
"card-buttons": "Card buttons",
"show-card-buttons": "Show card buttons",
"card-appearance": "Card appearance",
"color": "Color"
},
"widget-type": {
"import": "Import widget type",
@ -4273,10 +4282,12 @@
"bar-alignment-left": "Left",
"bar-alignment-right": "Right",
"bar-alignment-center": "Center",
"default-font": "Default font",
"default-font-size": "Default font size",
"default-font-color": "Default font color",
"thresholds-line-width": "Default line width for all thresholds",
"tooltip-settings": "Tooltip settings",
"tooltip": "Tooltip",
"show-tooltip": "Show tooltip",
"hover-individual-points": "Hover individual points",
"show-cumulative-values": "Show cumulative values in stacking mode",
@ -4351,7 +4362,7 @@
"axis-position-right": "Right",
"thresholds": "Thresholds",
"no-thresholds": "No thresholds configured",
"add-threshold": "Add new threshold",
"add-threshold": "Add threshold",
"show-values-for-comparison": "Show historical values for comparison",
"comparison-values-label": "Historical values label",
"threshold-settings": "Threshold settings",
@ -4372,7 +4383,23 @@
"border-color": "Border color",
"legend-settings": "Legend settings",
"display-legend": "Display legend",
"labels-font-color": "Labels font color"
"labels-font-color": "Labels font color",
"series": "Series",
"add-series": "Add series",
"series-settings": "Series settings",
"remove-series": "Remove series",
"no-series": "No series configured",
"no-series-error": "At least one series should be specified",
"chart-appearance": "Chart appearance",
"vertical-grid-lines": "Vertical grid lines",
"horizontal-grid-lines": "Horizontal grid lines",
"chart-background": "Chart background",
"grid-lines-color": "Grid lines color",
"border": "Border",
"axis": "Axis",
"vertical-axis": "Vertical axis",
"ticks": "Ticks",
"horizontal-axis": "Horizontal axis"
},
"dashboard-state": {
"dashboard-state-settings": "Dashboard state settings",
@ -5239,7 +5266,6 @@
"remove-column": "Remove column",
"add-column": "Add column",
"no-columns": "No columns configured",
"show-card-buttons": "Show card buttons",
"columns-to-display": "Columns to display",
"table-header": "Table header",
"header-buttons": "Header buttons",

41
ui-ngx/src/styles.scss

@ -1212,11 +1212,11 @@ mat-label {
&.tb-slide-toggle {
padding: 0;
gap: 0;
.tb-widget-config-panel-title {
> .tb-widget-config-panel-title {
padding-top: 16px;
padding-left: 16px;
}
.mat-expansion-panel {
> .mat-expansion-panel {
padding: 16px;
.mat-expansion-panel-header {
height: 32px;
@ -1232,7 +1232,7 @@ mat-label {
.mat-content {
overflow: visible;
}
.mat-expansion-panel-header {
> .mat-expansion-panel-header {
font-weight: 500;
font-size: 16px;
line-height: 24px;
@ -1255,12 +1255,15 @@ mat-label {
padding: 2px;
}
}
.mat-expansion-panel-header-description {
> .mat-expansion-panel-header-description {
align-items: center;
}
> .mat-expansion-panel-content {
> .mat-expansion-panel-body {
padding: 0;
display: flex;
flex-direction: column;
gap: 16px;
padding: 16px 0 0 !important;
}
}
.tb-json-object-panel, .tb-css-content-panel {
@ -1272,9 +1275,9 @@ mat-label {
}
}
.mat-slide {
margin: 8px 0;
&.no-margin {
margin: 0;
margin: 0;
&.margin {
margin: 8px 0;
}
.mdc-form-field>label {
font-weight: 400;
@ -1313,7 +1316,13 @@ mat-label {
height: 56px;
}
.mat-mdc-form-field {
width: 80px;
width: 106px;
&.medium-width {
width: 220px;
}
}
.fixed-title-width {
min-width: 200px;
}
}
@ -1341,9 +1350,9 @@ mat-label {
}
}
.mat-mdc-form-field-infix {
padding-top: 7px;
padding-bottom: 7px;
min-height: 38px;
padding-top: 8px;
padding-bottom: 8px;
min-height: 40px;
width: auto;
.mdc-text-field__input, .mat-mdc-select {
font-weight: 400;
@ -1373,6 +1382,14 @@ mat-label {
}
}
}
.mat-mdc-form-field-flex {
.mat-mdc-form-field-icon-suffix {
font-size: 14px;
line-height: 20px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.38);
}
}
}
}

Loading…
Cancel
Save