From fa8decd29313bc9100bb7fe3a2f3f4279f7229fc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 25 May 2023 17:38:26 +0300 Subject: [PATCH 1/5] UI: Fixed timewindows writeValue is being called twice, first time with a phantom null value --- .../dashboard-page.component.html | 1 + .../entity/entities-table.component.html | 8 +- .../entity/entities-table.component.ts | 18 +-- .../components/event/event-table.component.ts | 13 +- .../widget/widget-container.component.html | 1 + .../components/time/timewindow.component.html | 2 +- .../components/time/timewindow.component.ts | 118 ++++++------------ 7 files changed, 66 insertions(+), 95 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 6a9ce1f657..fd827c7f55 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -107,6 +107,7 @@ tooltipPosition="below" aggregation="true" timezone="true" + isNgModel [(ngModel)]="dashboardCtx.dashboardTimewindow"> {{ entitiesTableConfig.tableTitle }} - + +
diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index b868fd1e47..43bc451c49 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -24,6 +24,7 @@ import { EventEmitter, Input, OnChanges, + OnDestroy, OnInit, SimpleChanges, ViewChild @@ -72,7 +73,7 @@ import { EntityDetailsPanelComponent } from '@home/components/entity/entity-deta styleUrls: ['./entities-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges { +export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges, OnDestroy { @Input() entitiesTableConfig: EntityTableConfig>; @@ -162,6 +163,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } ngOnDestroy() { + super.ngOnDestroy(); if (this.widgetResize$) { this.widgetResize$.disconnect(); } @@ -366,12 +368,10 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa ); if (this.displayPagination) { paginatorSubscription$ = this.paginator.page.asObservable().pipe( - map((data) => { - return { - page: data.pageIndex === 0 ? null : data.pageIndex, - pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize - }; - }) + map((data) => ({ + page: data.pageIndex === 0 ? null : data.pageIndex, + pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize + })) ); } this.updateDataSubscription = ((this.displayPagination ? merge(sortSubscription$, paginatorSubscription$) @@ -421,8 +421,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } } - private getTimePageLinkInterval(): {startTime?: number, endTime?: number} { - const interval: {startTime?: number, endTime?: number} = {}; + private getTimePageLinkInterval(): {startTime?: number; endTime?: number} { + const interval: {startTime?: number; endTime?: number} = {}; switch (this.timewindow.history.historyType) { case HistoryWindowType.LAST_INTERVAL: const currentTime = Date.now(); diff --git a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts index bce66fc3c1..fbdd0a07da 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; import { MatDialog } from '@angular/material/dialog'; @@ -32,7 +41,7 @@ import { Subscription } from 'rxjs'; templateUrl: './event-table.component.html', styleUrls: ['./event-table.component.scss'] }) -export class EventTableComponent implements OnInit, AfterViewInit { +export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy { @Input() tenantId: string; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 23082a121b..f173b103eb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -50,6 +50,7 @@ historyOnly="{{widget.onlyHistoryTimewindow}}" alwaysDisplayTypePrefix timezone="true" + isNgModel [isEdit]="isEdit" [(ngModel)]="widgetComponent.widget.config.timewindow" (ngModelChange)="widgetComponent.onTimewindowChanged($event)"> diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.html b/ui-ngx/src/app/shared/components/time/timewindow.component.html index a9d5ce0eaa..fee59f289f 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.html @@ -46,7 +46,7 @@ (click)="toggleTimewindow($event)" matTooltip="{{ 'timewindow.edit' | translate }}" [matTooltipPosition]="tooltipPosition"> - {{innerValue?.displayValue}} | {{innerValue.displayTimezoneAbbr}} + {{innerValue?.displayValue}} | {{innerValue?.displayTimezoneAbbr}}
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index f173b103eb..23082a121b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -50,7 +50,6 @@ historyOnly="{{widget.onlyHistoryTimewindow}}" alwaysDisplayTypePrefix timezone="true" - isNgModel [isEdit]="isEdit" [(ngModel)]="widgetComponent.widget.config.timewindow" (ngModelChange)="widgetComponent.onTimewindowChanged($event)"> diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index 933cafe0ca..777c286c1d 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -117,10 +117,6 @@ export class TimewindowComponent implements ControlValueAccessor { @coerceBoolean() strokedButton = false; - @Input() - @coerceBoolean() - isNgModel = false; - isEditValue = false; @Input() @@ -149,8 +145,6 @@ export class TimewindowComponent implements ControlValueAccessor { private propagateChange = (_: any) => {}; - private _isControlInitialized = false; - constructor(private overlay: Overlay, private translate: TranslateService, private timeService: TimeService, @@ -229,7 +223,6 @@ export class TimewindowComponent implements ControlValueAccessor { registerOnChange(fn: any): void { this.propagateChange = fn; - this._isControlInitialized = true; } registerOnTouched(fn: any): void { @@ -241,16 +234,14 @@ export class TimewindowComponent implements ControlValueAccessor { } writeValue(obj: Timewindow): void { - if (this._isControlInitialized || !this.isNgModel) { - this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.timeService); - this.timewindowDisabled = this.isTimewindowDisabled(); - if (this.onHistoryOnlyChanged()) { - setTimeout(() => { - this.notifyChanged(); - }); - } else { - this.updateDisplayValue(); - } + this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.timeService, this.historyOnly); + this.timewindowDisabled = this.isTimewindowDisabled(); + if (this.onHistoryOnlyChanged()) { + setTimeout(() => { + this.notifyChanged(); + }); + } else { + this.updateDisplayValue(); } } diff --git a/ui-ngx/src/app/shared/models/time/time.models.ts b/ui-ngx/src/app/shared/models/time/time.models.ts index 3e87150f87..68c7a12436 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -245,7 +245,8 @@ const getTimewindowType = (timewindow: Timewindow): TimewindowType => { } }; -export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalOnly: boolean, timeService: TimeService): Timewindow => { +export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalOnly: boolean, + timeService: TimeService, historyOnly: boolean): Timewindow => { const model = defaultTimewindow(timeService); if (value) { model.hideInterval = value.hideInterval; @@ -316,6 +317,9 @@ export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalO if (quickIntervalOnly) { model.realtime.realtimeType = RealtimeWindowType.INTERVAL; } + if (historyOnly) { + model.selectedTab = TimewindowType.HISTORY; + } return model; }; From 6ccc21632dbfa1bc237fb869111c2aebec93a563 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 26 May 2023 13:39:15 +0300 Subject: [PATCH 3/5] Add upgrade script to fix dashboard templates after Angular migration to ver.15 --- .../main/data/upgrade/3.5.0/schema_update.sql | 23 +++++++++++++++++++ .../install/ThingsboardInstallService.java | 1 + .../install/SqlDatabaseUpgradeService.java | 13 +++++++++++ 3 files changed, 37 insertions(+) create mode 100644 application/src/main/data/upgrade/3.5.0/schema_update.sql diff --git a/application/src/main/data/upgrade/3.5.0/schema_update.sql b/application/src/main/data/upgrade/3.5.0/schema_update.sql new file mode 100644 index 0000000000..321112c4eb --- /dev/null +++ b/application/src/main/data/upgrade/3.5.0/schema_update.sql @@ -0,0 +1,23 @@ +-- +-- Copyright © 2016-2023 The Thingsboard Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +-- FIX DASHBOARD TEMPLATES AFTER ANGULAR MIGRATION TO VER.15 + +UPDATE dashboard SET configuration = REPLACE(configuration, 'mat-button mat-icon-button', 'mat-icon-button') + WHERE configuration like '%mat-button mat-icon-button%'; + +UPDATE widget_type SET descriptor = REPLACE(descriptor, 'mat-button mat-icon-button', 'mat-icon-button') + WHERE descriptor like '%mat-button mat-icon-button%'; diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 04f0cc78c8..781f01c844 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -256,6 +256,7 @@ public class ThingsboardInstallService { } case "3.5.0": log.info("Upgrading ThingsBoard from version 3.5.0 to 3.5.1 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.5.0"); //TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache break; default: diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 504b058879..f79e0dca08 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -713,6 +713,19 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.5.0": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + if (isOldSchema(conn, 3005000)) { + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.5.0", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3005001;"); + } + log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } From dbb5a8cc8b4448f7c1cd7084ceee10fde339148c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 26 May 2023 16:45:29 +0300 Subject: [PATCH 4/5] UI: Improve custom dialog error diagnostics. Improve widget error message formatting. --- .../src/app/core/services/dialog.service.ts | 18 +++++++ ui-ngx/src/app/core/services/utils.service.ts | 4 ++ .../custom-dialog-container.component.ts | 18 ++++++- .../components/widget/widget.component.html | 2 +- .../pages/widget/widget-editor.component.ts | 3 -- .../dialog/alert-dialog.component.html | 2 +- .../dialog/error-alert-dialog.component.html | 30 ++++++++++++ .../dialog/error-alert-dialog.component.scss | 37 ++++++++++++++ .../dialog/error-alert-dialog.component.ts | 49 +++++++++++++++++++ .../components/snack-bar-component.scss | 2 +- ui-ngx/src/app/shared/shared.module.ts | 3 ++ .../assets/locale/locale.constant-en_US.json | 10 +++- 12 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.scss create mode 100644 ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.ts diff --git a/ui-ngx/src/app/core/services/dialog.service.ts b/ui-ngx/src/app/core/services/dialog.service.ts index 6d664085b1..be0c24a958 100644 --- a/ui-ngx/src/app/core/services/dialog.service.ts +++ b/ui-ngx/src/app/core/services/dialog.service.ts @@ -29,6 +29,7 @@ import { } from '@shared/components/dialog/material-icons-dialog.component'; import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component'; import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component'; +import { ErrorAlertDialogComponent } from '@shared/components/dialog/error-alert-dialog.component'; import { TodoDialogComponent } from '@shared/components/dialog/todo-dialog.component'; @Injectable( @@ -78,6 +79,23 @@ export class DialogService { return dialogRef.afterClosed(); } + errorAlert(title: string, message: string, error: any, ok: string = null, fullscreen: boolean = false): Observable { + const dialogConfig: MatDialogConfig = { + disableClose: true, + data: { + title, + message, + error, + ok: ok || this.translate.instant('action.ok') + } + }; + if (fullscreen) { + dialogConfig.panelClass = ['tb-fullscreen-dialog']; + } + const dialogRef = this.dialog.open(ErrorAlertDialogComponent, dialogConfig); + return dialogRef.afterClosed(); + } + colorPicker(color: string): Observable { return this.dialog.open(ColorPickerDialogComponent, { diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index 813127cbc5..f82c6c3072 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -188,6 +188,10 @@ export class UtilsService { public processWidgetException(exception: any): ExceptionData { const data = this.parseException(exception, -6); + if (data.message?.startsWith('NG0')) { + data.message = `${this.translate.instant('widget.widget-template-error')}
+
${this.translate.instant('dialog.error-message-title')}

${data.message}`; + } if (this.widgetEditMode) { const message: WindowMessage = { type: 'widgetException', diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts index d9ab65813f..dc3e9c7ac2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts @@ -33,6 +33,8 @@ import { CustomDialogComponent, CustomDialogData } from '@home/components/widget/dialog/custom-dialog.component'; +import { DialogService } from '@core/services/dialog.service'; +import { TranslateService } from '@ngx-translate/core'; export interface CustomDialogContainerData { controller: (instance: CustomDialogComponent) => void; @@ -54,6 +56,8 @@ export class CustomDialogContainerComponent extends DialogComponent, + private dialogService: DialogService, + private translate: TranslateService, @Inject(MAT_DIALOG_DATA) public data: CustomDialogContainerData) { super(store, router, dialogRef); let customDialogData: CustomDialogData = { @@ -72,7 +76,19 @@ export class CustomDialogContainerComponent extends DialogComponent
- Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}} +

{{data.title}}

-
+
diff --git a/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html new file mode 100644 index 0000000000..8554a3d707 --- /dev/null +++ b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html @@ -0,0 +1,30 @@ + +

{{title}}

+
+
{{ message }}
+
dialog.error-message-title
+
{{ errorMessage }}
+ + {{ 'dialog.error-details-title' | translate }} + + +
+
+ +
diff --git a/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.scss new file mode 100644 index 0000000000..3ca391dbcd --- /dev/null +++ b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.scss @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .mat-mdc-dialog-content { + padding: 0 24px 24px; + } + .tb-error-alert-dialog-content { + .error-message-title { + font-style: italic; + } + .error-message-content { + color: red; + } + .error-details-content { + display: block; + border: solid 1px #d3d3d3; + padding: 8px; + border-radius: 4px; + } + & > *:not(:last-child) { + padding-bottom: 16px; + } + } +} diff --git a/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.ts new file mode 100644 index 0000000000..8ef9032421 --- /dev/null +++ b/ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.ts @@ -0,0 +1,49 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +export interface ErrorAlertDialogData { + title: string; + message: string; + error: any; + ok: string; +} + +@Component({ + selector: 'tb-error-alert-dialog', + templateUrl: './error-alert-dialog.component.html', + styleUrls: ['./error-alert-dialog.component.scss'] +}) +export class ErrorAlertDialogComponent { + + title: string; + message: string; + errorMessage: string; + errorDetails?: string; + + constructor(public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: ErrorAlertDialogData) { + this.title = this.data.title; + this.message = this.data.message; + this.errorMessage = this.data.error.message ? this.data.error.message : JSON.stringify(this.data.error); + if (this.data.error.stack) { + this.errorDetails = this.data.error.stack.replaceAll('\n', '
'); + } + } + +} diff --git a/ui-ngx/src/app/shared/components/snack-bar-component.scss b/ui-ngx/src/app/shared/components/snack-bar-component.scss index 8832604510..b2db177e06 100644 --- a/ui-ngx/src/app/shared/components/snack-bar-component.scss +++ b/ui-ngx/src/app/shared/components/snack-bar-component.scss @@ -51,7 +51,7 @@ padding: 0 18px; margin: 8px; .toast-text { - padding: 0 6px; + padding: 8px; width: 100%; } button { diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 9bd9006399..60877bd20d 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -123,6 +123,7 @@ import { JsFuncComponent } from '@shared/components/js-func.component'; import { JsonFormComponent } from '@shared/components/json-form/json-form.component'; import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component'; import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component'; +import { ErrorAlertDialogComponent } from '@shared/components/dialog/error-alert-dialog.component'; import { TodoDialogComponent } from '@shared/components/dialog/todo-dialog.component'; import { MaterialIconsDialogComponent } from '@shared/components/dialog/material-icons-dialog.component'; import { MaterialIconSelectComponent } from '@shared/components/material-icon-select.component'; @@ -305,6 +306,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetsBundleSelectComponent, ConfirmDialogComponent, AlertDialogComponent, + ErrorAlertDialogComponent, TodoDialogComponent, ColorPickerDialogComponent, MaterialIconsDialogComponent, @@ -528,6 +530,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) MarkdownModule, ConfirmDialogComponent, AlertDialogComponent, + ErrorAlertDialogComponent, TodoDialogComponent, ColorPickerDialogComponent, MaterialIconsDialogComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index bcaa4a183f..c9d236bf2a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1789,7 +1789,9 @@ } }, "dialog": { - "close": "Close dialog" + "close": "Close dialog", + "error-message-title": "Error message:", + "error-details-title": "Error details" }, "direction": { "column": "Column", @@ -3991,7 +3993,8 @@ "alarm-data-overflow": "Widget displays alarms for {{allowedEntities}} (maximum allowed) entities out of {{totalEntities}} entities", "search": "Search widget", "filter": "Widget filter type", - "loading-widgets": "Loading widgets..." + "loading-widgets": "Loading widgets...", + "widget-template-error": "Invalid widget HTML template." }, "widget-action": { "header-button": "Widget header button", @@ -4000,6 +4003,9 @@ "open-dashboard": "Navigate to other dashboard", "custom": "Custom action", "custom-pretty": "Custom action (with HTML template)", + "custom-pretty-error-title": "Custom dialog error", + "custom-pretty-template-error": "Invalid custom dialog template.", + "custom-pretty-controller-error": "Error occurred while evaluating custom dialog function.", "mobile-action": "Mobile action", "target-dashboard-state": "Target dashboard state", "target-dashboard-state-required": "Target dashboard state is required", From fdd6ebcb2c2bd54ee6e0869aacf476bf9a1a78d2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 26 May 2023 16:57:50 +0300 Subject: [PATCH 5/5] UI: Revert unnessery changes and change function order --- .../core/services/dashboard-utils.service.ts | 6 +++--- .../entity/entities-table.component.html | 8 +++----- .../entity/entities-table.component.ts | 18 +++++++++--------- .../components/time/timewindow.component.ts | 2 +- .../src/app/shared/models/time/time.models.ts | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 66c376bc2a..5a112f8336 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -235,7 +235,7 @@ export class DashboardUtilsService { }); if (type === widgetType.latest) { const onlyHistoryTimewindow = datasourcesHasOnlyComparisonAggregation(widgetConfig.datasources); - widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, this.timeService, onlyHistoryTimewindow); + widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, onlyHistoryTimewindow, this.timeService); } if (type === widgetType.alarm) { if (!widgetConfig.alarmFilterConfig) { @@ -429,7 +429,7 @@ export class DashboardUtilsService { targetLayout: DashboardLayoutId, widget: Widget, originalColumns?: number, - originalSize?: {sizeX: number; sizeY: number}, + originalSize?: {sizeX: number, sizeY: number}, row?: number, column?: number): void { const dashboardConfiguration = dashboard.configuration; @@ -502,7 +502,7 @@ export class DashboardUtilsService { this.removeUnusedWidgets(dashboard); } - public isSingleLayoutDashboard(dashboard: Dashboard): {state: string; layout: DashboardLayoutId} { + public isSingleLayoutDashboard(dashboard: Dashboard): {state: string, layout: DashboardLayoutId} { const dashboardConfiguration = dashboard.configuration; const states = dashboardConfiguration.states; const stateKeys = Object.keys(states); diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index a69c949327..f07010854c 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -40,11 +40,9 @@
{{ entitiesTableConfig.tableTitle }} - - +
diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index 43bc451c49..b868fd1e47 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -24,7 +24,6 @@ import { EventEmitter, Input, OnChanges, - OnDestroy, OnInit, SimpleChanges, ViewChild @@ -73,7 +72,7 @@ import { EntityDetailsPanelComponent } from '@home/components/entity/entity-deta styleUrls: ['./entities-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges, OnDestroy { +export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges { @Input() entitiesTableConfig: EntityTableConfig>; @@ -163,7 +162,6 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } ngOnDestroy() { - super.ngOnDestroy(); if (this.widgetResize$) { this.widgetResize$.disconnect(); } @@ -368,10 +366,12 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa ); if (this.displayPagination) { paginatorSubscription$ = this.paginator.page.asObservable().pipe( - map((data) => ({ - page: data.pageIndex === 0 ? null : data.pageIndex, - pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize - })) + map((data) => { + return { + page: data.pageIndex === 0 ? null : data.pageIndex, + pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize + }; + }) ); } this.updateDataSubscription = ((this.displayPagination ? merge(sortSubscription$, paginatorSubscription$) @@ -421,8 +421,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } } - private getTimePageLinkInterval(): {startTime?: number; endTime?: number} { - const interval: {startTime?: number; endTime?: number} = {}; + private getTimePageLinkInterval(): {startTime?: number, endTime?: number} { + const interval: {startTime?: number, endTime?: number} = {}; switch (this.timewindow.history.historyType) { case HistoryWindowType.LAST_INTERVAL: const currentTime = Date.now(); diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index 777c286c1d..9f193ab103 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -234,7 +234,7 @@ export class TimewindowComponent implements ControlValueAccessor { } writeValue(obj: Timewindow): void { - this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.timeService, this.historyOnly); + this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.historyOnly, this.timeService); this.timewindowDisabled = this.isTimewindowDisabled(); if (this.onHistoryOnlyChanged()) { setTimeout(() => { diff --git a/ui-ngx/src/app/shared/models/time/time.models.ts b/ui-ngx/src/app/shared/models/time/time.models.ts index 68c7a12436..fd2b4f52fa 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -246,7 +246,7 @@ const getTimewindowType = (timewindow: Timewindow): TimewindowType => { }; export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalOnly: boolean, - timeService: TimeService, historyOnly: boolean): Timewindow => { + historyOnly: boolean, timeService: TimeService): Timewindow => { const model = defaultTimewindow(timeService); if (value) { model.hideInterval = value.hideInterval;