Browse Source

UI: Flot line chart data key settings

pull/8881/head
Igor Kulikov 3 years ago
parent
commit
48e781fe2a
  1. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html
  2. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html
  3. 44
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html
  4. 18
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html
  5. 10
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss
  6. 50
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html
  7. 14
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts
  8. 1
      ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html
  9. 4
      ui-ngx/src/app/modules/home/components/widget/widget-preview.component.ts
  10. 6
      ui-ngx/src/app/shared/components/color-input.component.html
  11. 3
      ui-ngx/src/app/shared/components/color-input.component.ts
  12. 24
      ui-ngx/src/app/shared/components/toggle-select.component.html
  13. 132
      ui-ngx/src/app/shared/components/toggle-select.component.ts
  14. 5
      ui-ngx/src/app/shared/shared.module.ts
  15. 3
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  16. 12
      ui-ngx/src/styles.scss

1
ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html

@ -57,6 +57,7 @@
<tb-widget-preview *ngIf="previewMode" class="tb-absolute-fill"
[aliasController]="aliasController"
[stateController]="stateController"
[dashboardTimewindow]="dashboard.configuration.timewindow"
[widget]="widget"
[widgetConfig]="widgetFormGroup.get('widgetConfig').value.config">
<div class="tb-preview-panel-content">

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

@ -58,6 +58,7 @@
<tb-widget-preview class="widget-preview-section"
[aliasController]="aliasController"
[stateController]="stateController"
[dashboardTimewindow]="dashboard.configuration.timewindow"
[widget]="widget"
[widgetConfig]="widgetFormGroup.get('widgetConfig').value.config">
</tb-widget-preview>

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

@ -216,35 +216,35 @@
</div>
</div>
</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">
<div class="tb-widget-config-panel tb-slide-toggle" formGroupName="comparisonSettings">
<div class="tb-widget-config-panel-title" translate>widgets.chart.comparison-settings</div>
<mat-expansion-panel class="tb-settings" [expanded]="flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').value"
[disabled]="!flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title fxFlex="60">
<mat-slide-toggle formControlName="showValuesForComparison" (click)="$event.stopPropagation()"
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showValuesForComparison" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.chart.show-values-for-comparison' | 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>
<section fxFlex fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.chart.comparison-values-label</mat-label>
<input matInput formControlName="comparisonValuesLabel">
<div class="tb-widget-config-row">
<div class="fixed-title-width" translate>widgets.chart.comparison-values-label</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="comparisonValuesLabel" placeholder="{{ 'widget-config.set' | translate }}">
</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>
<div class="tb-widget-config-row space-between same-padding">
<div>{{ 'widgets.chart.comparison-line-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>
</fieldset>
</section>
</div>
</ng-container>

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

@ -16,7 +16,7 @@
-->
<div class="tb-flot-threshold">
<mat-expansion-panel class="tb-settings" fxFlex [formGroup]="thresholdFormGroup" [(expanded)]="expanded">
<mat-expansion-panel class="tb-settings tb-flot-threshold-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>
@ -29,17 +29,13 @@
</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">
<div class="tb-widget-config-row space-between">
<div translate>widgets.chart.line-width</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>
<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>
<button *ngIf="!disabled" mat-icon-button

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

@ -19,7 +19,7 @@
flex-direction: row;
align-items: start;
gap: 4px;
.mat-expansion-panel {
.mat-expansion-panel.tb-settings.tb-flot-threshold-settings {
box-shadow: none;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.12);
@ -54,8 +54,10 @@
margin-top: 12px;
}
}
.mat-expansion-panel-body {
padding: 0 8px 8px;
> .mat-expansion-panel-content {
> .mat-expansion-panel-body {
padding: 16px !important;
}
}
&.mat-expanded {
.mat-expansion-panel-header {
@ -63,7 +65,7 @@
}
}
}
.mdc-icon-button {
> .mdc-icon-button {
margin-top: 4px;
color: rgba(0, 0, 0, 0.54);
}

50
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html

@ -15,27 +15,27 @@
limitations under the License.
-->
<section [formGroup]="valueSourceFormGroup" fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.value-source.value-source</mat-label>
<mat-select formControlName="valueSource">
<mat-option [value]="'predefinedValue'">
<ng-container [formGroup]="valueSourceFormGroup">
<div style="display: flex;">
<tb-toggle-select formControlName="valueSource" style="min-width: 300px;">
<tb-toggle-option [value]="'predefinedValue'">
{{ 'widgets.value-source.predefined-value' | translate }}
</mat-option>
<mat-option [value]="'entityAttribute'">
</tb-toggle-option>
<tb-toggle-option [value]="'entityAttribute'">
{{ 'widgets.value-source.entity-attribute' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [fxShow]="valueSourceFormGroup.get('valueSource').value === 'predefinedValue'" fxFlex class="mat-block">
<mat-label translate>widgets.value-source.value</mat-label>
<input matInput type="number" formControlName="value">
</mat-form-field>
<section [fxShow]="valueSourceFormGroup.get('valueSource').value === 'entityAttribute'"
fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutAlign="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label>{{ 'widgets.value-source.source-entity-alias' | translate }}</mat-label>
<input matInput type="text" placeholder="{{ 'entity.entity-alias' | translate }}"
</tb-toggle-option>
</tb-toggle-select>
</div>
<div [fxShow]="valueSourceFormGroup.get('valueSource').value === 'predefinedValue'" class="tb-widget-config-row space-between">
<div translate>widgets.value-source.value</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="value" type="number" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div [fxShow]="valueSourceFormGroup.get('valueSource').value === 'entityAttribute'" class="tb-widget-config-row space-between">
<div translate>widgets.value-source.source-entity-alias</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<input matInput type="text" placeholder="{{ 'widget-config.set' | translate }}"
#entityAliasInput
formControlName="entityAlias"
[matAutocomplete]="entityAliasAutocomplete">
@ -53,9 +53,11 @@
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label>{{ 'widgets.value-source.source-entity-attribute' | translate }}</mat-label>
<input matInput type="text" placeholder="{{ 'entity.key-name' | translate }}"
</div>
<div [fxShow]="valueSourceFormGroup.get('valueSource').value === 'entityAttribute'" class="tb-widget-config-row space-between">
<div translate>widgets.value-source.source-entity-attribute</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<input matInput type="text" placeholder="{{ 'widget-config.set' | translate }}"
#keyInput
formControlName="attribute"
[matAutocomplete]="keyAutocomplete">
@ -73,5 +75,5 @@
</mat-option>
</mat-autocomplete>
</mat-form-field>
</section>
</section>
</div>
</ng-container>

14
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts

@ -14,8 +14,8 @@
/// limitations under the License.
///
import { Component, ElementRef, forwardRef, HostBinding, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -39,7 +39,7 @@ export interface ValueSourceProperty {
@Component({
selector: 'tb-value-source',
templateUrl: './value-source.component.html',
styleUrls: [],
styleUrls: ['./../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -50,8 +50,6 @@ export interface ValueSourceProperty {
})
export class ValueSourceComponent extends PageComponent implements OnInit, ControlValueAccessor {
@HostBinding('style.display') display = 'block';
@ViewChild('entityAliasInput') entityAliasInput: ElementRef;
@ViewChild('keyInput') keyInput: ElementRef;
@ -212,15 +210,13 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr
private fetchEntityKeys(entityAliasId: string, dataKeyTypes: Array<DataKeyType>): Observable<Array<DataKey>> {
return this.aliasController.getAliasInfo(entityAliasId).pipe(
mergeMap((aliasInfo) => {
return this.entityService.getEntityKeysByEntityFilter(
mergeMap((aliasInfo) => this.entityService.getEntityKeysByEntityFilter(
aliasInfo.entityFilter,
dataKeyTypes, [],
{ignoreLoading: true, ignoreErrors: true}
).pipe(
catchError(() => of([]))
);
}),
)),
catchError(() => of([] as Array<DataKey>))
);
}

1
ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html

@ -18,6 +18,7 @@
<tb-dashboard class="tb-preview-dashboard"
[aliasController]="aliasController"
[stateController]="stateController"
[dashboardTimewindow]="dashboardTimewindow"
[widgets]="widgets"
[autofillHeight]="true"
[columns]="24"

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

@ -21,6 +21,7 @@ import { Widget, WidgetConfig } from '@shared/models/widget.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { deepClone } from '@core/utils';
import { Timewindow } from '@shared/models/time/time.models';
@Component({
selector: 'tb-widget-preview',
@ -35,6 +36,9 @@ export class WidgetPreviewComponent extends PageComponent implements OnInit, OnC
@Input()
stateController: IStateController;
@Input()
dashboardTimewindow: Timewindow;
@Input()
widget: Widget;

6
ui-ngx/src/app/shared/components/color-input.component.html

@ -20,10 +20,10 @@
<mat-icon *ngIf="icon">{{icon}}</mat-icon>
<span *ngIf="label">{{label}}</span>
</mat-label>
<div matPrefix class="tb-color-preview" (click)="!disabled && showColorPicker()">
<div matPrefix class="tb-color-preview" (click)="!disabled && showColorPicker($event)">
<div class="tb-color-result" [ngStyle]="{background: colorFormGroup.get('color').value}"></div>
</div>
<input matInput formControlName="color" (keydown)="$event.preventDefault();" (click)="openOnInput && showColorPicker()" [required]="required">
<input matInput formControlName="color" (keydown)="$event.preventDefault();" (click)="openOnInput && showColorPicker($event)" [required]="required">
<button *ngIf="colorClearButton && !disabled"
type="button"
matSuffix mat-icon-button aria-label="Clear"
@ -35,7 +35,7 @@
</mat-error>
</mat-form-field>
<ng-template #boxInput>
<div class="tb-color-preview no-margin box" [ngClass]="{'disabled': disabled}" (click)="!disabled && showColorPicker()">
<div class="tb-color-preview no-margin box" [ngClass]="{'disabled': disabled}" (click)="!disabled && showColorPicker($event)">
<div class="tb-color-result" [ngStyle]="!disabled ? {background: colorFormGroup.get('color').value} : {}"></div>
</div>
</ng-template>

3
ui-ngx/src/app/shared/components/color-input.component.ts

@ -153,7 +153,8 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro
}
}
showColorPicker() {
showColorPicker($event: MouseEvent) {
$event.stopPropagation();
this.dialogs.colorPicker(this.colorFormGroup.get('color').value).subscribe(
(color) => {
if (color) {

24
ui-ngx/src/app/shared/components/toggle-select.component.html

@ -0,0 +1,24 @@
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tb-toggle-header
ignoreMdLgSize="true"
useSelectOnMdLg="false"
[options]="options"
[value]="modelValue"
(valueChange)="updateModel($event)">
</tb-toggle-header>

132
ui-ngx/src/app/shared/components/toggle-select.component.ts

@ -0,0 +1,132 @@
///
/// 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 {
AfterContentInit,
ChangeDetectorRef,
Component,
ContentChildren,
Directive,
ElementRef,
forwardRef,
Input,
OnDestroy,
QueryList
} from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs';
import { startWith, takeUntil } from 'rxjs/operators';
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
@Directive(
{
// eslint-disable-next-line @angular-eslint/directive-selector
selector: 'tb-toggle-option',
}
)
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export class ToggleSelectOption {
@Input() value: any;
get viewValue(): string {
return (this._element?.nativeElement.textContent || '').trim();
}
constructor(
private _element: ElementRef<HTMLElement>
) {}
}
@Component({
selector: 'tb-toggle-select',
templateUrl: './toggle-select.component.html',
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ToggleSelectComponent),
multi: true
}
]
})
export class ToggleSelectComponent extends PageComponent implements AfterContentInit, OnDestroy, ControlValueAccessor {
@ContentChildren(ToggleSelectOption) toggleSelectOptions: QueryList<ToggleSelectOption>;
@Input()
disabled: boolean;
options: ToggleHeaderOption[] = [];
private _destroyed = new Subject<void>();
modelValue: any;
private propagateChange = null;
constructor(protected store: Store<AppState>,
private cd: ChangeDetectorRef) {
super(store);
}
ngAfterContentInit(): void {
this.toggleSelectOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
this.syncToggleHeaderOptions();
});
}
ngOnDestroy() {
this._destroyed.next();
this._destroyed.complete();
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(value: any): void {
this.modelValue = value;
}
private syncToggleHeaderOptions() {
this.options.length = 0;
if (this.toggleSelectOptions) {
this.toggleSelectOptions.forEach(selectOption => {
this.options.push(
{ name: selectOption.viewValue,
value: selectOption.value
}
);
});
}
}
updateModel(value: any) {
this.modelValue = value;
this.propagateChange(this.modelValue);
}
}

5
ui-ngx/src/app/shared/shared.module.ts

@ -193,6 +193,7 @@ import { ResourceAutocompleteComponent } from '@shared/components/resource/resou
import { ShortNumberPipe } from '@shared/pipe/short-number.pipe';
import { ToggleHeaderComponent } from '@shared/components/toggle-header.component';
import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component';
import { ToggleSelectComponent, ToggleSelectOption } from '@shared/components/toggle-select.component';
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
return markedOptionsService;
@ -364,6 +365,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
ColorPickerComponent,
ResourceAutocompleteComponent,
ToggleHeaderComponent,
ToggleSelectOption,
ToggleSelectComponent,
RuleChainSelectComponent
],
imports: [
@ -592,6 +595,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
ColorPickerComponent,
ResourceAutocompleteComponent,
ToggleHeaderComponent,
ToggleSelectOption,
ToggleSelectComponent,
RuleChainSelectComponent
]
})

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

@ -4365,6 +4365,7 @@
"add-threshold": "Add threshold",
"show-values-for-comparison": "Show historical values for comparison",
"comparison-values-label": "Historical values label",
"comparison-line-color": "Comparison line color",
"threshold-settings": "Threshold settings",
"use-as-threshold": "Use key value as threshold",
"threshold-line-width": "Threshold line width",
@ -5277,7 +5278,7 @@
"value-source": {
"value-source": "Value source",
"predefined-value": "Predefined value",
"entity-attribute": "Value taken from entity attribute",
"entity-attribute": "Entity attribute",
"value": "Value",
"source-entity-alias": "Source entity alias",
"source-entity-attribute": "Source entity attribute"

12
ui-ngx/src/styles.scss

@ -1360,6 +1360,18 @@ mat-label {
line-height: 20px;
}
}
.mat-mdc-form-field-icon-suffix {
button.mat-mdc-icon-button {
width: 40px;
height: 40px;
padding: 8px;
.mat-icon {
width: 20px;
height: 20px;
font-size: 20px;
}
}
}
}
}
&.center {

Loading…
Cancel
Save