UI: Refactoring liquid level widgets after review
This commit is contained in:
parent
73566db398
commit
0bab29c8ec
@ -84,7 +84,7 @@
|
||||
label="{{ 'widgets.liquid-level-card.shape-type' | translate }}" formControlName="selectedShape">
|
||||
<tb-image-cards-select-option *ngFor="let shape of shapes"
|
||||
[value]="shape"
|
||||
[image]="createShapeLayout(shapesImageMap.get(shape), this.levelCardLayouts.simple)">
|
||||
[image]="createShape(shapesImageMap.get(shape), this.levelCardLayouts.simple)">
|
||||
{{ shapesTranslationMap.get(shape) | translate }}
|
||||
</tb-image-cards-select-option>
|
||||
</tb-image-cards-select>
|
||||
@ -94,8 +94,7 @@
|
||||
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[required]="isRequired('shapeAttributeName')"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="shapeAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
</div>
|
||||
@ -118,7 +117,7 @@
|
||||
<tb-image-cards-select-option
|
||||
*ngFor="let layout of [levelCardLayouts.simple, levelCardLayouts.percentage, levelCardLayouts.absolute]"
|
||||
[value]="layout"
|
||||
[image]="createShapeLayout(shapesImageMap.get(levelCardWidgetConfigForm.get('selectedShape').value), layout)">
|
||||
[image]="createShape(shapesImageMap.get(levelCardWidgetConfigForm.get('selectedShape').value), layout)">
|
||||
{{ levelCardLayoutTranslationMap.get(layout) | translate }}
|
||||
</tb-image-cards-select-option>
|
||||
</tb-image-cards-select>
|
||||
@ -144,7 +143,7 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<tb-unit-input [fxShow]="levelCardWidgetConfigForm.get('widgetUnitsSource')?.value !== levelOptions.attribute"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
class="flex"
|
||||
[tagFilter]="unitsType.capacity"
|
||||
[required]="isRequired('units')"
|
||||
formControlName="units">
|
||||
@ -153,8 +152,7 @@
|
||||
[fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[required]="isRequired('widgetUnitsAttributeName')"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="widgetUnitsAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
</div>
|
||||
@ -182,17 +180,14 @@
|
||||
warning
|
||||
</mat-icon>
|
||||
</mat-form-field>
|
||||
<tb-string-autocomplete style="max-width: 25%"
|
||||
[fxShow]="levelCardWidgetConfigForm.get('volumeSource')?.value === levelOptions.attribute"
|
||||
<tb-string-autocomplete [fxShow]="levelCardWidgetConfigForm.get('volumeSource')?.value === levelOptions.attribute"
|
||||
[fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
[required]="isRequired('volumeAttributeName')"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="volumeAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
<tb-unit-input asBoxInput colorClearButton
|
||||
[tagFilter]="unitsType.capacity"
|
||||
<tb-unit-input [tagFilter]="unitsType.capacity"
|
||||
[required]="isRequired('volumeUnits')"
|
||||
style="max-width: 25%" class="flex"
|
||||
formControlName="volumeUnits">
|
||||
|
||||
@ -43,23 +43,22 @@ import {
|
||||
} from '@shared/models/widget-settings.models';
|
||||
import {
|
||||
CapacityUnits,
|
||||
createAbsoluteLayout,
|
||||
createPercentLayout,
|
||||
createShapeLayout,
|
||||
levelCardDefaultSettings,
|
||||
LevelCardLayout,
|
||||
levelCardLayoutTranslations,
|
||||
LevelCardWidgetSettings,
|
||||
LevelSelectOptions,
|
||||
loadSvgShapesMapping,
|
||||
optionsFilter,
|
||||
Shapes,
|
||||
shapesTranslations,
|
||||
svgMapping
|
||||
shapesTranslations
|
||||
} from '@home/components/widget/lib/indicator/liquid-level-widget.models';
|
||||
import { UnitsType } from '@shared/models/unit.models';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
import { ImageCardsSelectComponent } from '@home/components/widget/lib/settings/common/image-cards-select.component';
|
||||
import { map, publishReplay, refCount, tap } from 'rxjs/operators';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { map, share, tap } from 'rxjs/operators';
|
||||
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||
import { ResourcesService } from '@core/services/resources.service';
|
||||
import { UnitInputComponent } from '@shared/components/unit-input.component';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
@ -242,7 +241,7 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
|
||||
actions: [configData.config.actions || {}, []]
|
||||
});
|
||||
|
||||
this.levelCardWidgetConfigForm.get('selectedShape').valueChanges.subscribe((shape) => {
|
||||
this.levelCardWidgetConfigForm.get('selectedShape').valueChanges.subscribe(() => {
|
||||
this.cd.detectChanges();
|
||||
this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges();
|
||||
});
|
||||
@ -562,21 +561,8 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
|
||||
}
|
||||
|
||||
private createSvgShapesMapping(): void {
|
||||
const obsArray: Array<Observable<{svg: string; shape: Shapes}>> = [];
|
||||
for (const shape of this.shapes) {
|
||||
const svgUrl = svgMapping.get(shape).svg;
|
||||
|
||||
const obs = this.resourcesService.loadJsonResource<string>(svgUrl).pipe(
|
||||
map((svg) => ({svg, shape}))
|
||||
);
|
||||
|
||||
obsArray.push(obs);
|
||||
}
|
||||
|
||||
forkJoin(obsArray).subscribe((svgData) => {
|
||||
for (const data of svgData) {
|
||||
this.shapesImageMap.set(data.shape, data.svg);
|
||||
}
|
||||
loadSvgShapesMapping(this.resourcesService).subscribe(shapeMap => {
|
||||
this.shapesImageMap = shapeMap;
|
||||
|
||||
this.cd.detectChanges();
|
||||
this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges();
|
||||
@ -584,25 +570,8 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
|
||||
});
|
||||
}
|
||||
|
||||
public createShapeLayout(svg: string, layout: LevelCardLayout): SafeUrl {
|
||||
if (svg && layout) {
|
||||
const parser = new DOMParser();
|
||||
const svgImage = parser.parseFromString(svg, 'image/svg+xml');
|
||||
|
||||
if (layout === this.levelCardLayouts.simple) {
|
||||
svgImage.querySelector('.container-overlay').remove();
|
||||
} else if (layout === this.levelCardLayouts.percentage) {
|
||||
svgImage.querySelector('.absolute-overlay').remove();
|
||||
svgImage.querySelector('.percentage-value-container').innerHTML = createPercentLayout();
|
||||
} else {
|
||||
svgImage.querySelector('.absolute-value-container').innerHTML = createAbsoluteLayout();
|
||||
svgImage.querySelector('.percentage-overlay').remove();
|
||||
}
|
||||
|
||||
const encodedSvg = encodeURIComponent(svgImage.documentElement.outerHTML);
|
||||
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(`data:image/svg+xml,${encodedSvg}`);
|
||||
}
|
||||
createShape(svg: string, layout: LevelCardLayout): SafeUrl {
|
||||
return createShapeLayout(svg, layout, this.sanitizer);
|
||||
}
|
||||
|
||||
public isRequired(formControlName: string): boolean {
|
||||
@ -649,8 +618,12 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon
|
||||
fetchObservable = of([]);
|
||||
}
|
||||
return fetchObservable.pipe(
|
||||
publishReplay(1),
|
||||
refCount()
|
||||
share({
|
||||
connector: () => new ReplaySubject(1),
|
||||
resetOnError: false,
|
||||
resetOnComplete: false,
|
||||
resetOnRefCountZero: false
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import { AppState } from '@core/core.state';
|
||||
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { DataKey, DatasourceType, KeyInfo, WidgetConfigMode } from '@shared/models/widget.models';
|
||||
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
|
||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||
import { isDefinedAndNotNull } from '@core/utils';
|
||||
|
||||
export type WidgetConfigCallbacks = DatasourceCallbacks & WidgetActionCallbacks;
|
||||
|
||||
@ -20,7 +20,9 @@ import { isDefined, isDefinedAndNotNull, isNumber, isString } from '@core/utils'
|
||||
import {
|
||||
CapacityUnits,
|
||||
ConversionType,
|
||||
convertLiters, createAbsoluteLayout, createPercentLayout,
|
||||
convertLiters,
|
||||
createAbsoluteLayout,
|
||||
createPercentLayout,
|
||||
extractValue,
|
||||
levelCardDefaultSettings,
|
||||
LevelCardLayout,
|
||||
@ -40,11 +42,12 @@ import {
|
||||
DateFormatProcessor,
|
||||
inlineTextStyle
|
||||
} from '@shared/models/widget-settings.models';
|
||||
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
||||
import { ResourcesService } from '@core/services/resources.service';
|
||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
||||
|
||||
@Component({
|
||||
selector: 'tb-liquid-level-widget',
|
||||
template: ''
|
||||
@ -328,7 +331,12 @@ export class LiquidLevelWidgetComponent implements OnInit {
|
||||
this.updateLevel(newYPos, percentage);
|
||||
}
|
||||
|
||||
private calculatePosition(percentage, limits): number {
|
||||
private calculatePosition(percentage: number, limits: SvgLimits): number {
|
||||
if (percentage > 100) {
|
||||
return limits.max;
|
||||
} if (percentage <= 0) {
|
||||
return limits.min;
|
||||
}
|
||||
return limits.min + (percentage / 100) * (limits.max - limits.min);
|
||||
}
|
||||
|
||||
@ -368,7 +376,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private updateShapeColor(value): void {
|
||||
private updateShapeColor(value: number): void {
|
||||
const shapeStrokes = this.ctx.$container.find('.tb-shape-stroke');
|
||||
const shapeFill = this.ctx.$container.find('.tb-shape-fill');
|
||||
this.tankColor.update(value);
|
||||
@ -504,7 +512,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public cardClick($event) {
|
||||
public cardClick($event: Event) {
|
||||
this.ctx.actionsApi.cardClick($event);
|
||||
}
|
||||
}
|
||||
@ -24,12 +24,14 @@ import {
|
||||
} from '@shared/models/widget-settings.models';
|
||||
import { DataKey, WidgetConfig } from '@shared/models/widget.models';
|
||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { singleEntityFilterFromDeviceId } from '@shared/models/query/query.models';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
import { catchError, mergeMap } from 'rxjs/operators';
|
||||
import { catchError, map, mergeMap } from 'rxjs/operators';
|
||||
import { EntityService } from '@core/http/entity.service';
|
||||
import { IAliasController } from '@core/api/widget-api.models';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
import { ResourcesService } from '@core/services/resources.service';
|
||||
|
||||
export interface SvgInfo {
|
||||
svg: string;
|
||||
@ -123,7 +125,7 @@ export enum ConversionType {
|
||||
from = 'from',
|
||||
}
|
||||
|
||||
export const svgMapping = new Map<string, SvgInfo>(
|
||||
export const svgMapping = new Map<Shapes, SvgInfo>(
|
||||
[
|
||||
[
|
||||
Shapes.vOval,
|
||||
@ -421,8 +423,49 @@ export const fetchEntityKeys = (entityAliasId: string, dataKeyTypes: Array<DataK
|
||||
aliasInfo.entityFilter,
|
||||
dataKeyTypes, [],
|
||||
{ignoreLoading: true, ignoreErrors: true}
|
||||
).pipe(
|
||||
catchError(() => of([]))
|
||||
)),
|
||||
catchError(() => of([] as Array<DataKey>))
|
||||
);
|
||||
|
||||
|
||||
export const createShapeLayout = (svg: string, layout: LevelCardLayout, sanitizer: DomSanitizer): SafeUrl => {
|
||||
if (svg && layout) {
|
||||
const parser = new DOMParser();
|
||||
const svgImage = parser.parseFromString(svg, 'image/svg+xml');
|
||||
|
||||
if (layout === LevelCardLayout.simple) {
|
||||
svgImage.querySelector('.container-overlay').remove();
|
||||
} else if (layout === LevelCardLayout.percentage) {
|
||||
svgImage.querySelector('.absolute-overlay').remove();
|
||||
svgImage.querySelector('.percentage-value-container').innerHTML = createPercentLayout();
|
||||
} else {
|
||||
svgImage.querySelector('.absolute-value-container').innerHTML = createAbsoluteLayout();
|
||||
svgImage.querySelector('.percentage-overlay').remove();
|
||||
}
|
||||
|
||||
const encodedSvg = encodeURIComponent(svgImage.documentElement.outerHTML);
|
||||
|
||||
return sanitizer.bypassSecurityTrustResourceUrl(`data:image/svg+xml,${encodedSvg}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const loadSvgShapesMapping = (resourcesService: ResourcesService): Observable<Map<Shapes, string>> => {
|
||||
const obsArray: Array<Observable<{svg: string; shape: Shapes}>> = [];
|
||||
const shapesImageMap: Map<Shapes, string> = new Map();
|
||||
svgMapping.forEach((value, shape) => {
|
||||
const obs = resourcesService.loadJsonResource<string>(value.svg).pipe(
|
||||
map((svg) => ({svg, shape}))
|
||||
);
|
||||
|
||||
obsArray.push(obs);
|
||||
});
|
||||
|
||||
return forkJoin(obsArray).pipe(
|
||||
map(svgData => {
|
||||
for (const data of svgData) {
|
||||
shapesImageMap.set(data.shape, data.svg);
|
||||
}
|
||||
return shapesImageMap;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
-->
|
||||
<ng-container *ngIf="levelCardWidgetSettingsForm" [formGroup]="levelCardWidgetSettingsForm">
|
||||
<div style="display: flex; flex-direction: column; gap: 16px;">
|
||||
<div class="tb-form-panel no-padding no-border">
|
||||
<div class="tb-form-panel">
|
||||
<div fxFlex fxLayout="column" class="tb-form-row space-between">
|
||||
<div fxFlex fxLayout="row" style="width: 100%;" fxLayoutAlign="space-between center">
|
||||
@ -39,7 +39,7 @@
|
||||
label="{{ 'widgets.liquid-level-card.shape-type' | translate }}" formControlName="selectedShape">
|
||||
<tb-image-cards-select-option *ngFor="let shape of shapes"
|
||||
[value]="shape"
|
||||
[image]="createShapeLayout(shapesImageMap.get(shape), this.levelCardLayouts.simple)">
|
||||
[image]="createShape(shapesImageMap.get(shape), this.levelCardLayouts.simple)">
|
||||
{{ shapesTranslationMap.get(shape) | translate }}
|
||||
</tb-image-cards-select-option>
|
||||
</tb-image-cards-select>
|
||||
@ -49,8 +49,7 @@
|
||||
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[required]="isRequired('shapeAttributeName')"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="shapeAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
</div>
|
||||
@ -77,7 +76,7 @@
|
||||
<tb-image-cards-select-option
|
||||
*ngFor="let layout of [levelCardLayouts.simple, levelCardLayouts.percentage, levelCardLayouts.absolute]"
|
||||
[value]="layout"
|
||||
[image]="createShapeLayout(shapesImageMap.get(levelCardWidgetSettingsForm.get('selectedShape').value), layout)">
|
||||
[image]="createShape(shapesImageMap.get(levelCardWidgetSettingsForm.get('selectedShape').value), layout)">
|
||||
{{ levelCardLayoutTranslationMap.get(layout) | translate }}
|
||||
</tb-image-cards-select-option>
|
||||
</tb-image-cards-select>
|
||||
@ -103,7 +102,7 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<tb-unit-input [fxShow]="levelCardWidgetSettingsForm.get('widgetUnitsSource')?.value !== volumeOptions.attribute"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
class="flex"
|
||||
[tagFilter]="unitsType.capacity"
|
||||
[required]="isRequired('units')"
|
||||
formControlName="units">
|
||||
@ -112,8 +111,7 @@
|
||||
[fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[required]="isRequired('widgetUnitsAttributeName')"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="widgetUnitsAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
</div>
|
||||
@ -141,17 +139,14 @@
|
||||
warning
|
||||
</mat-icon>
|
||||
</mat-form-field>
|
||||
<tb-string-autocomplete style="max-width: 25%"
|
||||
[fxShow]="levelCardWidgetSettingsForm.get('volumeSource')?.value === volumeOptions.attribute"
|
||||
<tb-string-autocomplete [fxShow]="levelCardWidgetSettingsForm.get('volumeSource')?.value === volumeOptions.attribute"
|
||||
[fetchOptionsFn]="fetchOptions.bind(this)"
|
||||
[required]="isRequired('volumeAttributeName')"
|
||||
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
|
||||
style="flex: 1; width: auto;"
|
||||
asBoxInput colorClearButton class="flex"
|
||||
style="flex: 1"
|
||||
formControlName="volumeAttributeName">
|
||||
</tb-string-autocomplete>
|
||||
<tb-unit-input asBoxInput colorClearButton
|
||||
[tagFilter]="unitsType.capacity"
|
||||
<tb-unit-input [tagFilter]="unitsType.capacity"
|
||||
[required]="isRequired('volumeUnits')"
|
||||
style="max-width: 25%" class="flex"
|
||||
formControlName="volumeUnits">
|
||||
|
||||
@ -27,30 +27,26 @@ import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { formatValue, isDefined } from '@core/utils';
|
||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
|
||||
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
|
||||
import {
|
||||
DateFormatProcessor,
|
||||
DateFormatSettings
|
||||
} from '@shared/models/widget-settings.models';
|
||||
import {
|
||||
CapacityUnits,
|
||||
createShapeLayout,
|
||||
fetchEntityKeys,
|
||||
fetchEntityKeysForDevice,
|
||||
levelCardDefaultSettings,
|
||||
LevelCardLayout,
|
||||
levelCardLayoutTranslations,
|
||||
Shapes,
|
||||
shapesTranslations,
|
||||
svgMapping,
|
||||
CapacityUnits,
|
||||
LevelSelectOptions,
|
||||
createPercentLayout,
|
||||
createAbsoluteLayout,
|
||||
loadSvgShapesMapping,
|
||||
optionsFilter,
|
||||
fetchEntityKeysForDevice,
|
||||
fetchEntityKeys
|
||||
Shapes,
|
||||
shapesTranslations
|
||||
} from '@home/components/widget/lib/indicator/liquid-level-widget.models';
|
||||
import { UnitsType } from '@shared/models/unit.models';
|
||||
import { ImageCardsSelectComponent } from '@home/components/widget/lib/settings/common/image-cards-select.component';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { map, publishReplay, refCount, tap } from 'rxjs/operators';
|
||||
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||
import { map, share, tap } from 'rxjs/operators';
|
||||
import { ResourcesService } from '@core/services/resources.service';
|
||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
@ -201,7 +197,7 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
|
||||
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
|
||||
});
|
||||
|
||||
this.levelCardWidgetSettingsForm.get('selectedShape').valueChanges.subscribe((shape) => {
|
||||
this.levelCardWidgetSettingsForm.get('selectedShape').valueChanges.subscribe(() => {
|
||||
this.cd.detectChanges();
|
||||
this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges();
|
||||
});
|
||||
@ -390,21 +386,8 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
|
||||
}
|
||||
|
||||
private createSvgShapesMapping(): void {
|
||||
const obsArray: Array<Observable<{svg: string; shape: Shapes}>> = [];
|
||||
for (const shape of this.shapes) {
|
||||
const svgUrl = svgMapping.get(shape).svg;
|
||||
|
||||
const obs = this.resourcesService.loadJsonResource<string>(svgUrl).pipe(
|
||||
map((svg) => ({svg, shape}))
|
||||
);
|
||||
|
||||
obsArray.push(obs);
|
||||
}
|
||||
|
||||
forkJoin(obsArray).subscribe((svgData) => {
|
||||
for (const data of svgData) {
|
||||
this.shapesImageMap.set(data.shape, data.svg);
|
||||
}
|
||||
loadSvgShapesMapping(this.resourcesService).subscribe(shapeMap => {
|
||||
this.shapesImageMap = shapeMap;
|
||||
|
||||
this.cd.detectChanges();
|
||||
this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges();
|
||||
@ -412,25 +395,8 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
|
||||
});
|
||||
}
|
||||
|
||||
public createShapeLayout(svg: string, layout: LevelCardLayout): SafeUrl {
|
||||
if (svg && layout) {
|
||||
const parser = new DOMParser();
|
||||
const svgImage = parser.parseFromString(svg, 'image/svg+xml');
|
||||
|
||||
if (layout === this.levelCardLayouts.simple) {
|
||||
svgImage.querySelector('.container-overlay').remove();
|
||||
} else if (layout === this.levelCardLayouts.percentage) {
|
||||
svgImage.querySelector('.absolute-overlay').remove();
|
||||
svgImage.querySelector('.percentage-value-container').innerHTML = createPercentLayout();
|
||||
} else {
|
||||
svgImage.querySelector('.absolute-value-container').innerHTML = createAbsoluteLayout();
|
||||
svgImage.querySelector('.percentage-overlay').remove();
|
||||
}
|
||||
|
||||
const encodedSvg = encodeURIComponent(svgImage.documentElement.outerHTML);
|
||||
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(`data:image/svg+xml,${encodedSvg}`);
|
||||
}
|
||||
createShape(svg: string, layout: LevelCardLayout): SafeUrl {
|
||||
return createShapeLayout(svg, layout, this.sanitizer);
|
||||
}
|
||||
|
||||
public isRequired(formControlName: string): boolean {
|
||||
@ -509,8 +475,12 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon
|
||||
fetchObservable = of([]);
|
||||
}
|
||||
return fetchObservable.pipe(
|
||||
publishReplay(1),
|
||||
refCount()
|
||||
share({
|
||||
connector: () => new ReplaySubject(1),
|
||||
resetOnError: false,
|
||||
resetOnComplete: false,
|
||||
resetOnRefCountZero: false
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,11 +32,12 @@ import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { map, share, startWith, takeUntil } from 'rxjs/operators';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { MediaBreakpoints } from '@shared/models/constants';
|
||||
import { SafeUrl } from '@angular/platform-browser';
|
||||
|
||||
export interface ImageCardsSelectOption {
|
||||
name: string;
|
||||
value: any;
|
||||
image: string;
|
||||
image: string | SafeUrl;
|
||||
}
|
||||
|
||||
@Directive(
|
||||
@ -49,7 +50,7 @@ export class ImageCardsSelectOptionDirective {
|
||||
|
||||
@Input() value: any;
|
||||
|
||||
@Input() image: string;
|
||||
@Input() image: string | SafeUrl;
|
||||
|
||||
get viewValue(): string {
|
||||
return (this._element?.nativeElement.textContent || '').trim();
|
||||
|
||||
@ -64,7 +64,7 @@ import {
|
||||
import { SignalStrengthWidgetComponent } from '@home/components/widget/lib/indicator/signal-strength-widget.component';
|
||||
import { ValueChartCardWidgetComponent } from '@home/components/widget/lib/cards/value-chart-card-widget.component';
|
||||
import { ProgressBarWidgetComponent } from '@home/components/widget/lib/cards/progress-bar-widget.component';
|
||||
import { LiquidLevelWidgetComponent } from '@home/components/widget/lib/indicator/liquid-level-widget';
|
||||
import { LiquidLevelWidgetComponent } from '@home/components/widget/lib/indicator/liquid-level-widget.component';
|
||||
|
||||
@NgModule({
|
||||
declarations:
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<mat-form-field [appearance]="appearance" [ngClass]="ngClass"
|
||||
<mat-form-field [appearance]="appearance" [class]="additionalClass"
|
||||
[subscriptSizing]="subscriptSizing" style="width: 100%">
|
||||
<mat-label *ngIf="label">{{label}}</mat-label>
|
||||
<input matInput #nameInput [formControl]="selectionFormControl"
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
:host {
|
||||
mat-form-field {
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
flex: 1;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ import { Observable, of } from 'rxjs';
|
||||
import { tap, map, switchMap, take } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-string-autocomplete',
|
||||
@ -48,41 +49,42 @@ import { coerceBoolean } from '@shared/decorators/coercion';
|
||||
})
|
||||
export class StringAutocompleteComponent implements ControlValueAccessor, OnInit {
|
||||
|
||||
@ViewChild('nameInput', {static: true}) nameInput: ElementRef;
|
||||
|
||||
@Input()
|
||||
disabled: boolean;
|
||||
|
||||
@coerceBoolean()
|
||||
@Input()
|
||||
required: boolean = false;
|
||||
@coerceBoolean()
|
||||
required = false;
|
||||
|
||||
@Input() fetchOptionsFn: (searchText?: string) => Observable<Array<string>>;
|
||||
|
||||
@ViewChild('nameInput', {static: true}) nameInput: ElementRef;
|
||||
@Input()
|
||||
fetchOptionsFn: (searchText?: string) => Observable<Array<string>>;
|
||||
|
||||
@Input()
|
||||
placeholderText: string = this.translate.instant('widget-config.set');
|
||||
|
||||
@Input()
|
||||
subscriptSizing: string = 'dynamic';
|
||||
subscriptSizing: SubscriptSizing = 'dynamic';
|
||||
|
||||
@Input()
|
||||
ngClass: string | string[] | Set<string> | { [klass: string]: any; } = 'tb-inline-field tb-suffix-show-on-hover';
|
||||
additionalClass: string | string[] | Record<string, boolean | undefined | null> = 'tb-inline-field tb-suffix-show-on-hover';
|
||||
|
||||
@Input()
|
||||
appearance: string = 'outline';
|
||||
appearance: MatFormFieldAppearance = 'outline';
|
||||
|
||||
@Input()
|
||||
label: string;
|
||||
|
||||
@Input()
|
||||
tooltipClass: string = 'tb-error-tooltip';
|
||||
tooltipClass = 'tb-error-tooltip';
|
||||
|
||||
@Input()
|
||||
errorText: string;
|
||||
|
||||
@coerceBoolean()
|
||||
@Input()
|
||||
showInlineError: boolean = false;
|
||||
@coerceBoolean()
|
||||
showInlineError = false;
|
||||
|
||||
selectionFormControl: FormControl;
|
||||
|
||||
|
||||
@ -62,9 +62,9 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit {
|
||||
@Input()
|
||||
disabled: boolean;
|
||||
|
||||
@coerceBoolean()
|
||||
@Input()
|
||||
required: boolean = false;
|
||||
@coerceBoolean()
|
||||
required = false;
|
||||
|
||||
@Input()
|
||||
tagFilter: UnitsType;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user