Browse Source

Merge pull request #10050 from Dmitriymush/enhacements/liquid-level

Added dynamic volume inputs and other minor improvements for liquid level widget.
pull/10184/head
Igor Kulikov 3 years ago
committed by GitHub
parent
commit
3bea9472ab
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 50
      ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.html
  2. 6
      ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts
  3. 63
      ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts
  4. 31
      ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts
  5. 46
      ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.html
  6. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts
  7. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  8. 30
      ui-ngx/src/form.scss

50
ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.html

@ -34,7 +34,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widgets.liquid-level-card.title' | translate }} {{ 'widgets.liquid-level-card.title' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}"> <input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field> </mat-form-field>
@ -49,7 +49,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitleIcon"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitleIcon">
{{ 'widgets.liquid-level-card.icon' | translate }} {{ 'widgets.liquid-level-card.icon' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic"> <mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="iconSize" placeholder="{{ 'widget-config.set' | translate }}"> <input matInput type="number" min="0" formControlName="iconSize" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field> </mat-form-field>
@ -64,7 +64,7 @@
</div> </div>
</div> </div>
<div fxFlex fxLayout="column" class="tb-form-row space-between"> <div fxFlex fxLayout="column" class="tb-form-row space-between">
<div fxFlex fxLayout="row" style="width: 100%;" fxLayoutAlign="space-between center"> <div class="tb-flex row space-between align-center no-gap fill-width">
<div class="fixed-title-width" translate>widgets.liquid-level-card.shape</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.shape</div>
<tb-toggle-select formControlName="tankSelectionType"> <tb-toggle-select formControlName="tankSelectionType">
<tb-toggle-option *ngFor="let type of DataSourceTypes" [value]="type"> <tb-toggle-option *ngFor="let type of DataSourceTypes" [value]="type">
@ -96,7 +96,7 @@
formControlName="shapeAttributeName"> formControlName="shapeAttributeName">
</tb-string-autocomplete> </tb-string-autocomplete>
</div> </div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center" style="width: 100%;"> <div class="tb-flex row space-between align-center no-gap fill-width">
<div class="tb-hint" style="padding: 0;" translate>widgets.liquid-level-card.shape-by-attribute</div> <div class="tb-hint" style="padding: 0;" translate>widgets.liquid-level-card.shape-by-attribute</div>
<div class="see-example" <div class="see-example"
[tb-help-popup]="'widget/lib/indicator/shape_attribute_fn'" [tb-help-popup]="'widget/lib/indicator/shape_attribute_fn'"
@ -123,16 +123,16 @@
<div class="tb-form-panel-title" translate>widgets.liquid-level-card.units</div> <div class="tb-form-panel-title" translate>widgets.liquid-level-card.units</div>
<div class="tb-form-row space-between"> <div class="tb-form-row space-between">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.datasource-units</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.datasource-units</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center"> <div class="tb-flex row flex-end align-center no-gap">
<tb-unit-input required style="max-width: 25%;" class="flex" <tb-unit-input required style="max-width: 25%;" class="flex"
[tagFilter]="unitsType.capacity" [tagFilter]="unitsType.capacity"
formControlName="datasourceUnits"> formControlName="datasourceUnits">
</tb-unit-input> </tb-unit-input>
</div> </div>
</div> </div>
<div class="tb-form-row space-between" *ngIf="levelCardWidgetConfigForm.get('layout').value === LevelCardLayout.absolute"> <div class="tb-form-row space-between column-xs" *ngIf="levelCardWidgetConfigForm.get('layout').value === LevelCardLayout.absolute">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.widget-units</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.widget-units</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="widgetUnitsSource" placeholder="{{ 'widget-config.set' | translate }}"> <mat-select formControlName="widgetUnitsSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type"> <mat-option *ngFor="let type of DataSourceTypes" [value]="type">
@ -154,9 +154,9 @@
</ng-template> </ng-template>
</div> </div>
</div> </div>
<div class="tb-form-row" [fxShow]="volumeInput"> <div class="tb-form-row column-xs" [fxShow]="volumeInput">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="volumeSource" placeholder="{{ 'widget-config.set' | translate }}"> <mat-select formControlName="volumeSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type"> <mat-option *ngFor="let type of DataSourceTypes" [value]="type">
@ -184,10 +184,30 @@
formControlName="volumeAttributeName"> formControlName="volumeAttributeName">
</tb-string-autocomplete> </tb-string-autocomplete>
</ng-template> </ng-template>
<tb-unit-input [tagFilter]="unitsType.capacity" </div>
required style="max-width: 25%" class="flex" </div>
<div class="tb-form-row space-between column-xs" [fxShow]="volumeInput">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume-units</div>
<div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="volumeUnitsSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type">
{{ DataSourceTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-unit-input *ngIf="levelCardWidgetConfigForm.get('volumeUnitsSource').value === DataSourceType.static; else selectVolumeUnitsAttributes"
class="flex" required
[tagFilter]="unitsType.capacity"
formControlName="volumeUnits"> formControlName="volumeUnits">
</tb-unit-input> </tb-unit-input>
<ng-template #selectVolumeUnitsAttributes>
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
required style="flex: 1"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
formControlName="volumeUnitsAttributeName">
</tb-string-autocomplete>
</ng-template>
</div> </div>
</div> </div>
</div> </div>
@ -206,7 +226,7 @@
<div class="tb-form-row space-between" <div class="tb-form-row space-between"
*ngIf="levelCardWidgetConfigForm.get('layout').value !== LevelCardLayout.simple"> *ngIf="levelCardWidgetConfigForm.get('layout').value !== LevelCardLayout.simple">
<div class="fixed-title-width" translate>widgets.liquid-level-card.value</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.value</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<mat-form-field style="max-width: 40%;" appearance="outline" class="flex number" subscriptSizing="dynamic"> <mat-form-field style="max-width: 40%;" appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" <input matInput formControlName="decimals" type="number"
min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}"> min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
@ -221,7 +241,7 @@
</div> </div>
<div class="tb-form-row" *ngIf="levelCardWidgetConfigForm.get('layout').value === LevelCardLayout.absolute"> <div class="tb-form-row" *ngIf="levelCardWidgetConfigForm.get('layout').value === LevelCardLayout.absolute">
<div class="fixed-title-width" translate>widgets.liquid-level-card.total-volume</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.total-volume</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<tb-font-settings formControlName="volumeFont" <tb-font-settings formControlName="volumeFont"
[previewText]="totalVolumeValuePreviewFn"> [previewText]="totalVolumeValuePreviewFn">
</tb-font-settings> </tb-font-settings>
@ -247,7 +267,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipLevel"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipLevel">
{{ 'widgets.liquid-level-card.level' | translate }} {{ 'widgets.liquid-level-card.level' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<tb-unit-input required class="flex" <tb-unit-input required class="flex"
[tagFilter]="unitsType.capacity" [tagFilter]="unitsType.capacity"
formControlName="tooltipUnits"> formControlName="tooltipUnits">
@ -268,7 +288,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipDate"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipDate">
{{ 'widgets.value-card.date' | translate }} {{ 'widgets.value-card.date' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<tb-date-format-select fxFlex formControlName="tooltipDateFormat"></tb-date-format-select> <tb-date-format-select fxFlex formControlName="tooltipDateFormat"></tb-date-format-select>
<tb-font-settings formControlName="tooltipDateFont" <tb-font-settings formControlName="tooltipDateFont"
[previewText]="datePreviewFn"> [previewText]="datePreviewFn">

6
ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts

@ -194,7 +194,9 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
volumeSource: [settings.volumeSource, []], volumeSource: [settings.volumeSource, []],
volumeConstant: [settings.volumeConstant, [Validators.required, Validators.min(0.1)]], volumeConstant: [settings.volumeConstant, [Validators.required, Validators.min(0.1)]],
volumeAttributeName: [settings.volumeAttributeName, [Validators.required]], volumeAttributeName: [settings.volumeAttributeName, [Validators.required]],
volumeUnitsSource: [settings.volumeUnitsSource, []],
volumeUnits: [settings.volumeUnits, [Validators.required]], volumeUnits: [settings.volumeUnits, [Validators.required]],
volumeUnitsAttributeName: [settings.volumeUnitsAttributeName, [Validators.required]],
volumeFont: [settings.volumeFont, []], volumeFont: [settings.volumeFont, []],
volumeColor: [settings.volumeColor, []], volumeColor: [settings.volumeColor, []],
units: [settings.units, [Validators.required]], units: [settings.units, [Validators.required]],
@ -260,6 +262,8 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
this.widgetConfig.config.settings.volumeSource = config.volumeSource; this.widgetConfig.config.settings.volumeSource = config.volumeSource;
this.widgetConfig.config.settings.volumeConstant = config.volumeConstant; this.widgetConfig.config.settings.volumeConstant = config.volumeConstant;
this.widgetConfig.config.settings.volumeAttributeName = config.volumeAttributeName; this.widgetConfig.config.settings.volumeAttributeName = config.volumeAttributeName;
this.widgetConfig.config.settings.volumeUnitsSource = config.volumeUnitsSource;
this.widgetConfig.config.settings.volumeUnitsAttributeName = config.volumeUnitsAttributeName;
this.widgetConfig.config.settings.volumeUnits = config.volumeUnits; this.widgetConfig.config.settings.volumeUnits = config.volumeUnits;
this.widgetConfig.config.settings.volumeFont = config.volumeFont; this.widgetConfig.config.settings.volumeFont = config.volumeFont;
this.widgetConfig.config.settings.volumeColor = config.volumeColor; this.widgetConfig.config.settings.volumeColor = config.volumeColor;
@ -294,7 +298,7 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return [ return [
'showTooltip', 'showTooltipLevel', 'tankSelectionType', 'datasourceUnits', 'showTitleIcon', 'volumeSource', 'showTooltip', 'showTooltipLevel', 'tankSelectionType', 'datasourceUnits', 'showTitleIcon', 'volumeSource',
'showTooltipDate', 'layout', 'showTitle', 'widgetUnitsSource' 'showTooltipDate', 'layout', 'showTitle', 'widgetUnitsSource', 'volumeUnitsSource'
]; ];
} }

63
ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts

@ -106,6 +106,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
private volume: number; private volume: number;
private tooltipContent: string; private tooltipContent: string;
private widgetUnits: string; private widgetUnits: string;
private volumeUnits: string;
private capacityUnits = Object.values(CapacityUnits); private capacityUnits = Object.values(CapacityUnits);
@ -128,7 +129,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
this.getData().subscribe(data => { this.getData().subscribe(data => {
if (data) { if (data) {
const { svg, volume, units } = data; const { svg, volume, units, volumeUnits } = data;
if (svg && isNotEmptyStr(svg) && this.liquidLevelContent.nativeElement) { if (svg && isNotEmptyStr(svg) && this.liquidLevelContent.nativeElement) {
const jQueryContainerElement = $(this.liquidLevelContent.nativeElement); const jQueryContainerElement = $(this.liquidLevelContent.nativeElement);
jQueryContainerElement.html(svg); jQueryContainerElement.html(svg);
@ -145,6 +146,10 @@ export class LiquidLevelWidgetComponent implements OnInit {
this.volume = Number(volume); this.volume = Number(volume);
} }
if (volumeUnits) {
this.volumeUnits = volumeUnits;
}
if (units) { if (units) {
this.widgetUnits = units; this.widgetUnits = units;
} }
@ -164,7 +169,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat); this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat);
} }
private getData(): Observable<{ svg: string; volume: number; units: string }> { private getData(): Observable<{ svg: string; volume: number; units: string; volumeUnits: string}> {
if (this.ctx.datasources?.length) { if (this.ctx.datasources?.length) {
const entityId: EntityId = { const entityId: EntityId = {
entityType: this.ctx.datasources[0].entityType, entityType: this.ctx.datasources[0].entityType,
@ -308,7 +313,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
.pipe(map(attributes => { .pipe(map(attributes => {
const shape = extractValue<Shapes>(attributes, this.settings.shapeAttributeName); const shape = extractValue<Shapes>(attributes, this.settings.shapeAttributeName);
if (!shape || !svgMapping.has(shape)) { if (!shape || !svgMapping.has(shape)) {
this.createdErrorMgs(this.settings.shapeAttributeName, isUndefinedOrNull(shape) || isEmptyStr(shape)); this.createdErrorMsg(this.settings.shapeAttributeName, isUndefinedOrNull(shape) || isEmptyStr(shape));
return this.settings.selectedShape; return this.settings.selectedShape;
} }
return shape; return shape;
@ -318,12 +323,15 @@ export class LiquidLevelWidgetComponent implements OnInit {
return of(this.settings.selectedShape); return of(this.settings.selectedShape);
} }
private getTankersParams(entityId: EntityId): Observable<{ volume: number; units: string }> { private getTankersParams(entityId: EntityId): Observable<{ volume: number; units: string; volumeUnits: string }> {
const isVolumeStatic = this.settings.layout !== LevelCardLayout.absolute const isVolumeStatic = this.settings.layout !== LevelCardLayout.absolute
&& this.settings.datasourceUnits === CapacityUnits.percent && this.settings.datasourceUnits === CapacityUnits.percent
|| this.settings.volumeSource === LiquidWidgetDataSourceType.static; || this.settings.volumeSource === LiquidWidgetDataSourceType.static;
const isUnitStatic = this.settings.layout !== LevelCardLayout.absolute || const isUnitStatic = this.settings.layout !== LevelCardLayout.absolute ||
this.settings.widgetUnitsSource === LiquidWidgetDataSourceType.static; this.settings.widgetUnitsSource === LiquidWidgetDataSourceType.static;
const isVolumeUnitStatic = this.settings.layout !== LevelCardLayout.absolute
&& this.settings.datasourceUnits === CapacityUnits.percent
|| this.settings.volumeUnitsSource === LiquidWidgetDataSourceType.static;
const attributeKeys: string[] = []; const attributeKeys: string[] = [];
@ -335,20 +343,29 @@ export class LiquidLevelWidgetComponent implements OnInit {
attributeKeys.push(this.settings.widgetUnitsAttributeName); attributeKeys.push(this.settings.widgetUnitsAttributeName);
} }
if (!isVolumeUnitStatic) {
attributeKeys.push(this.settings.volumeUnitsAttributeName);
}
if (!attributeKeys.length || entityId.id === NULL_UUID) { if (!attributeKeys.length || entityId.id === NULL_UUID) {
return of({ return of({
volume: this.settings.volumeConstant, volume: this.settings.volumeConstant,
volumeUnits: this.settings.volumeUnits,
units: this.settings.units units: this.settings.units
}); });
} }
return this.ctx.attributeService.getEntityAttributes(entityId, null, attributeKeys).pipe( return this.ctx.attributeService.getEntityAttributes(entityId, null, attributeKeys).pipe(
map(attributes => { map(attributes => {
let volume = isVolumeStatic ? this.settings.volumeConstant : extractValue<number>(attributes, this.settings.volumeAttributeName); let volume = isVolumeStatic ? this.settings.volumeConstant :
let units = isUnitStatic ? this.settings.units : extractValue<string>(attributes, this.settings.widgetUnitsAttributeName); extractValue<number>(attributes, this.settings.volumeAttributeName);
let volumeUnits = isVolumeUnitStatic ? this.settings.volumeUnits :
extractValue<string>(attributes, this.settings.volumeUnitsAttributeName);
let units = isUnitStatic ? this.settings.units :
extractValue<string>(attributes, this.settings.widgetUnitsAttributeName);
if (!isVolumeStatic && (!volume || !isNumeric(volume) || volume < 0.1)) { if (!isVolumeStatic && (!volume || !isNumeric(volume) || volume < 0.1)) {
this.createdErrorMgs(this.settings.volumeAttributeName, isUndefinedOrNull(volume) || isEmptyStr(volume)); this.createdErrorMsg(this.settings.volumeAttributeName, isUndefinedOrNull(volume) || isEmptyStr(volume));
volume = this.settings.volumeConstant; volume = this.settings.volumeConstant;
} }
@ -358,20 +375,33 @@ export class LiquidLevelWidgetComponent implements OnInit {
units = this.capacityUnits.find(unit => unit.normalize() === normalizeUnits); units = this.capacityUnits.find(unit => unit.normalize() === normalizeUnits);
} }
if (isUndefinedOrNull(units) || !isNotEmptyStr(units)) { if (isUndefinedOrNull(units) || !isNotEmptyStr(units)) {
this.createdErrorMgs(this.settings.widgetUnitsAttributeName, isUndefinedOrNull(units) || isEmptyStr(units)); this.createdErrorMsg(this.settings.widgetUnitsAttributeName, isUndefinedOrNull(units) || isEmptyStr(units));
units = this.settings.units; units = this.settings.units;
} }
} }
if (!isVolumeUnitStatic) {
if (isNotEmptyStr(volumeUnits)) {
const normalizeUnits = volumeUnits.normalize().trim();
volumeUnits = this.capacityUnits.find(unit => unit.normalize() === normalizeUnits);
}
if (isUndefinedOrNull(volumeUnits) || !isNotEmptyStr(volumeUnits)) {
this.createdErrorMsg(this.settings.widgetUnitsAttributeName,
isUndefinedOrNull(volumeUnits) || isEmptyStr(volumeUnits));
volumeUnits = this.settings.volumeUnits;
}
}
return { return {
volume, volume,
volumeUnits,
units units
}; };
}) })
); );
} }
private createdErrorMgs(attributeName: string, isEmpty = false) { private createdErrorMsg(attributeName: string, isEmpty = false) {
if (isEmpty) { if (isEmpty) {
this.errorsMsg.push(this.translate.instant('widgets.liquid-level-card.attribute-key-not-set', {attributeName})); this.errorsMsg.push(this.translate.instant('widgets.liquid-level-card.attribute-key-not-set', {attributeName}));
} else { } else {
@ -474,9 +504,14 @@ export class LiquidLevelWidgetComponent implements OnInit {
} }
if (this.settings.layout === LevelCardLayout.absolute) { if (this.settings.layout === LevelCardLayout.absolute) {
const volumeInLiters: number = convertLiters(this.volume, this.settings.volumeUnits as CapacityUnits, ConversionType.to); let volume: number | string;
const volume = convertLiters(volumeInLiters, this.widgetUnits as CapacityUnits, ConversionType.from) if (this.widgetUnits !== CapacityUnits.percent) {
.toFixed(this.settings.decimals || 0); const volumeInLiters: number = convertLiters(this.volume, this.volumeUnits as CapacityUnits, ConversionType.to);
volume = convertLiters(volumeInLiters, this.widgetUnits as CapacityUnits, ConversionType.from)
.toFixed(this.settings.decimals || 0);
} else {
volume = this.volume.toFixed(this.settings.decimals || 0);
}
const volumeTextStyle = cssTextFromInlineStyle({...inlineTextStyle(this.settings.volumeFont), const volumeTextStyle = cssTextFromInlineStyle({...inlineTextStyle(this.settings.volumeFont),
color: this.settings.volumeColor}); color: this.settings.volumeColor});
@ -553,7 +588,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
private convertInputData(value: any): number { private convertInputData(value: any): number {
if (this.settings.datasourceUnits !== CapacityUnits.percent) { if (this.settings.datasourceUnits !== CapacityUnits.percent) {
return (convertLiters(Number(value), this.settings.datasourceUnits, ConversionType.to) / return (convertLiters(Number(value), this.settings.datasourceUnits, ConversionType.to) /
convertLiters(this.volume, this.settings.volumeUnits, ConversionType.to)) * 100; convertLiters(this.volume, this.volumeUnits as CapacityUnits, ConversionType.to)) * 100;
} }
return Number(value); return Number(value);
@ -561,7 +596,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
private convertOutputData(value: number): number { private convertOutputData(value: number): number {
if (this.widgetUnits !== CapacityUnits.percent) { if (this.widgetUnits !== CapacityUnits.percent) {
return convertLiters(this.volume * (value / 100), this.settings.volumeUnits, ConversionType.to); return convertLiters(this.volume * (value / 100), this.volumeUnits as CapacityUnits, ConversionType.to);
} }
return value; return value;

31
ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts

@ -56,6 +56,8 @@ export interface LevelCardWidgetSettings extends WidgetConfig {
volumeSource: LiquidWidgetDataSourceType; volumeSource: LiquidWidgetDataSourceType;
volumeConstant: number; volumeConstant: number;
volumeAttributeName: string; volumeAttributeName: string;
volumeUnitsSource: LiquidWidgetDataSourceType;
volumeUnitsAttributeName: string;
volumeUnits: CapacityUnits; volumeUnits: CapacityUnits;
volumeFont: Font; volumeFont: Font;
volumeColor: string; volumeColor: string;
@ -257,8 +259,10 @@ export const levelCardDefaultSettings: LevelCardWidgetSettings = {
iconColor: '#5469FF', iconColor: '#5469FF',
volumeSource: LiquidWidgetDataSourceType.static, volumeSource: LiquidWidgetDataSourceType.static,
volumeConstant: 500, volumeConstant: 500,
volumeUnits: CapacityUnits.liters,
volumeAttributeName: 'volume', volumeAttributeName: 'volume',
volumeUnitsSource: LiquidWidgetDataSourceType.static,
volumeUnitsAttributeName: 'volumeUnits',
volumeUnits: CapacityUnits.liters,
volumeFont: { volumeFont: {
family: 'Roboto', family: 'Roboto',
size: 14, size: 14,
@ -375,9 +379,7 @@ export const convertLiters = (value: number, units: CapacityUnits, conversionTyp
return conversionType === ConversionType.to ? value / factor : value * factor; return conversionType === ConversionType.to ? value / factor : value * factor;
}; };
export const extractValue = <T>(attributes: Array<AttributeData>, attributeName: string): T | undefined => { export const extractValue = <T>(attributes: Array<AttributeData>, attributeName: string): T | undefined => attributes.find(attr => attr.key === attributeName)?.value;
return attributes.find(attr => attr.key === attributeName)?.value;
};
export const valueContainerStyleDefaults = cssTextFromInlineStyle({ export const valueContainerStyleDefaults = cssTextFromInlineStyle({
width: '100%', width: '100%',
@ -494,6 +496,7 @@ export const updatedFormSettingsValidators = (formGroup: FormGroup) => {
const datasourceUnits: string = formGroup.get('datasourceUnits').value; const datasourceUnits: string = formGroup.get('datasourceUnits').value;
const layout: LevelCardLayout = formGroup.get('layout').value; const layout: LevelCardLayout = formGroup.get('layout').value;
const volumeSource: LiquidWidgetDataSourceType = formGroup.get('volumeSource').value; const volumeSource: LiquidWidgetDataSourceType = formGroup.get('volumeSource').value;
const volumeUnitsSource: LiquidWidgetDataSourceType = formGroup.get('volumeUnitsSource').value;
const widgetUnitsSource: LiquidWidgetDataSourceType = formGroup.get('widgetUnitsSource').value; const widgetUnitsSource: LiquidWidgetDataSourceType = formGroup.get('widgetUnitsSource').value;
const showTooltipLevel: boolean = formGroup.get('showTooltipLevel').value; const showTooltipLevel: boolean = formGroup.get('showTooltipLevel').value;
const showTooltipDate: boolean = formGroup.get('showTooltipDate').value; const showTooltipDate: boolean = formGroup.get('showTooltipDate').value;
@ -517,7 +520,7 @@ export const updatedFormSettingsValidators = (formGroup: FormGroup) => {
if (datasourceUnits !== CapacityUnits.percent) { if (datasourceUnits !== CapacityUnits.percent) {
formGroup.get('volumeSource').enable({emitEvent: false}); formGroup.get('volumeSource').enable({emitEvent: false});
formGroup.get('volumeUnits').enable({emitEvent: false}); formGroup.get('volumeUnitsSource').enable({emitEvent: false});
if (volumeSource === LiquidWidgetDataSourceType.static) { if (volumeSource === LiquidWidgetDataSourceType.static) {
formGroup.get('volumeConstant').enable({emitEvent: false}); formGroup.get('volumeConstant').enable({emitEvent: false});
formGroup.get('volumeAttributeName').disable({emitEvent: false}); formGroup.get('volumeAttributeName').disable({emitEvent: false});
@ -525,11 +528,20 @@ export const updatedFormSettingsValidators = (formGroup: FormGroup) => {
formGroup.get('volumeConstant').disable({emitEvent: false}); formGroup.get('volumeConstant').disable({emitEvent: false});
formGroup.get('volumeAttributeName').enable({emitEvent: false}); formGroup.get('volumeAttributeName').enable({emitEvent: false});
} }
if (volumeUnitsSource === LiquidWidgetDataSourceType.static) {
formGroup.get('volumeUnits').enable({emitEvent: false});
formGroup.get('volumeUnitsAttributeName').disable({emitEvent: false});
} else {
formGroup.get('volumeUnits').disable({emitEvent: false});
formGroup.get('volumeUnitsAttributeName').enable({emitEvent: false});
}
} else { } else {
formGroup.get('volumeSource').disable({emitEvent: false}); formGroup.get('volumeSource').disable({emitEvent: false});
formGroup.get('volumeConstant').disable({emitEvent: false}); formGroup.get('volumeConstant').disable({emitEvent: false});
formGroup.get('volumeAttributeName').disable({emitEvent: false}); formGroup.get('volumeAttributeName').disable({emitEvent: false});
formGroup.get('volumeUnitsSource').disable({emitEvent: false});
formGroup.get('volumeUnits').disable({emitEvent: false}); formGroup.get('volumeUnits').disable({emitEvent: false});
formGroup.get('volumeUnitsAttributeName').disable({emitEvent: false});
} }
if (layout === LevelCardLayout.simple) { if (layout === LevelCardLayout.simple) {
@ -557,7 +569,7 @@ export const updatedFormSettingsValidators = (formGroup: FormGroup) => {
} }
formGroup.get('volumeSource').enable({emitEvent: false}); formGroup.get('volumeSource').enable({emitEvent: false});
formGroup.get('volumeUnits').enable({emitEvent: false}); formGroup.get('volumeUnitsSource').enable({emitEvent: false});
if (volumeSource === LiquidWidgetDataSourceType.static) { if (volumeSource === LiquidWidgetDataSourceType.static) {
formGroup.get('volumeConstant').enable({emitEvent: false}); formGroup.get('volumeConstant').enable({emitEvent: false});
formGroup.get('volumeAttributeName').disable({emitEvent: false}); formGroup.get('volumeAttributeName').disable({emitEvent: false});
@ -565,6 +577,13 @@ export const updatedFormSettingsValidators = (formGroup: FormGroup) => {
formGroup.get('volumeConstant').disable({emitEvent: false}); formGroup.get('volumeConstant').disable({emitEvent: false});
formGroup.get('volumeAttributeName').enable({emitEvent: false}); formGroup.get('volumeAttributeName').enable({emitEvent: false});
} }
if (volumeUnitsSource === LiquidWidgetDataSourceType.static) {
formGroup.get('volumeUnits').enable({emitEvent: false});
formGroup.get('volumeUnitsAttributeName').disable({emitEvent: false});
} else {
formGroup.get('volumeUnits').disable({emitEvent: false});
formGroup.get('volumeUnitsAttributeName').enable({emitEvent: false});
}
if (formGroup.get('decimals')) { if (formGroup.get('decimals')) {
formGroup.get('decimals').enable({emitEvent: false}); formGroup.get('decimals').enable({emitEvent: false});

46
ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.html

@ -19,8 +19,8 @@
<div class="tb-form-panel no-padding no-border"> <div class="tb-form-panel no-padding no-border">
<div class="tb-form-panel"> <div class="tb-form-panel">
<div fxFlex fxLayout="column" class="tb-form-row space-between"> <div fxFlex fxLayout="column" class="tb-form-row space-between">
<div fxFlex fxLayout="row" style="width: 100%;" fxLayoutAlign="space-between center"> <div class="tb-flex row space-between align-center no-gap fill-width">
<div class="fixed-title-width" translate>widgets.liquid-level-card.shape</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.shape</div>
<tb-toggle-select formControlName="tankSelectionType"> <tb-toggle-select formControlName="tankSelectionType">
<tb-toggle-option *ngFor="let type of DataSourceTypes" [value]="type"> <tb-toggle-option *ngFor="let type of DataSourceTypes" [value]="type">
{{ DataSourceTypeTranslations.get(type) | translate }} {{ DataSourceTypeTranslations.get(type) | translate }}
@ -51,7 +51,7 @@
formControlName="shapeAttributeName"> formControlName="shapeAttributeName">
</tb-string-autocomplete> </tb-string-autocomplete>
</div> </div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center" style="width: 100%;"> <div class="tb-flex row space-between align-center no-gap fill-width">
<div class="tb-hint" style="padding: 0;" translate>widgets.liquid-level-card.shape-by-attribute</div> <div class="tb-hint" style="padding: 0;" translate>widgets.liquid-level-card.shape-by-attribute</div>
<div class="see-example" <div class="see-example"
[tb-help-popup]="'widget/lib/indicator/shape_attribute_fn'" [tb-help-popup]="'widget/lib/indicator/shape_attribute_fn'"
@ -87,9 +87,9 @@
formControlName="datasourceUnits"> formControlName="datasourceUnits">
</tb-unit-input> </tb-unit-input>
</div> </div>
<div class="tb-form-row space-between" *ngIf="levelCardWidgetSettingsForm.get('layout').value === LevelCardLayout.absolute"> <div class="tb-form-row space-between column-xs" *ngIf="levelCardWidgetSettingsForm.get('layout').value === LevelCardLayout.absolute">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.widget-units</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.widget-units</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="widgetUnitsSource" placeholder="{{ 'widget-config.set' | translate }}"> <mat-select formControlName="widgetUnitsSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type"> <mat-option *ngFor="let type of DataSourceTypes" [value]="type">
@ -111,9 +111,9 @@
</ng-template> </ng-template>
</div> </div>
</div> </div>
<div class="tb-form-row" *ngIf="volumeInput"> <div class="tb-form-row column-xs" *ngIf="volumeInput">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="volumeSource" placeholder="{{ 'widget-config.set' | translate }}"> <mat-select formControlName="volumeSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type"> <mat-option *ngFor="let type of DataSourceTypes" [value]="type">
@ -141,10 +141,30 @@
formControlName="volumeAttributeName"> formControlName="volumeAttributeName">
</tb-string-autocomplete> </tb-string-autocomplete>
</ng-template> </ng-template>
<tb-unit-input [tagFilter]="unitsType.capacity" </div>
required style="max-width: 25%" class="flex" </div>
<div class="tb-form-row space-between column-xs" [fxShow]="volumeInput">
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.total-volume-units</div>
<div class="tb-flex row flex-start align-center">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic" style="max-width: 25%">
<mat-select formControlName="volumeUnitsSource" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option *ngFor="let type of DataSourceTypes" [value]="type">
{{ DataSourceTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-unit-input *ngIf="levelCardWidgetSettingsForm.get('volumeUnitsSource').value === DataSourceType.static; else selectVolumeUnitsAttributes"
class="flex" required
[tagFilter]="unitsType.capacity"
formControlName="volumeUnits"> formControlName="volumeUnits">
</tb-unit-input> </tb-unit-input>
<ng-template #selectVolumeUnitsAttributes>
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
required style="flex: 1"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
formControlName="volumeUnitsAttributeName">
</tb-string-autocomplete>
</ng-template>
</div> </div>
</div> </div>
</div> </div>
@ -168,7 +188,7 @@
<div class="tb-form-row space-between" <div class="tb-form-row space-between"
*ngIf="levelCardWidgetSettingsForm.get('layout').value !== LevelCardLayout.simple"> *ngIf="levelCardWidgetSettingsForm.get('layout').value !== LevelCardLayout.simple">
<div class="fixed-title-width" translate>widgets.liquid-level-card.value</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.value</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<tb-font-settings formControlName="valueFont" <tb-font-settings formControlName="valueFont"
[previewText]="valuePreviewFn"> [previewText]="valuePreviewFn">
</tb-font-settings> </tb-font-settings>
@ -178,7 +198,7 @@
</div> </div>
<div class="tb-form-row" *ngIf="levelCardWidgetSettingsForm.get('layout').value === LevelCardLayout.absolute"> <div class="tb-form-row" *ngIf="levelCardWidgetSettingsForm.get('layout').value === LevelCardLayout.absolute">
<div class="fixed-title-width" translate>widgets.liquid-level-card.total-volume</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.total-volume</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px"> <div class="tb-flex row flex-end align-center">
<tb-font-settings formControlName="volumeFont" <tb-font-settings formControlName="volumeFont"
[previewText]="totalVolumeValuePreviewFn"> [previewText]="totalVolumeValuePreviewFn">
</tb-font-settings> </tb-font-settings>
@ -212,7 +232,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipLevel"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipLevel">
{{ 'widgets.liquid-level-card.level' | translate }} {{ 'widgets.liquid-level-card.level' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<tb-unit-input [tagFilter]="unitsType.capacity" <tb-unit-input [tagFilter]="unitsType.capacity"
required class="flex" formControlName="tooltipUnits"> required class="flex" formControlName="tooltipUnits">
</tb-unit-input> </tb-unit-input>
@ -232,7 +252,7 @@
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipDate"> <mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTooltipDate">
{{ 'widgets.value-card.date' | translate }} {{ 'widgets.value-card.date' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div class="tb-flex row flex-start align-center">
<tb-date-format-select fxFlex formControlName="tooltipDateFormat"></tb-date-format-select> <tb-date-format-select fxFlex formControlName="tooltipDateFormat"></tb-date-format-select>
<tb-font-settings formControlName="tooltipDateFont" <tb-font-settings formControlName="tooltipDateFont"
[previewText]="datePreviewFn"> [previewText]="datePreviewFn">

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts

@ -158,7 +158,9 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
volumeSource: [settings.volumeSource, []], volumeSource: [settings.volumeSource, []],
volumeConstant: [settings.volumeConstant, [Validators.required, Validators.min(0.1)]], volumeConstant: [settings.volumeConstant, [Validators.required, Validators.min(0.1)]],
volumeAttributeName: [settings.volumeAttributeName, [Validators.required]], volumeAttributeName: [settings.volumeAttributeName, [Validators.required]],
volumeUnitsSource: [settings.volumeUnitsSource, []],
volumeUnits: [settings.volumeUnits, [Validators.required]], volumeUnits: [settings.volumeUnits, [Validators.required]],
volumeUnitsAttributeName: [settings.volumeUnitsAttributeName, [Validators.required]],
volumeFont: [settings.volumeFont, []], volumeFont: [settings.volumeFont, []],
volumeColor: [settings.volumeColor, []], volumeColor: [settings.volumeColor, []],
valueFont: [settings.valueFont, []], valueFont: [settings.valueFont, []],
@ -195,7 +197,7 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return [ return [
'showBackgroundOverlay', 'showTooltip', 'showTooltipLevel', 'tankSelectionType', 'datasourceUnits', 'showBackgroundOverlay', 'showTooltip', 'showTooltipLevel', 'tankSelectionType', 'datasourceUnits',
'showTooltipDate', 'layout', 'volumeSource', 'widgetUnitsSource' 'showTooltipDate', 'layout', 'volumeSource', 'widgetUnitsSource', 'volumeUnitsSource'
]; ];
} }

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

@ -6361,6 +6361,7 @@
"layout": "Layout", "layout": "Layout",
"background-overlay": "Value background overlay", "background-overlay": "Value background overlay",
"total-volume": "Total volume", "total-volume": "Total volume",
"total-volume-units": "Total volume units",
"tank": "Tank", "tank": "Tank",
"shape": "Shape", "shape": "Shape",
"datasource-units": "Source units", "datasource-units": "Source units",

30
ui-ngx/src/form.scss

@ -233,6 +233,36 @@
} }
} }
.tb-flex {
display: flex;
flex: 1;
gap: 8px;
&.row {
flex-direction: row;
}
&.column {
flex-direction: column;
}
&.flex-start {
justify-content: flex-start;
}
&.flex-end {
justify-content: flex-end;
}
&.space-between {
justify-content: space-between;
}
&.align-center {
align-items: center;
}
&.no-gap {
gap: 0;
}
&.fill-width {
width: 100%;
}
}
.tb-form-panel, .tb-form-row { .tb-form-panel, .tb-form-row {
.mat-slide { .mat-slide {
margin: 0; margin: 0;

Loading…
Cancel
Save