Merge with develop/3.5.2
This commit is contained in:
commit
36f1cd00e7
23
application/src/main/data/upgrade/3.5.0/schema_update.sql
Normal file
23
application/src/main/data/upgrade/3.5.0/schema_update.sql
Normal file
@ -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%';
|
||||||
@ -256,6 +256,7 @@ public class ThingsboardInstallService {
|
|||||||
}
|
}
|
||||||
case "3.5.0":
|
case "3.5.0":
|
||||||
log.info("Upgrading ThingsBoard from version 3.5.0 to 3.5.1 ...");
|
log.info("Upgrading ThingsBoard from version 3.5.0 to 3.5.1 ...");
|
||||||
|
databaseEntitiesUpgradeService.upgradeDatabase("3.5.0");
|
||||||
case "3.5.1":
|
case "3.5.1":
|
||||||
log.info("Upgrading ThingsBoard from version 3.5.1 to 3.5.2 ...");
|
log.info("Upgrading ThingsBoard from version 3.5.1 to 3.5.2 ...");
|
||||||
databaseEntitiesUpgradeService.upgradeDatabase("3.5.1");
|
databaseEntitiesUpgradeService.upgradeDatabase("3.5.1");
|
||||||
|
|||||||
@ -714,10 +714,23 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
|
|||||||
log.error("Failed updating schema!!!", e);
|
log.error("Failed updating schema!!!", e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "3.5.1":
|
case "3.5.0":
|
||||||
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
||||||
log.info("Updating schema ...");
|
log.info("Updating schema ...");
|
||||||
if (isOldSchema(conn, 3005000)) {
|
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;
|
||||||
|
case "3.5.1":
|
||||||
|
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
||||||
|
log.info("Updating schema ...");
|
||||||
|
if (isOldSchema(conn, 3005001)) {
|
||||||
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.5.1", SCHEMA_UPDATE_SQL);
|
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.5.1", SCHEMA_UPDATE_SQL);
|
||||||
loadSql(schemaUpdateFile, conn);
|
loadSql(schemaUpdateFile, conn);
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import {
|
|||||||
import { isDefined, isDefinedAndNotNull, isString, isUndefined } from '@core/utils';
|
import { isDefined, isDefinedAndNotNull, isString, isUndefined } from '@core/utils';
|
||||||
import {
|
import {
|
||||||
Datasource,
|
Datasource,
|
||||||
|
datasourcesHasOnlyComparisonAggregation,
|
||||||
DatasourceType,
|
DatasourceType,
|
||||||
defaultLegendConfig,
|
defaultLegendConfig,
|
||||||
Widget,
|
Widget,
|
||||||
@ -249,7 +250,8 @@ export class DashboardUtilsService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (type === widgetType.latest) {
|
if (type === widgetType.latest) {
|
||||||
widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, this.timeService);
|
const onlyHistoryTimewindow = datasourcesHasOnlyComparisonAggregation(widgetConfig.datasources);
|
||||||
|
widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, onlyHistoryTimewindow, this.timeService);
|
||||||
}
|
}
|
||||||
if (type === widgetType.alarm) {
|
if (type === widgetType.alarm) {
|
||||||
if (!widgetConfig.alarmFilterConfig) {
|
if (!widgetConfig.alarmFilterConfig) {
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import {
|
|||||||
} from '@shared/components/dialog/material-icons-dialog.component';
|
} from '@shared/components/dialog/material-icons-dialog.component';
|
||||||
import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component';
|
||||||
import { AlertDialogComponent } from '@shared/components/dialog/alert-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 { TodoDialogComponent } from '@shared/components/dialog/todo-dialog.component';
|
||||||
|
|
||||||
@Injectable(
|
@Injectable(
|
||||||
@ -78,6 +79,23 @@ export class DialogService {
|
|||||||
return dialogRef.afterClosed();
|
return dialogRef.afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errorAlert(title: string, message: string, error: any, ok: string = null, fullscreen: boolean = false): Observable<any> {
|
||||||
|
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<string> {
|
colorPicker(color: string): Observable<string> {
|
||||||
return this.dialog.open<ColorPickerDialogComponent, ColorPickerDialogData, string>(ColorPickerDialogComponent,
|
return this.dialog.open<ColorPickerDialogComponent, ColorPickerDialogData, string>(ColorPickerDialogComponent,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -188,6 +188,10 @@ export class UtilsService {
|
|||||||
|
|
||||||
public processWidgetException(exception: any): ExceptionData {
|
public processWidgetException(exception: any): ExceptionData {
|
||||||
const data = this.parseException(exception, -6);
|
const data = this.parseException(exception, -6);
|
||||||
|
if (data.message?.startsWith('NG0')) {
|
||||||
|
data.message = `${this.translate.instant('widget.widget-template-error')}<br/>
|
||||||
|
<br/><i>${this.translate.instant('dialog.error-message-title')}</i><br/><br/>${data.message}`;
|
||||||
|
}
|
||||||
if (this.widgetEditMode) {
|
if (this.widgetEditMode) {
|
||||||
const message: WindowMessage = {
|
const message: WindowMessage = {
|
||||||
type: 'widgetException',
|
type: 'widgetException',
|
||||||
|
|||||||
@ -14,7 +14,16 @@
|
|||||||
/// limitations under the License.
|
/// 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 { TranslateService } from '@ngx-translate/core';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@ -32,7 +41,7 @@ import { Subscription } from 'rxjs';
|
|||||||
templateUrl: './event-table.component.html',
|
templateUrl: './event-table.component.html',
|
||||||
styleUrls: ['./event-table.component.scss']
|
styleUrls: ['./event-table.component.scss']
|
||||||
})
|
})
|
||||||
export class EventTableComponent implements OnInit, AfterViewInit {
|
export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
tenantId: string;
|
tenantId: string;
|
||||||
|
|||||||
@ -33,6 +33,8 @@ import {
|
|||||||
CustomDialogComponent,
|
CustomDialogComponent,
|
||||||
CustomDialogData
|
CustomDialogData
|
||||||
} from '@home/components/widget/dialog/custom-dialog.component';
|
} from '@home/components/widget/dialog/custom-dialog.component';
|
||||||
|
import { DialogService } from '@core/services/dialog.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
export interface CustomDialogContainerData {
|
export interface CustomDialogContainerData {
|
||||||
controller: (instance: CustomDialogComponent) => void;
|
controller: (instance: CustomDialogComponent) => void;
|
||||||
@ -54,6 +56,8 @@ export class CustomDialogContainerComponent extends DialogComponent<CustomDialog
|
|||||||
protected router: Router,
|
protected router: Router,
|
||||||
public viewContainerRef: ViewContainerRef,
|
public viewContainerRef: ViewContainerRef,
|
||||||
public dialogRef: MatDialogRef<CustomDialogContainerComponent>,
|
public dialogRef: MatDialogRef<CustomDialogContainerComponent>,
|
||||||
|
private dialogService: DialogService,
|
||||||
|
private translate: TranslateService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: CustomDialogContainerData) {
|
@Inject(MAT_DIALOG_DATA) public data: CustomDialogContainerData) {
|
||||||
super(store, router, dialogRef);
|
super(store, router, dialogRef);
|
||||||
let customDialogData: CustomDialogData = {
|
let customDialogData: CustomDialogData = {
|
||||||
@ -72,7 +76,19 @@ export class CustomDialogContainerComponent extends DialogComponent<CustomDialog
|
|||||||
useValue: dialogRef
|
useValue: dialogRef
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
this.customComponentRef = this.viewContainerRef.createComponent(this.data.customComponentFactory, 0, injector);
|
try {
|
||||||
|
this.customComponentRef = this.viewContainerRef.createComponent(this.data.customComponentFactory, 0, injector);
|
||||||
|
} catch (e: any) {
|
||||||
|
let message;
|
||||||
|
if (e.message?.startsWith('NG0')) {
|
||||||
|
message = this.translate.instant('widget-action.custom-pretty-template-error');
|
||||||
|
} else {
|
||||||
|
message = this.translate.instant('widget-action.custom-pretty-controller-error');
|
||||||
|
}
|
||||||
|
dialogRef.close();
|
||||||
|
console.error(e);
|
||||||
|
this.dialogService.errorAlert(this.translate.instant('widget-action.custom-pretty-error-title'), message, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-absolute-fill tb-widget-error" *ngIf="widgetErrorData">
|
<div class="tb-absolute-fill tb-widget-error" *ngIf="widgetErrorData">
|
||||||
<span>Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}</span>
|
<span [innerHtml]="('Widget Error:<br/><br/>' + widgetErrorData.message) | safe:'html'"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-absolute-fill tb-widget-no-data" *ngIf="displayNoData">
|
<div class="tb-absolute-fill tb-widget-no-data" *ngIf="displayNoData">
|
||||||
<span fxLayoutAlign="center center"
|
<span fxLayoutAlign="center center"
|
||||||
|
|||||||
@ -489,9 +489,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
|
|||||||
if (!this.gotError) {
|
if (!this.gotError) {
|
||||||
this.gotError = true;
|
this.gotError = true;
|
||||||
let errorInfo = 'Error:';
|
let errorInfo = 'Error:';
|
||||||
if (details.name) {
|
|
||||||
errorInfo += ' ' + details.name + ':';
|
|
||||||
}
|
|
||||||
if (details.message) {
|
if (details.message) {
|
||||||
errorInfo += ' ' + details.message;
|
errorInfo += ' ' + details.message;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<h2 mat-dialog-title>{{data.title}}</h2>
|
<h2 mat-dialog-title>{{data.title}}</h2>
|
||||||
<div mat-dialog-content [innerHTML]="data.message"></div>
|
<div mat-dialog-content [innerHTML]="data.message | safe:'html'"></div>
|
||||||
<div mat-dialog-actions fxLayoutAlign="end center">
|
<div mat-dialog-actions fxLayoutAlign="end center">
|
||||||
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
|
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<h2 mat-dialog-title>{{title}}</h2>
|
||||||
|
<div mat-dialog-content class="tb-error-alert-dialog-content">
|
||||||
|
<div>{{ message }}</div>
|
||||||
|
<div class="error-message-title" translate>dialog.error-message-title</div>
|
||||||
|
<div class="error-message-content"> {{ errorMessage }} </div>
|
||||||
|
<mat-expansion-panel *ngIf="errorDetails">
|
||||||
|
<mat-expansion-panel-header>{{ 'dialog.error-details-title' | translate }}</mat-expansion-panel-header>
|
||||||
|
<small class="error-details-content" [innerHTML]="errorDetails"></small>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions fxLayoutAlign="end center">
|
||||||
|
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
|
||||||
|
</div>
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<ErrorAlertDialogComponent>,
|
||||||
|
@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', '<br/>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -51,7 +51,7 @@
|
|||||||
padding: 0 18px;
|
padding: 0 18px;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
.toast-text {
|
.toast-text {
|
||||||
padding: 0 6px;
|
padding: 8px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
(click)="toggleTimewindow($event)"
|
(click)="toggleTimewindow($event)"
|
||||||
matTooltip="{{ 'timewindow.edit' | translate }}"
|
matTooltip="{{ 'timewindow.edit' | translate }}"
|
||||||
[matTooltipPosition]="tooltipPosition">
|
[matTooltipPosition]="tooltipPosition">
|
||||||
{{innerValue?.displayValue}} <span [fxShow]="innerValue?.displayTimezoneAbbr !== ''">| <span class="timezone-abbr">{{innerValue.displayTimezoneAbbr}}</span></span>
|
{{innerValue?.displayValue}} <span [fxShow]="innerValue?.displayTimezoneAbbr !== ''">| <span class="timezone-abbr">{{innerValue?.displayTimezoneAbbr}}</span></span>
|
||||||
</span>
|
</span>
|
||||||
<button *ngIf="direction === 'right'" [disabled]="timewindowDisabled" mat-icon-button class="tb-mat-32"
|
<button *ngIf="direction === 'right'" [disabled]="timewindowDisabled" mat-icon-button class="tb-mat-32"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -21,8 +21,6 @@ import {
|
|||||||
forwardRef,
|
forwardRef,
|
||||||
Injector,
|
Injector,
|
||||||
Input,
|
Input,
|
||||||
OnDestroy,
|
|
||||||
OnInit,
|
|
||||||
StaticProvider,
|
StaticProvider,
|
||||||
ViewContainerRef
|
ViewContainerRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
@ -66,7 +64,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAccessor {
|
export class TimewindowComponent implements ControlValueAccessor {
|
||||||
|
|
||||||
historyOnlyValue = false;
|
historyOnlyValue = false;
|
||||||
|
|
||||||
@ -89,60 +87,29 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
@coerceBoolean()
|
@coerceBoolean()
|
||||||
forAllTimeEnabled = false;
|
forAllTimeEnabled = false;
|
||||||
|
|
||||||
alwaysDisplayTypePrefixValue = false;
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
alwaysDisplayTypePrefix = false;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set alwaysDisplayTypePrefix(val) {
|
@coerceBoolean()
|
||||||
this.alwaysDisplayTypePrefixValue = coerceBooleanProperty(val);
|
quickIntervalOnly = false;
|
||||||
}
|
|
||||||
|
|
||||||
get alwaysDisplayTypePrefix() {
|
|
||||||
return this.alwaysDisplayTypePrefixValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
quickIntervalOnlyValue = false;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set quickIntervalOnly(val) {
|
@coerceBoolean()
|
||||||
this.quickIntervalOnlyValue = coerceBooleanProperty(val);
|
aggregation = false;
|
||||||
}
|
|
||||||
|
|
||||||
get quickIntervalOnly() {
|
|
||||||
return this.quickIntervalOnlyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
aggregationValue = false;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set aggregation(val) {
|
@coerceBoolean()
|
||||||
this.aggregationValue = coerceBooleanProperty(val);
|
timezone = false;
|
||||||
}
|
|
||||||
|
|
||||||
get aggregation() {
|
|
||||||
return this.aggregationValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
timezoneValue = false;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set timezone(val) {
|
@coerceBoolean()
|
||||||
this.timezoneValue = coerceBooleanProperty(val);
|
isToolbar = false;
|
||||||
}
|
|
||||||
|
|
||||||
get timezone() {
|
|
||||||
return this.timezoneValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
asButtonValue = false;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set asButton(val) {
|
@coerceBoolean()
|
||||||
this.asButtonValue = coerceBooleanProperty(val);
|
asButton = false;
|
||||||
}
|
|
||||||
|
|
||||||
get asButton() {
|
|
||||||
return this.asButtonValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@coerceBoolean()
|
@coerceBoolean()
|
||||||
@ -178,7 +145,9 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
@Input()
|
@Input()
|
||||||
tooltipPosition: TooltipPosition = 'above';
|
tooltipPosition: TooltipPosition = 'above';
|
||||||
|
|
||||||
@Input() disabled: boolean;
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
innerValue: Timewindow;
|
innerValue: Timewindow;
|
||||||
|
|
||||||
@ -196,12 +165,6 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
public viewContainerRef: ViewContainerRef) {
|
public viewContainerRef: ViewContainerRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleTimewindow($event: Event) {
|
toggleTimewindow($event: Event) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
@ -213,7 +176,6 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
maxHeight: '80vh',
|
maxHeight: '80vh',
|
||||||
height: 'min-content'
|
height: 'min-content'
|
||||||
});
|
});
|
||||||
config.hasBackdrop = true;
|
|
||||||
const connectedPosition: ConnectedPosition = {
|
const connectedPosition: ConnectedPosition = {
|
||||||
originX: 'start',
|
originX: 'start',
|
||||||
originY: 'bottom',
|
originY: 'bottom',
|
||||||
@ -260,12 +222,10 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onHistoryOnlyChanged(): boolean {
|
private onHistoryOnlyChanged(): boolean {
|
||||||
if (this.historyOnlyValue && this.innerValue) {
|
if (this.historyOnlyValue && this.innerValue && this.innerValue.selectedTab !== TimewindowType.HISTORY) {
|
||||||
if (this.innerValue.selectedTab !== TimewindowType.HISTORY) {
|
this.innerValue.selectedTab = TimewindowType.HISTORY;
|
||||||
this.innerValue.selectedTab = TimewindowType.HISTORY;
|
this.updateDisplayValue();
|
||||||
this.updateDisplayValue();
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -283,7 +243,7 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeValue(obj: Timewindow): void {
|
writeValue(obj: Timewindow): void {
|
||||||
this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.timeService);
|
this.innerValue = initModelFromDefaultTimewindow(obj, this.quickIntervalOnly, this.historyOnly, this.timeService);
|
||||||
this.timewindowDisabled = this.isTimewindowDisabled();
|
this.timewindowDisabled = this.isTimewindowDisabled();
|
||||||
if (this.onHistoryOnlyChanged()) {
|
if (this.onHistoryOnlyChanged()) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@ -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,
|
||||||
|
historyOnly: boolean, timeService: TimeService): Timewindow => {
|
||||||
const model = defaultTimewindow(timeService);
|
const model = defaultTimewindow(timeService);
|
||||||
if (value) {
|
if (value) {
|
||||||
model.hideInterval = value.hideInterval;
|
model.hideInterval = value.hideInterval;
|
||||||
@ -316,6 +317,9 @@ export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalO
|
|||||||
if (quickIntervalOnly) {
|
if (quickIntervalOnly) {
|
||||||
model.realtime.realtimeType = RealtimeWindowType.INTERVAL;
|
model.realtime.realtimeType = RealtimeWindowType.INTERVAL;
|
||||||
}
|
}
|
||||||
|
if (historyOnly) {
|
||||||
|
model.selectedTab = TimewindowType.HISTORY;
|
||||||
|
}
|
||||||
return model;
|
return model;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -123,6 +123,7 @@ import { JsFuncComponent } from '@shared/components/js-func.component';
|
|||||||
import { JsonFormComponent } from '@shared/components/json-form/json-form.component';
|
import { JsonFormComponent } from '@shared/components/json-form/json-form.component';
|
||||||
import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component';
|
||||||
import { AlertDialogComponent } from '@shared/components/dialog/alert-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 { TodoDialogComponent } from '@shared/components/dialog/todo-dialog.component';
|
||||||
import { MaterialIconsDialogComponent } from '@shared/components/dialog/material-icons-dialog.component';
|
import { MaterialIconsDialogComponent } from '@shared/components/dialog/material-icons-dialog.component';
|
||||||
import { MaterialIconSelectComponent } from '@shared/components/material-icon-select.component';
|
import { MaterialIconSelectComponent } from '@shared/components/material-icon-select.component';
|
||||||
@ -306,6 +307,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
WidgetsBundleSelectComponent,
|
WidgetsBundleSelectComponent,
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
AlertDialogComponent,
|
AlertDialogComponent,
|
||||||
|
ErrorAlertDialogComponent,
|
||||||
TodoDialogComponent,
|
TodoDialogComponent,
|
||||||
ColorPickerDialogComponent,
|
ColorPickerDialogComponent,
|
||||||
MaterialIconsDialogComponent,
|
MaterialIconsDialogComponent,
|
||||||
@ -530,6 +532,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
MarkdownModule,
|
MarkdownModule,
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
AlertDialogComponent,
|
AlertDialogComponent,
|
||||||
|
ErrorAlertDialogComponent,
|
||||||
TodoDialogComponent,
|
TodoDialogComponent,
|
||||||
ColorPickerDialogComponent,
|
ColorPickerDialogComponent,
|
||||||
MaterialIconsDialogComponent,
|
MaterialIconsDialogComponent,
|
||||||
|
|||||||
@ -1798,7 +1798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"close": "Close dialog"
|
"close": "Close dialog",
|
||||||
|
"error-message-title": "Error message:",
|
||||||
|
"error-details-title": "Error details"
|
||||||
},
|
},
|
||||||
"direction": {
|
"direction": {
|
||||||
"column": "Column",
|
"column": "Column",
|
||||||
@ -4017,7 +4019,8 @@
|
|||||||
"alarm-data-overflow": "Widget displays alarms for {{allowedEntities}} (maximum allowed) entities out of {{totalEntities}} entities",
|
"alarm-data-overflow": "Widget displays alarms for {{allowedEntities}} (maximum allowed) entities out of {{totalEntities}} entities",
|
||||||
"search": "Search widget",
|
"search": "Search widget",
|
||||||
"filter": "Widget filter type",
|
"filter": "Widget filter type",
|
||||||
"loading-widgets": "Loading widgets..."
|
"loading-widgets": "Loading widgets...",
|
||||||
|
"widget-template-error": "Invalid widget HTML template."
|
||||||
},
|
},
|
||||||
"widget-action": {
|
"widget-action": {
|
||||||
"header-button": "Widget header button",
|
"header-button": "Widget header button",
|
||||||
@ -4026,6 +4029,9 @@
|
|||||||
"open-dashboard": "Navigate to other dashboard",
|
"open-dashboard": "Navigate to other dashboard",
|
||||||
"custom": "Custom action",
|
"custom": "Custom action",
|
||||||
"custom-pretty": "Custom action (with HTML template)",
|
"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",
|
"mobile-action": "Mobile action",
|
||||||
"target-dashboard-state": "Target dashboard state",
|
"target-dashboard-state": "Target dashboard state",
|
||||||
"target-dashboard-state-required": "Target dashboard state is required",
|
"target-dashboard-state-required": "Target dashboard state is required",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user