UI: gateway dashboard improvements for connectors config

This commit is contained in:
Dmitriymush 2024-04-29 17:47:13 +03:00
parent e1d1f6c7f8
commit 9ce24b8ee3
7 changed files with 77 additions and 40 deletions

View File

@ -63,14 +63,16 @@ export class EllipsisChipListDirective implements OnDestroy {
private adjustChips(): void { private adjustChips(): void {
const chipListElement = this.el.nativeElement; const chipListElement = this.el.nativeElement;
const ellipsisText = this.el.nativeElement.querySelector('.ellipsis-text');
const chipNodes = chipListElement.querySelectorAll('mat-chip:not(.ellipsis-chip)');
const ellipsisChip = this.el.nativeElement.querySelector('.ellipsis-chip'); const ellipsisChip = this.el.nativeElement.querySelector('.ellipsis-chip');
const margin = parseFloat(this.window.getComputedStyle(ellipsisChip).marginLeft) || 0;
const chipNodes = chipListElement.querySelectorAll('mat-chip:not(.ellipsis-chip)');
if (this.chipsValue.length > 1) {
const ellipsisText = this.el.nativeElement.querySelector('.ellipsis-text');
this.renderer.setStyle(ellipsisChip, 'display', 'inline-flex'); this.renderer.setStyle(ellipsisChip, 'display', 'inline-flex');
ellipsisText.innerHTML = this.translate.instant('gateway.ellipsis-chips-text', ellipsisText.innerHTML = this.translate.instant('gateway.ellipsis-chips-text',
{count: (this.chipsValue.length)}); {count: (this.chipsValue.length)});
const margin = parseFloat(this.window.getComputedStyle(ellipsisChip).marginLeft) || 0;
const availableWidth = chipListElement.offsetWidth - (ellipsisChip.offsetWidth + margin); const availableWidth = chipListElement.offsetWidth - (ellipsisChip.offsetWidth + margin);
let usedWidth = 0; let usedWidth = 0;
let visibleChipsCount = 0; let visibleChipsCount = 0;
@ -91,6 +93,23 @@ export class EllipsisChipListDirective implements OnDestroy {
if (visibleChipsCount === this.chipsValue?.length) { if (visibleChipsCount === this.chipsValue?.length) {
this.renderer.setStyle(ellipsisChip, 'display', 'none'); this.renderer.setStyle(ellipsisChip, 'display', 'none');
} }
} else if (this.chipsValue.length === 1) {
this.renderer.setStyle(ellipsisChip, 'display', 'none');
const chipLabelContainer = chipNodes[0].querySelector('.mdc-evolution-chip__action');
const textLabelContainer = chipLabelContainer.querySelector('.mdc-evolution-chip__text-label');
const leftPadding = parseFloat(this.window.getComputedStyle(chipLabelContainer).paddingLeft) || 0;
const rightPadding = parseFloat(this.window.getComputedStyle(chipLabelContainer).paddingRight) || 0;
const computedTextWidth = chipListElement.offsetWidth - margin -
(leftPadding + rightPadding);
this.renderer.setStyle(textLabelContainer, 'max-width', computedTextWidth + 'px');
this.renderer.setStyle(textLabelContainer, 'overflow', 'hidden');
this.renderer.setStyle(textLabelContainer, 'text-overflow', 'ellipsis');
this.renderer.setStyle(textLabelContainer, 'white-space', 'nowrap');
} else {
this.renderer.setStyle(ellipsisChip, 'display', 'none');
}
} }
ngOnDestroy(): void { ngOnDestroy(): void {

View File

@ -26,7 +26,9 @@
<mat-expansion-panel class="tb-settings" [expanded]="last"> <mat-expansion-panel class="tb-settings" [expanded]="last">
<mat-expansion-panel-header fxLayout="row wrap"> <mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title> <mat-panel-title>
{{ keyControl.get('key').value + '-' + valueTitle(keyControl.get('value').value) }} <div class="title-container">{{ keyControl.get('key').value }}</div>
{{ '-' }}
<div class="title-container">{{ valueTitle(keyControl.get('value').value) }}</div>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<ng-template matExpansionPanelContent> <ng-template matExpansionPanelContent>

View File

@ -16,9 +16,16 @@
:host { :host {
.tb-mapping-keys-panel { .tb-mapping-keys-panel {
min-width: 700px; width: 77vw;
max-width: 700px; max-width: 700px;
.title-container {
max-width: 14vw;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
.key-panel { .key-panel {
height: 500px; height: 500px;
overflow: auto; overflow: auto;

View File

@ -98,7 +98,7 @@
*ngIf="converterType === ConvertorTypeEnum.BYTES || converterType === ConvertorTypeEnum.JSON"> *ngIf="converterType === ConvertorTypeEnum.BYTES || converterType === ConvertorTypeEnum.JSON">
<div class="tb-form-row space-between tb-flex"> <div class="tb-form-row space-between tb-flex">
<div class="fixed-title-width" translate>gateway.attributes</div> <div class="fixed-title-width" translate>gateway.attributes</div>
<div class="tb-flex"> <div class="tb-flex ellipsis-chips-container">
<mat-chip-listbox [tb-ellipsis-chip-list]="converterAttributes" class="tb-flex"> <mat-chip-listbox [tb-ellipsis-chip-list]="converterAttributes" class="tb-flex">
<mat-chip *ngFor="let attribute of converterAttributes"> <mat-chip *ngFor="let attribute of converterAttributes">
{{ attribute }} {{ attribute }}
@ -118,7 +118,7 @@
</div> </div>
<div class="tb-form-row space-between tb-flex"> <div class="tb-form-row space-between tb-flex">
<div class="fixed-title-width" translate>gateway.timeseries</div> <div class="fixed-title-width" translate>gateway.timeseries</div>
<div class="tb-flex"> <div class="tb-flex ellipsis-chips-container">
<mat-chip-listbox class="tb-flex" [tb-ellipsis-chip-list]="converterTelemetry"> <mat-chip-listbox class="tb-flex" [tb-ellipsis-chip-list]="converterTelemetry">
<mat-chip *ngFor="let telemetry of converterTelemetry"> <mat-chip *ngFor="let telemetry of converterTelemetry">
{{ telemetry }} {{ telemetry }}
@ -163,7 +163,7 @@
<div class="tb-form-hint tb-primary-fill">{{ 'gateway.extension-configuration-hint' | translate }}</div> <div class="tb-form-hint tb-primary-fill">{{ 'gateway.extension-configuration-hint' | translate }}</div>
<div class="tb-form-row space-between tb-flex"> <div class="tb-form-row space-between tb-flex">
<div class="fixed-title-width" translate>gateway.keys</div> <div class="fixed-title-width" translate>gateway.keys</div>
<div class="tb-flex"> <div class="tb-flex ellipsis-chips-container">
<mat-chip-listbox [tb-ellipsis-chip-list]="customKeys" class="tb-flex"> <mat-chip-listbox [tb-ellipsis-chip-list]="customKeys" class="tb-flex">
<mat-chip *ngFor="let telemetry of customKeys"> <mat-chip *ngFor="let telemetry of customKeys">
{{ telemetry }} {{ telemetry }}

View File

@ -36,6 +36,10 @@
max-height: 670px; max-height: 670px;
height: 670px; height: 670px;
} }
.ellipsis-chips-container {
max-width: 70%;
}
} }
:host ::ng-deep { :host ::ng-deep {

View File

@ -317,7 +317,7 @@
<div class="tb-flex no-gap"> <div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" type="number" min="1" formControlName="maxNumberOfWorkers" <input matInput name="value" type="number" min="1" formControlName="maxNumberOfWorkers"
placeholder="{{ 'gateway.default' | translate }}"/> placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix <mat-icon matSuffix
matTooltipPosition="above" matTooltipPosition="above"
matTooltipClass="tb-error-tooltip" matTooltipClass="tb-error-tooltip"
@ -339,7 +339,7 @@
<div class="tb-flex no-gap"> <div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" type="number" min="1" formControlName="maxMessageNumberPerWorker" <input matInput name="value" type="number" min="1" formControlName="maxMessageNumberPerWorker"
placeholder="{{ 'gateway.default' | translate }}"/> placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix <mat-icon matSuffix
matTooltipPosition="above" matTooltipPosition="above"
matTooltipClass="tb-error-tooltip" matTooltipClass="tb-error-tooltip"

View File

@ -64,6 +64,7 @@ import { MatDialog } from '@angular/material/dialog';
import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway/dialog/add-connector-dialog.component'; import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway/dialog/add-connector-dialog.component';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { ErrorStateMatcher } from '@angular/material/core'; import { ErrorStateMatcher } from '@angular/material/core';
import { PageData } from '@shared/models/page/page-data';
export class ForceErrorStateMatcher implements ErrorStateMatcher { export class ForceErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
@ -136,7 +137,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
private subscriptionOptions: WidgetSubscriptionOptions = { private subscriptionOptions: WidgetSubscriptionOptions = {
callbacks: { callbacks: {
onDataUpdated: (data) => this.ctx.ngZone.run(() => { onDataUpdated: () => this.ctx.ngZone.run(() => {
this.onDataUpdated(); this.onDataUpdated();
}), }),
onDataUpdateError: (subscription, e) => this.ctx.ngZone.run(() => { onDataUpdateError: (subscription, e) => this.ctx.ngZone.run(() => {
@ -363,17 +364,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
this.activeData = data.data.filter(value => this.activeConnectors.includes(value.key)); this.activeData = data.data.filter(value => this.activeConnectors.includes(value.key));
this.combineData(); this.combineData();
this.generateSubscription(); this.generateSubscription();
if (this.initialConnector) { this.setClientData(data);
const clientConnectorData = data.data.find(attr => attr.key === this.initialConnector.name);
if (clientConnectorData) {
clientConnectorData.value = typeof clientConnectorData.value === 'string' ?
JSON.parse(clientConnectorData.value) : clientConnectorData.value;
if (this.isConnectorSynced(clientConnectorData) && clientConnectorData.value.configurationJson) {
this.setFormValue(clientConnectorData.value);
}
}
}
}); });
this.inactiveConnectorsDataSource.loadAttributes(this.device, AttributeScope.SHARED_SCOPE, this.pageLink, reload).subscribe(data => { this.inactiveConnectorsDataSource.loadAttributes(this.device, AttributeScope.SHARED_SCOPE, this.pageLink, reload).subscribe(data => {
this.sharedAttributeData = data.data.filter(value => this.activeConnectors.includes(value.key)); this.sharedAttributeData = data.data.filter(value => this.activeConnectors.includes(value.key));
@ -723,4 +714,18 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
this.connectorForm.patchValue(connector, {emitEvent: false}); this.connectorForm.patchValue(connector, {emitEvent: false});
this.connectorForm.markAsPristine(); this.connectorForm.markAsPristine();
} }
private setClientData(data: PageData<AttributeData>): void {
if (this.initialConnector) {
const clientConnectorData = data.data.find(attr => attr.key === this.initialConnector.name);
if (clientConnectorData) {
clientConnectorData.value = typeof clientConnectorData.value === 'string' ?
JSON.parse(clientConnectorData.value) : clientConnectorData.value;
if (this.isConnectorSynced(clientConnectorData) && clientConnectorData.value.configurationJson) {
this.setFormValue(clientConnectorData.value);
}
}
}
}
} }