UI: Improved view gateway dashboard and updated gateway widget types

This commit is contained in:
Vladyslav_Prykhodko 2023-09-12 19:08:40 +03:00
parent 0b9df293cd
commit 65145284ca
14 changed files with 452 additions and 605 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,8 +17,6 @@
import { Inject, Injectable, Type } from '@angular/core';
import { Observable } from 'rxjs';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
import { AuthService } from '@core/auth/auth.service';
import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service';
import { CommonModule } from '@angular/common';
import { mergeMap, tap } from 'rxjs/operators';
@ -28,7 +26,11 @@ import {
CustomDialogContainerData
} from '@home/components/widget/dialog/custom-dialog-container.component';
import { SHARED_MODULE_TOKEN } from '@shared/components/tokens';
import { HOME_COMPONENTS_MODULE_TOKEN, SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens';
import {
HOME_COMPONENTS_MODULE_TOKEN,
SHARED_HOME_COMPONENTS_MODULE_TOKEN,
WIDGET_COMPONENTS_MODULE_TOKEN
} from '@home/components/tokens';
@Injectable()
export class CustomDialogService {
@ -36,12 +38,11 @@ export class CustomDialogService {
private customModules: Array<Type<any>>;
constructor(
private translate: TranslateService,
private authService: AuthService,
private dynamicComponentFactoryService: DynamicComponentFactoryService,
@Inject(SHARED_MODULE_TOKEN) private sharedModule: Type<any>,
@Inject(SHARED_HOME_COMPONENTS_MODULE_TOKEN) private sharedHomeComponentsModule: Type<any>,
@Inject(HOME_COMPONENTS_MODULE_TOKEN) private homeComponentsModule: Type<any>,
@Inject(WIDGET_COMPONENTS_MODULE_TOKEN) private widgetComponentsModule: Type<any>,
public dialog: MatDialog
) {
}
@ -52,7 +53,8 @@ export class CustomDialogService {
customDialog(template: string, controller: (instance: CustomDialogComponent) => void, data?: any,
config?: MatDialogConfig): Observable<any> {
const modules = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule];
const modules = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule,
this.widgetComponentsModule];
if (Array.isArray(this.customModules)) {
modules.push(...this.customModules);
}

View File

@ -15,7 +15,7 @@
limitations under the License.
-->
<div mat-dialog-content fxLayout="column" style="padding: 0">
<div mat-dialog-content fxLayout="column" style="padding: 0 8px 8px">
<div fxLayout="row" fxLayoutAlign="space-between center">
<span class="tb-no-data-text">{{ 'gateway.docker-label' | translate }}</span>
<div fxFlexAlign="end" class="tb-help" [tb-help]="helpLink"></div>
@ -60,7 +60,8 @@
</div>
<ng-template #commandsExample let-command="command">
<div class="tb-form-panel no-padding no-border tb-tab-body">
<div class="tb-form-panel stroked tb-tab-body">
<div class="tb-form-panel-title" translate>device.connectivity.execute-following-command</div>
<tb-markdown usePlainMarkdown containerClass="start-code"
data="
```bash

View File

@ -26,12 +26,44 @@
overflow: hidden;
white-space: break-spaces;
word-break: break-all;
background: #F3F6FA;
border-color: #305680;
}
.code-wrapper {
padding: 0;
}
button.clipboard-btn {
right: 0;
p {
color: #305680;
}
p, div {
background-color: #F3F6FA;
}
div {
img {
display: none;
}
&:after {
content: "";
position: initial;
display: block;
width: 18px;
height: 18px;
background: #305680;
mask-image: url(/assets/copy-code-icon.svg);
mask-repeat: no-repeat;
}
}
}
}
}
.tb-form-panel.tb-tab-body {
margin-top: 16px;
}
}

View File

@ -15,17 +15,10 @@
limitations under the License.
-->
<mat-toolbar color="primary">
<mat-toolbar color="primary" *ngIf="!dialogRef">
<h2 translate>gateway.gateway-configuration</h2>
<span fxFlex></span>
<button mat-icon-button
type="button"
(click)="cancel()"
*ngIf="dialogRef">
<mat-icon class="material-icons" style="color:#000;">close</mat-icon>
</button>
</mat-toolbar>
<mat-tab-group style="max-height: calc(100% - 117px); height: 100%;" [formGroup]="gatewayConfigGroup">
<mat-tab-group class="tab-group-block" [formGroup]="gatewayConfigGroup">
<mat-tab label="{{ 'gateway.thingsboard-general' | translate }}">
<div formGroupName="thingsboard" class="mat-content mat-padding configuration-block">
<div class="tb-form-panel no-padding-bottom">
@ -713,7 +706,7 @@
</div>
</mat-tab>
</mat-tab-group>
<div mat-dialog-actions fxLayoutAlign="start center">
<div class="actions">
<button mat-button color="primary"
type="button"
*ngIf="dialogRef"

View File

@ -16,8 +16,8 @@
:host {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: min-content minmax(auto, 1fr) min-content;
.configuration-block {
display: flex;
@ -26,10 +26,18 @@
}
.mat-toolbar {
grid-row: 1;
background: transparent;
color: rgba(0, 0, 0, .87) !important;
}
.tab-group-block {
min-width: 0;
height: 100%;
min-height: 0;
grid-row: 2;
}
.toggle-group {
margin-right: auto;
}
@ -45,6 +53,15 @@
.saving-period {
flex: 1;
}
.actions {
grid-row: 3;
padding: 8px;
display: flex;
gap: 8px;
justify-content: flex-end;
flex: 1;
}
}
:host ::ng-deep {

View File

@ -16,7 +16,7 @@
-->
<div class="connector-container tb-form-panel no-border">
<section class="table-container tb-form-panel stroked no-padding flex">
<section class="table-section tb-form-panel no-padding flex section-container">
<mat-toolbar class="mat-mdc-table-toolbar">
<h2>{{ 'gateway.connectors' | translate }}</h2>
<span fxFlex></span>
@ -28,89 +28,64 @@
<mat-icon>add</mat-icon>
</button>
</mat-toolbar>
<table mat-table [dataSource]="dataSource"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()"
matSortDisableClear>
<ng-container matColumnDef="enabled" sticky>
<mat-header-cell *matHeaderCellDef style="width: 60px;min-width: 60px;">
{{ 'gateway.connectors-table-enabled' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute">
<mat-slide-toggle [checked]="activeConnectors.includes(attribute.key)"
(click)="$event.stopPropagation(); enableConnector(attribute)"></mat-slide-toggle>
</mat-cell>
</ng-container>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 40%">
{{ 'gateway.connectors-table-name' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let attribute">
{{ attribute.key }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.connectors-table-type' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
{{ returnType(attribute) }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="syncStatus">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.configuration' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
<div class="status" [class]="isConnectorSynced(attribute) ? 'status-sync' : 'status-unsync'">
{{ isConnectorSynced(attribute) ? 'sync' : 'out of sync' }}
</div>
</mat-cell>
</ng-container>
<ng-container matColumnDef="errors">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.connectors-table-status' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
<span class="dot"
matTooltip="{{ 'Errors: '+ getErrorsCount(attribute)}}"
matTooltipPosition="above"
[class]="{'hasErrors': +getErrorsCount(attribute) > 0,
'noErrors': +getErrorsCount(attribute) === 0 || getErrorsCount(attribute) === ''}"></span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef
[ngStyle.gt-md]="{ minWidth: '144px', maxWidth: '144px', width: '144px'}">
{{ 'gateway.connectors-table-actions' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute"
[ngStyle.gt-md]="{ minWidth: '144px', maxWidth: '144px', width: '144px'}">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-icon-button
matTooltip="RPC"
matTooltipPosition="above"
(click)="connectorRpc(attribute, $event)">
<mat-icon>private_connectivity</mat-icon>
</button>
<button mat-icon-button
matTooltip="Logs"
matTooltipPosition="above"
(click)="connectorLogs(attribute, $event)">
<mat-icon>list</mat-icon>
</button>
<button mat-icon-button
matTooltip="Delete connector"
matTooltipPosition="above"
(click)="deleteConnector(attribute, $event)">
<mat-icon>delete</mat-icon>
</button>
</div>
<div fxHide fxShow.lt-lg>
<button mat-icon-button
(click)="$event.stopPropagation()"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<div class="table-container">
<table mat-table [dataSource]="dataSource"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()"
matSortDisableClear>
<ng-container matColumnDef="enabled" sticky>
<mat-header-cell *matHeaderCellDef style="width: 60px;min-width: 60px;">
{{ 'gateway.connectors-table-enabled' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute">
<mat-slide-toggle [checked]="activeConnectors.includes(attribute.key)"
(click)="$event.stopPropagation(); enableConnector(attribute)"></mat-slide-toggle>
</mat-cell>
</ng-container>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 40%">
{{ 'gateway.connectors-table-name' | translate }}</mat-header-cell>
<mat-cell *matCellDef="let attribute">
{{ attribute.key }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.connectors-table-type' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
{{ returnType(attribute) }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="syncStatus">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.configuration' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
<div class="status" [class]="isConnectorSynced(attribute) ? 'status-sync' : 'status-unsync'">
{{ isConnectorSynced(attribute) ? 'sync' : 'out of sync' }}
</div>
</mat-cell>
</ng-container>
<ng-container matColumnDef="errors">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 30%">
{{ 'gateway.connectors-table-status' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute" style="text-transform: uppercase">
<span class="dot"
matTooltip="{{ 'Errors: '+ getErrorsCount(attribute)}}"
matTooltipPosition="above"
[class]="{'hasErrors': +getErrorsCount(attribute) > 0,
'noErrors': +getErrorsCount(attribute) === 0 || getErrorsCount(attribute) === ''}"></span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef
[ngStyle.gt-md]="{ minWidth: '144px', maxWidth: '144px', width: '144px'}">
{{ 'gateway.connectors-table-actions' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let attribute"
[ngStyle.gt-md]="{ minWidth: '144px', maxWidth: '144px', width: '144px'}">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-icon-button
matTooltip="RPC"
matTooltipPosition="above"
@ -118,7 +93,7 @@
<mat-icon>private_connectivity</mat-icon>
</button>
<button mat-icon-button
matTooltip="Delete connector"
matTooltip="Logs"
matTooltipPosition="above"
(click)="connectorLogs(attribute, $event)">
<mat-icon>list</mat-icon>
@ -129,55 +104,84 @@
(click)="deleteConnector(attribute, $event)">
<mat-icon>delete</mat-icon>
</button>
</mat-menu>
</div>
</mat-cell>
</ng-container>
<mat-header-row class="mat-row-select"
*matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row class="mat-row-select" [class]="{'tb-current-entity': isSameConnector(attribute)}"
*matRowDef="let attribute; columns: displayedColumns;" (click)="selectConnector(attribute)"></mat-row>
</table>
</div>
<div fxHide fxShow.lt-lg>
<button mat-icon-button
(click)="$event.stopPropagation()"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<button mat-icon-button
matTooltip="RPC"
matTooltipPosition="above"
(click)="connectorRpc(attribute, $event)">
<mat-icon>private_connectivity</mat-icon>
</button>
<button mat-icon-button
matTooltip="Delete connector"
matTooltipPosition="above"
(click)="connectorLogs(attribute, $event)">
<mat-icon>list</mat-icon>
</button>
<button mat-icon-button
matTooltip="Delete connector"
matTooltipPosition="above"
(click)="deleteConnector(attribute, $event)">
<mat-icon>delete</mat-icon>
</button>
</mat-menu>
</div>
</mat-cell>
</ng-container>
<mat-header-row class="mat-row-select"
*matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row class="mat-row-select" [class]="{'tb-current-entity': isSameConnector(attribute)}"
*matRowDef="let attribute; columns: displayedColumns;" (click)="selectConnector(attribute)"></mat-row>
</table>
</div>
</section>
<section [formGroup]="connectorForm" class="tb-form-panel no-border no-padding flex">
<section class="tb-form-row tb-not-inline-field same-padding input-container">
<mat-form-field class="flex" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-name' | translate }}</mat-label>
<input matInput formControlName="name" #nameInput/>
</mat-form-field>
<mat-form-field class="flex" subscriptSizing="dynamic" hideRequiredMarker>
<mat-label>{{ 'gateway.connectors-table-type' | translate }}</mat-label>
<mat-select formControlName="type">
<mat-option style="text-transform: uppercase"
*ngFor="let type of gatewayConnectorDefaultTypes | keyvalue" [value]="type.key">{{ type.value }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex" *ngIf="connectorForm.get('type').value === 'grpc'" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-key' | translate }}</mat-label>
<input matInput formControlName="key"/>
</mat-form-field>
<mat-form-field class="flex" *ngIf="connectorForm.get('type').value === 'custom'" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-class' | translate }}</mat-label>
<input matInput formControlName="class"/>
</mat-form-field>
<mat-form-field class="flex" subscriptSizing="dynamic" hideRequiredMarker>
<mat-label translate>gateway.remote-logging-level</mat-label>
<mat-select formControlName="logLevel">
<mat-option *ngFor="let logLevel of gatewayLogLevel" [value]="logLevel">{{ logLevel }}</mat-option>
</mat-select>
</mat-form-field>
<section class="tb-form-panel input-container section-container">
<section class="tb-form-row tb-not-inline-field no-padding no-border column-lt-md input-container">
<mat-form-field class="flex" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-name' | translate }}</mat-label>
<input matInput formControlName="name" #nameInput/>
</mat-form-field>
<mat-form-field class="flex" subscriptSizing="dynamic" hideRequiredMarker>
<mat-label>{{ 'gateway.connectors-table-type' | translate }}</mat-label>
<mat-select formControlName="type">
<mat-option style="text-transform: uppercase"
*ngFor="let type of gatewayConnectorDefaultTypes | keyvalue" [value]="type.key">{{ type.value }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex" *ngIf="connectorForm.get('type').value === 'grpc'" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-key' | translate }}</mat-label>
<input matInput formControlName="key"/>
</mat-form-field>
<mat-form-field class="flex" *ngIf="connectorForm.get('type').value === 'custom'" subscriptSizing="dynamic">
<mat-label>{{ 'gateway.connectors-table-class' | translate }}</mat-label>
<input matInput formControlName="class"/>
</mat-form-field>
<mat-form-field class="flex" subscriptSizing="dynamic" hideRequiredMarker>
<mat-label translate>gateway.remote-logging-level</mat-label>
<mat-select formControlName="logLevel">
<mat-option *ngFor="let logLevel of gatewayLogLevel" [value]="logLevel">{{ logLevel }}</mat-option>
</mat-select>
</mat-form-field>
</section>
</section>
<section class="tb-form-panel stroked flex">
<section class="tb-form-panel flex section-container">
<tb-json-object-edit
fillHeight="true"
class="flex"
fxLayout="column"
required
label="{{ 'gateway.configuration' | translate }}"
formControlName="configurationJson">
</tb-json-object-edit>
<div fxLayoutAlign="start center">
<div fxLayoutAlign="end center">
<button mat-raised-button color="primary"
class="action-button"
type="button"
[disabled]="!connectorForm.dirty || connectorForm.invalid"
(click)="saveConnector()">

View File

@ -30,9 +30,13 @@
flex-direction: column;
}
.table-container {
overflow: auto;
.table-section {
min-height: 35vh;
overflow: hidden;
.table-container {
overflow: auto;
}
}
.flex {
@ -42,6 +46,10 @@
.input-container {
height: auto;
}
.section-container {
background-color: #fff;
}
}
.mat-toolbar {
@ -69,10 +77,6 @@
}
}
.action-button {
margin: 0 15px;
}
mat-row {
cursor: pointer;
}