Browse Source

UI: Liquid level widget improvements, string autocomplete improvements

pull/9456/head
Dmitriymush 3 years ago
parent
commit
c20098088d
  1. 4
      ui-ngx/src/app/core/services/resources.service.ts
  2. 4
      ui-ngx/src/app/modules/home/components/widget/config/basic/cards/liquid-level-card-basic-config.component.html
  3. 3
      ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts
  4. 31
      ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.ts
  5. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/liquid-level-card-widget-settings.component.html
  6. 22
      ui-ngx/src/app/shared/components/string-autocomplete.component.html
  7. 33
      ui-ngx/src/app/shared/components/string-autocomplete.component.scss
  8. 58
      ui-ngx/src/app/shared/components/string-autocomplete.component.ts
  9. 3
      ui-ngx/src/app/shared/shared.module.ts

4
ui-ngx/src/app/core/services/resources.service.ts

@ -68,7 +68,9 @@ export class ResourcesService {
} }
const subject = new ReplaySubject<any>(); const subject = new ReplaySubject<any>();
this.loadedJsonResources[url] = subject; this.loadedJsonResources[url] = subject;
this.http.get<T>(url).subscribe( const req$ = (url.endsWith('.raw') || url.endsWith('.svg') ?
this.http.get(url, {responseType: 'text'}) : this.http.get<T>(url)) as Observable<T>;
req$.subscribe(
{ {
next: (o) => { next: (o) => {
if (postProcess) { if (postProcess) {

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

@ -93,6 +93,7 @@
<div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.shape-attribute-name</div> <div class="fixed-title-width tb-required" translate>widgets.liquid-level-card.shape-attribute-name</div>
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)" <tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
[required]="isRequired('shapeAttributeName')" [required]="isRequired('shapeAttributeName')"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
formControlName="shapeAttributeName"> formControlName="shapeAttributeName">
@ -151,6 +152,7 @@
<tb-string-autocomplete [fxShow]="levelCardWidgetConfigForm.get('widgetUnitsSource')?.value === levelOptions.attribute" <tb-string-autocomplete [fxShow]="levelCardWidgetConfigForm.get('widgetUnitsSource')?.value === levelOptions.attribute"
[fetchOptionsFn]="fetchOptions.bind(this)" [fetchOptionsFn]="fetchOptions.bind(this)"
[required]="isRequired('widgetUnitsAttributeName')" [required]="isRequired('widgetUnitsAttributeName')"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
formControlName="widgetUnitsAttributeName"> formControlName="widgetUnitsAttributeName">
@ -183,6 +185,7 @@
<tb-string-autocomplete style="max-width: 25%" <tb-string-autocomplete style="max-width: 25%"
[fxShow]="levelCardWidgetConfigForm.get('volumeSource')?.value === levelOptions.attribute" [fxShow]="levelCardWidgetConfigForm.get('volumeSource')?.value === levelOptions.attribute"
[fetchOptionsFn]="fetchOptions.bind(this)" [fetchOptionsFn]="fetchOptions.bind(this)"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
[required]="isRequired('volumeAttributeName')" [required]="isRequired('volumeAttributeName')"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
@ -315,7 +318,6 @@
<div class="tb-form-row space-between column-lt-md"> <div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div> <div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons"> <mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="dataExport">{{ 'widget-config.data-export' | translate }}</mat-chip-option>
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option> <mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox> </mat-chip-listbox>
</div> </div>

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

@ -16,7 +16,8 @@
import { import {
ColorSettings, ColorSettings,
constantColor, cssTextFromInlineStyle, constantColor,
cssTextFromInlineStyle,
DateFormatSettings, DateFormatSettings,
Font, Font,
lastUpdateAgoDateFormat lastUpdateAgoDateFormat

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

@ -43,13 +43,11 @@ import {
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import { ResourcesService } from '@core/services/resources.service'; import { ResourcesService } from '@core/services/resources.service';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
@Component({ @Component({
selector: 'tb-liquid-level-widget', selector: 'tb-liquid-level-widget',
template: '', template: ''
styleUrls: [],
encapsulation: ViewEncapsulation.None
}) })
export class LiquidLevelWidgetComponent implements OnInit { export class LiquidLevelWidgetComponent implements OnInit {
@ -98,17 +96,7 @@ export class LiquidLevelWidgetComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.ctx.$scope.liquidLevelWidget = this; this.ctx.$scope.liquidLevelWidget = this;
this.settings = {...levelCardDefaultSettings(), ...this.ctx.widgetConfig, ...this.ctx.settings}; this.settings = {...levelCardDefaultSettings(), ...this.ctx.widgetConfig, ...this.ctx.settings};
this.declareStyles();
this.tankColor = ColorProcessor.fromSettings(this.settings.tankColor);
this.volumeColor = ColorProcessor.fromSettings(this.settings.volumeColor);
this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor);
this.liquidColor = ColorProcessor.fromSettings(this.settings.liquidColor);
this.backgroundOverlayColor = ColorProcessor.fromSettings(this.settings.backgroundOverlayColor);
this.tooltipLevelColor = ColorProcessor.fromSettings(this.settings.tooltipLevelColor);
this.tooltipDateColor = ColorProcessor.fromSettings(this.settings.tooltipDateColor);
this.tooltipBackgroundColor = ColorProcessor.fromSettings(this.settings.tooltipBackgroundColor);
this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat);
} }
public onInit() { public onInit() {
@ -140,6 +128,19 @@ export class LiquidLevelWidgetComponent implements OnInit {
}); });
} }
private declareStyles():void {
this.tankColor = ColorProcessor.fromSettings(this.settings.tankColor);
this.volumeColor = ColorProcessor.fromSettings(this.settings.volumeColor);
this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor);
this.liquidColor = ColorProcessor.fromSettings(this.settings.liquidColor);
this.backgroundOverlayColor = ColorProcessor.fromSettings(this.settings.backgroundOverlayColor);
this.tooltipLevelColor = ColorProcessor.fromSettings(this.settings.tooltipLevelColor);
this.tooltipDateColor = ColorProcessor.fromSettings(this.settings.tooltipDateColor);
this.tooltipBackgroundColor = ColorProcessor.fromSettings(this.settings.tooltipBackgroundColor);
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 }> {
const entityId: EntityId = { const entityId: EntityId = {
entityType: this.ctx.datasources[0].entityType, entityType: this.ctx.datasources[0].entityType,

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

@ -48,6 +48,7 @@
<div class="fixed-title-width" translate>widgets.liquid-level-card.shape-attribute-name</div> <div class="fixed-title-width" translate>widgets.liquid-level-card.shape-attribute-name</div>
<tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)" <tb-string-autocomplete [fetchOptionsFn]="fetchOptions.bind(this)"
[required]="isRequired('shapeAttributeName')" [required]="isRequired('shapeAttributeName')"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
formControlName="shapeAttributeName"> formControlName="shapeAttributeName">
@ -110,6 +111,7 @@
<tb-string-autocomplete [fxShow]="levelCardWidgetSettingsForm.get('widgetUnitsSource')?.value === volumeOptions.attribute" <tb-string-autocomplete [fxShow]="levelCardWidgetSettingsForm.get('widgetUnitsSource')?.value === volumeOptions.attribute"
[fetchOptionsFn]="fetchOptions.bind(this)" [fetchOptionsFn]="fetchOptions.bind(this)"
[required]="isRequired('widgetUnitsAttributeName')" [required]="isRequired('widgetUnitsAttributeName')"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
formControlName="widgetUnitsAttributeName"> formControlName="widgetUnitsAttributeName">
@ -143,6 +145,7 @@
[fxShow]="levelCardWidgetSettingsForm.get('volumeSource')?.value === volumeOptions.attribute" [fxShow]="levelCardWidgetSettingsForm.get('volumeSource')?.value === volumeOptions.attribute"
[fetchOptionsFn]="fetchOptions.bind(this)" [fetchOptionsFn]="fetchOptions.bind(this)"
[required]="isRequired('volumeAttributeName')" [required]="isRequired('volumeAttributeName')"
[errorText]="'widgets.liquid-level-card.attribute-name-required' | translate"
style="flex: 1; width: auto;" style="flex: 1; width: auto;"
asBoxInput colorClearButton class="flex" asBoxInput colorClearButton class="flex"
formControlName="volumeAttributeName"> formControlName="volumeAttributeName">

22
ui-ngx/src/app/shared/components/string-autocomplete.component.html

@ -15,30 +15,36 @@
limitations under the License. limitations under the License.
--> -->
<mat-form-field fxFlex appearance="outline" class="tb-inline-field tb-suffix-show-on-hover" subscriptSizing="dynamic" style="width: 100%"> <mat-form-field [appearance]="appearance" [ngClass]="ngClass"
[subscriptSizing]="subscriptSizing" style="width: 100%">
<mat-label *ngIf="label">{{label}}</mat-label>
<input matInput #nameInput [formControl]="selectionFormControl" <input matInput #nameInput [formControl]="selectionFormControl"
placeholder="{{ 'widget-config.set' | translate }}" [placeholder]="placeholderText"
(focusin)="onFocus()" (focusin)="onFocus()"
[matAutocomplete]="optionsAutocomplete"> [matAutocomplete]="optionsAutocomplete">
<button *ngIf="selectionFormControl.value && !disabled && selectionFormControl.valid" <button *ngIf="selectionFormControl.value && !disabled"
type="button" type="button"
class="tb-icon-24" class="tb-icon-24"
matSuffix mat-icon-button aria-label="Clear" matSuffix mat-icon-button aria-label="Clear"
(click)="clear()"> (click)="clear()">
<mat-icon class="material-icons">close</mat-icon> <mat-icon class="material-icons">close</mat-icon>
</button> </button>
<mat-icon matSuffix <mat-icon *ngIf="selectionFormControl.hasError('required') && !showInlineError"
matIconSuffix
[matTooltip]="errorText"
matTooltipPosition="above" matTooltipPosition="above"
matTooltipClass="tb-error-tooltip" [matTooltipClass]="tooltipClass"
[matTooltip]="'widget-config.units-required' | translate" class="material-icons tb-suffix-show-always tb-error">
*ngIf="selectionFormControl.hasError('required')" class="material-icons tb-suffix-show-always tb-error">
warning warning
</mat-icon> </mat-icon>
<mat-error *ngIf="selectionFormControl.hasError('required') && showInlineError">
{{errorText}}
</mat-error>
<mat-autocomplete <mat-autocomplete
#optionsAutocomplete="matAutocomplete" #optionsAutocomplete="matAutocomplete"
class="tb-autocomplete tb-options-input-autocomplete" class="tb-autocomplete tb-options-input-autocomplete"
panelWidth="fit-content"> panelWidth="fit-content">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option"> <mat-option *ngFor="let option of filteredOptions$ | async" [value]="option">
<span class="tb-option-name" fxFlex [innerHTML]="option | highlight:searchText:true:'ig'"></span> <span class="tb-option-name" fxFlex [innerHTML]="option | highlight:searchText:true:'ig'"></span>
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>

33
ui-ngx/src/app/shared/components/string-autocomplete.component.scss

@ -13,19 +13,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
.tb-autocomplete.tb-option-input-autocomplete { :host {
.mat-mdc-option { display: flex;
border-bottom: none; flex: 1 1 0%;
.mdc-list-item__primary-text { max-width: 100%;
flex: 1; box-sizing: border-box;
display: flex;
flex-direction: row; .tb-autocomplete.tb-option-input-autocomplete {
gap: 8px; .mat-mdc-option {
.tb-option { border-bottom: none;
font-size: 14px; .mdc-list-item__primary-text {
font-weight: 400; flex: 1;
line-height: 20px; display: flex;
letter-spacing: 0.2px; flex-direction: row;
gap: 8px;
.tb-option {
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.2px;
}
} }
} }
} }

58
ui-ngx/src/app/shared/components/string-autocomplete.component.ts

@ -19,11 +19,8 @@ import {
Input, Input,
forwardRef, forwardRef,
OnInit, OnInit,
AfterViewInit,
HostBinding,
ViewChild, ViewChild,
ElementRef, ElementRef
Injector
} from '@angular/core'; } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
@ -33,7 +30,9 @@ import {
FormBuilder FormBuilder
} from '@angular/forms'; } from '@angular/forms';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { tap, map, switchMap } from 'rxjs/operators'; import { tap, map, switchMap, take } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({ @Component({
selector: 'tb-string-autocomplete', selector: 'tb-string-autocomplete',
@ -47,13 +46,12 @@ import { tap, map, switchMap } from 'rxjs/operators';
} }
] ]
}) })
export class StringAutocompleteComponent implements ControlValueAccessor, OnInit, AfterViewInit { export class StringAutocompleteComponent implements ControlValueAccessor, OnInit {
@HostBinding('style.display') get hostDisplay() {return 'flex';};
@Input() @Input()
disabled: boolean; disabled: boolean;
@coerceBoolean()
@Input() @Input()
required: boolean; required: boolean;
@ -61,11 +59,36 @@ export class StringAutocompleteComponent implements ControlValueAccessor, OnInit
@ViewChild('nameInput', {static: true}) nameInput: ElementRef; @ViewChild('nameInput', {static: true}) nameInput: ElementRef;
@Input()
placeholderText: string = this.translate.instant('widget-config.set');
@Input()
subscriptSizing: string = 'dynamic';
@Input()
ngClass: string | string[] | Set<string> | { [klass: string]: any; } = 'tb-inline-field tb-suffix-show-on-hover';
@Input()
appearance: string = 'outline';
@Input()
label: string;
@Input()
tooltipClass: string = 'tb-error-tooltip';
@Input()
errorText: string;
@coerceBoolean()
@Input()
showInlineError: boolean = false;
selectionFormControl: FormControl; selectionFormControl: FormControl;
modelValue: string | null; modelValue: string | null;
filteredOptions: Observable<Array<string>>; filteredOptions$: Observable<Array<string>>;
searchText = ''; searchText = '';
@ -73,13 +96,13 @@ export class StringAutocompleteComponent implements ControlValueAccessor, OnInit
private propagateChange = (_val: any) => {}; private propagateChange = (_val: any) => {};
constructor(private injector: Injector, constructor(private fb: FormBuilder,
private fb: FormBuilder) { private translate: TranslateService) {
} }
ngOnInit() { ngOnInit() {
this.selectionFormControl = this.fb.control('', []); this.selectionFormControl = this.fb.control('', this.required ? [Validators.required] : []);
this.filteredOptions = this.selectionFormControl.valueChanges this.filteredOptions$ = this.selectionFormControl.valueChanges
.pipe( .pipe(
tap(value => this.updateView(value)), tap(value => this.updateView(value)),
map(value => value ? value : ''), map(value => value ? value : ''),
@ -87,12 +110,6 @@ export class StringAutocompleteComponent implements ControlValueAccessor, OnInit
); );
} }
ngAfterViewInit() {
if (this.required) {
this.selectionFormControl.setValidators([Validators.required]);
}
}
writeValue(option?: string): void { writeValue(option?: string): void {
this.searchText = ''; this.searchText = '';
this.modelValue = option ? option : null; this.modelValue = option ? option : null;
@ -107,7 +124,8 @@ export class StringAutocompleteComponent implements ControlValueAccessor, OnInit
} }
return option; return option;
}) }),
take(1)
) )
.subscribe(result => { .subscribe(result => {
this.selectionFormControl.patchValue(result, { emitEvent: false }); this.selectionFormControl.patchValue(result, { emitEvent: false });

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

@ -200,7 +200,6 @@ import { ColorPickerPanelComponent } from '@shared/components/color-picker/color
import { TbIconComponent } from '@shared/components/icon.component'; import { TbIconComponent } from '@shared/components/icon.component';
import { HintTooltipIconComponent } from '@shared/components/hint-tooltip-icon.component'; import { HintTooltipIconComponent } from '@shared/components/hint-tooltip-icon.component';
import { StringAutocompleteComponent } from '@shared/components/string-autocomplete.component'; import { StringAutocompleteComponent } from '@shared/components/string-autocomplete.component';
import { MatFormFieldModule } from '@angular/material/form-field';
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
return markedOptionsService; return markedOptionsService;
@ -401,7 +400,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatGridListModule, MatGridListModule,
MatDialogModule, MatDialogModule,
MatSelectModule, MatSelectModule,
MatFormFieldModule,
MatTooltipModule, MatTooltipModule,
MatTableModule, MatTableModule,
MatPaginatorModule, MatPaginatorModule,
@ -517,7 +515,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatGridListModule, MatGridListModule,
MatDialogModule, MatDialogModule,
MatSelectModule, MatSelectModule,
MatFormFieldModule,
MatTooltipModule, MatTooltipModule,
MatTableModule, MatTableModule,
MatPaginatorModule, MatPaginatorModule,

Loading…
Cancel
Save