From 3963b56102f9a1d58a23d3ddf0002dffa17ea981 Mon Sep 17 00:00:00 2001 From: Serhii Mikhnytskyi Date: Fri, 18 Sep 2020 12:04:13 +0300 Subject: [PATCH 01/14] dashboard-form name validation added, rule-chain-details name validation pattern and trim added --- .../modules/home/pages/dashboard/dashboard-form.component.ts | 5 ----- .../home/pages/rulechain/rule-node-details.component.html | 3 ++- .../home/pages/rulechain/rule-node-details.component.ts | 5 ++++- .../modules/home/pages/rulechain/rulechain-page.component.ts | 5 +++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts index 5751c88341..7f19cfe571 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts @@ -95,11 +95,6 @@ export class DashboardFormComponent extends EntityComponent { this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); } - prepareFormValue(formValue: any): any { - formValue.configuration = {...(this.entity.configuration || {}), ...(formValue.configuration || {})}; - return formValue; - } - onPublicLinkCopied($event) { this.store.dispatch(new ActionNotificationShow( { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index e87f7158d0..fd4efddf5a 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -29,7 +29,8 @@ rulenode.name - + {{ 'rulenode.name-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index c19fe98348..b5630b52f8 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -72,8 +72,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O } if (this.ruleNode) { if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) { + this.ruleNodeFormGroup = this.fb.group({ - name: [this.ruleNode.name, [Validators.required]], + name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], debugMode: [this.ruleNode.debugMode, []], configuration: [this.ruleNode.configuration, [Validators.required]], additionalInfo: this.fb.group( @@ -102,6 +103,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O private updateRuleNode() { const formValue = this.ruleNodeFormGroup.value || {}; + if (this.ruleNode.component.type === RuleNodeType.RULE_CHAIN) { const targetRuleChainId: string = formValue.targetRuleChainId; if (this.ruleNode.targetRuleChainId !== targetRuleChainId && targetRuleChainId) { @@ -115,6 +117,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O Object.assign(this.ruleNode, formValue); } } else { + formValue.name = formValue.name.trim(); Object.assign(this.ruleNode, formValue); } } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 2c8ecc9419..2e5cdaa866 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -1550,6 +1550,11 @@ export class AddRuleNodeDialogComponent extends DialogComponent Date: Mon, 21 Sep 2020 12:13:17 +0300 Subject: [PATCH 02/14] modified parent method prepareFormValue in dashboard-form, deleted unused code in rulechain-page --- .../home/pages/dashboard/dashboard-form.component.ts | 6 ++++++ .../home/pages/rulechain/rulechain-page.component.ts | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts index 7f19cfe571..ee72b33453 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts @@ -95,6 +95,12 @@ export class DashboardFormComponent extends EntityComponent { this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); } + prepareFormValue(formValue: any): any { + const preparedValue = super.prepareFormValue(formValue); + preparedValue.configuration = {...(this.entity.configuration || {}), ...(preparedValue.configuration || {})}; + return preparedValue; + } + onPublicLinkCopied($event) { this.store.dispatch(new ActionNotificationShow( { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 2e5cdaa866..7096045aed 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -1551,10 +1551,6 @@ export class AddRuleNodeDialogComponent extends DialogComponent Date: Fri, 18 Sep 2020 17:31:22 +0300 Subject: [PATCH 03/14] set lib attribute "animatedValue" to "true" in analogue-gauge.models.ts --- .../home/components/widget/lib/analogue-gauge.models.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts index 9919173fbc..7038a2f18c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts @@ -1002,7 +1002,8 @@ export abstract class TbAnalogueGauge Date: Sun, 20 Sep 2020 23:45:04 +0300 Subject: [PATCH 04/14] UI Updated dependency --- ui-ngx/package.json | 3 +-- .../import-export/import-export.service.ts | 2 +- ui-ngx/src/tsconfig.app.json | 2 +- ui-ngx/yarn.lock | 23 +++++++------------ 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 4a94929bc5..51d044c3bf 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -105,10 +105,9 @@ "@types/jquery": "^3.5.1", "@types/js-beautify": "^1.11.0", "@types/jstree": "^3.3.40", - "@types/jszip": "^3.4.1", "@types/leaflet": "^1.5.17", - "@types/leaflet-markercluster": "^1.0.3", "@types/leaflet-polylinedecorator": "^1.6.0", + "@types/leaflet.markercluster": "^1.4.2", "@types/lodash": "^4.14.159", "@types/raphael": "^2.3.0", "@types/react": "^16.9.46", diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 210c04d6b2..53c70ce0ee 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -421,7 +421,7 @@ export class ImportExportService { } public exportJSZip(data: object, filename: string) { - const jsZip: JSZip = new JSZip(); + const jsZip = new JSZip(); for (const keyName in data) { if (data.hasOwnProperty(keyName)) { const valueData = data[keyName]; diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json index 2bd6ffd811..1139007835 100644 --- a/ui-ngx/src/tsconfig.app.json +++ b/ui-ngx/src/tsconfig.app.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "../out-tsc/app", "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", - "react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet-markercluster"] + "react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet.markercluster"] }, "angularCompilerOptions": { "fullTemplateTypeCheck": true diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 2aad17330d..5fdc64ee19 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -1397,20 +1397,6 @@ dependencies: "@types/jquery" "*" -"@types/jszip@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.4.1.tgz#e7a4059486e494c949ef750933d009684227846f" - integrity sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A== - dependencies: - jszip "*" - -"@types/leaflet-markercluster@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/leaflet-markercluster/-/leaflet-markercluster-1.0.3.tgz#64151be453f6490e8751500482deb961064e782c" - integrity sha1-ZBUb5FP2SQ6HUVAEgt65YQZOeCw= - dependencies: - "@types/leaflet" "*" - "@types/leaflet-polylinedecorator@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#1572131ffedb3154c6e18e682d2fb700e203af19" @@ -1418,6 +1404,13 @@ dependencies: "@types/leaflet" "*" +"@types/leaflet.markercluster@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.2.tgz#86b8ab7ca2397b48d9ba637757aaf7a6d1cc6f0f" + integrity sha512-QQ//hevAxMH2dlRQdRre7V/1G+TbtuDtZnZF/75TNwVIgklrsQVCIcS/cvLsl7UUryfPJ6xmoYHfFzK5iGVgpg== + dependencies: + "@types/leaflet" "*" + "@types/leaflet@*", "@types/leaflet@^1.5.17": version "1.5.17" resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b" @@ -5632,7 +5625,7 @@ jstree@^3.3.10: dependencies: jquery ">=1.9.1" -jszip@*, jszip@^3.1.3, jszip@^3.5.0: +jszip@^3.1.3, jszip@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6" integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA== From fbc58d0e2c2a4020cfaa2156d5ba83e6db3084ec Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 21 Sep 2020 10:45:29 +0300 Subject: [PATCH 05/14] Fix daterangepicker --- ui-ngx/package.json | 2 +- ui-ngx/yarn.lock | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 51d044c3bf..a74d9eee86 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -65,7 +65,7 @@ "moment": "^2.27.0", "ngx-clipboard": "^13.0.1", "ngx-color-picker": "^10.0.1", - "ngx-daterangepicker-material": "^3.0.4", + "ngx-daterangepicker-material": "^4.0.1", "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", "ngx-hm-carousel": "^2.0.0-rc.1", "ngx-sharebuttons": "^8.0.1", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 5fdc64ee19..ddc2e363b0 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6414,10 +6414,12 @@ ngx-color-picker@^10.0.1: dependencies: tslib "^2.0.0" -ngx-daterangepicker-material@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-3.0.4.tgz#af759e52fd587fcc9bce1fbcfc8cde828df6a471" - integrity sha512-pDg8kdXx/h8es8dpjBI+xbsxQbS0dV3uSPgfsx39t9LIw3Dv50h8T1achT5jUWSzSU7855ywTk+NlNBDTgkeNg== +ngx-daterangepicker-material@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-4.0.1.tgz#788c2e32eb4717629d4a0e60a60bf8d6430d8c13" + integrity sha512-0gY6DGU+dgYdmoAKrIJSB9xnDqBvj91Yis3II/ZJxxMfZVTG4qMMatck6w8FzdU+CYT64ArCq+Uwa6hJRHX6Nw== + dependencies: + tslib "^1.10.0" "ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#master": version "0.0.0" From 7347230ec42b880c0ec6fa860714894771f5fdea Mon Sep 17 00:00:00 2001 From: kalutkaz <43555187+kalutkaz@users.noreply.github.com> Date: Tue, 6 Oct 2020 18:28:26 +0300 Subject: [PATCH 06/14] Update knob control (#3501) * Epdate knob control * Fix click function * Refactoring * Formatting * Change 'mouseup' --- .../widget/lib/rpc/knob.component.ts | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/knob.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/knob.component.ts index a4c1d1c50b..f5f48c86c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/knob.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/knob.component.ts @@ -67,6 +67,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { title = ''; minValue: number; maxValue: number; + newValue = 0; private startDeg = -1; private currentDeg = 0; @@ -175,16 +176,15 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { const offset = this.knob.offset(); const center = { - y : offset.top + this.knob.height()/2, - x: offset.left + this.knob.width()/2 + y: offset.top + this.knob.height() / 2, + x: offset.left + this.knob.width() / 2 }; - const rad2deg = 180/Math.PI; + const rad2deg = 180 / Math.PI; const t: Touch = ((e.originalEvent as any).touches) ? (e.originalEvent as any).touches[0] : e; - const a = center.y - t.pageY; const b = center.x - t.pageX; - let deg = Math.atan2(a,b)*rad2deg; - if(deg < 0){ + let deg = Math.atan2(a, b) * rad2deg; + if (deg < 0) { deg = 360 + deg; } if (deg > this.maxDeg) { @@ -196,13 +196,17 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { } this.currentDeg = deg; this.lastDeg = deg; - this.knobTopPointerContainer.css('transform','rotate('+(this.currentDeg)+'deg)'); + this.knobTopPointerContainer.css('transform', 'rotate(' + (this.currentDeg) + 'deg)'); this.turn(this.degreeToRatio(this.currentDeg)); this.rotation = this.currentDeg; this.startDeg = -1; + this.rpcUpdateValue(this.newValue); }); + + this.knob.on('mousedown touchstart', (e) => { + this.moving = false; e.preventDefault(); const offset = this.knob.offset(); const center = { @@ -211,7 +215,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { }; const rad2deg = 180/Math.PI; - this.knob.on('mousemove.rem touchmove.rem', (ev) => { + $(document).on('mousemove.rem touchmove.rem', (ev) => { this.moving = true; const t: Touch = ((ev.originalEvent as any).touches) ? (ev.originalEvent as any).touches[0] : ev; @@ -262,6 +266,9 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { }); $(document).on('mouseup.rem touchend.rem',() => { + if(this.newValue !== this.rpcValue && this.moving) { + this.rpcUpdateValue(this.newValue); + } this.knob.off('.rem'); $(document).off('.rem'); this.rotation = this.currentDeg; @@ -308,12 +315,12 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { } private turn(ratio: number) { - const value = Number((this.minValue + (this.maxValue - this.minValue)*ratio).toFixed(this.ctx.decimals)); - if (this.canvasBar.value !== value) { - this.canvasBar.value = value; + this.newValue = Number((this.minValue + (this.maxValue - this.minValue)*ratio).toFixed(this.ctx.decimals)); + if (this.canvasBar.value !== this.newValue) { + this.canvasBar.value = this.newValue; } this.updateColor(this.canvasBar.getValueColor()); - this.onValue(value); + this.onValue(this.newValue); } private resize() { @@ -379,7 +386,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { private onValue(value: number) { this.value = this.formatValue(value); this.checkValueSize(); - this.rpcUpdateValue(value); this.ctx.detectChanges(); } From e35e54a764adad71240cc246e22c5142070f2d3f Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 21 Sep 2020 18:12:10 +0300 Subject: [PATCH 07/14] Fix resize switch control --- .../home/components/widget/lib/rpc/switch.component.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.scss index f878f45320..68bea36407 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.scss @@ -112,6 +112,9 @@ $error-height: 14px !default; height: 90%; } + .mat-slide-toggle-label{ + height: 100%; + } .mat-slide-toggle-thumb { top: 0; left: 0; From 1eccfcc76aca4997fb2be158ac3dfd7f035d6a86 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 21 Sep 2020 19:38:06 +0300 Subject: [PATCH 08/14] Fixed incorrect display of alarm table columns(AckTime, Cleared time), with no parameters specified --- .../home/components/widget/lib/alarms-table-widget.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index d21fbe9c77..81834ff9c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -804,7 +804,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, const alarmField = alarmFields[key.name]; if (alarmField) { if (alarmField.time) { - return this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss'); + return value ? this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss') : ''; } else if (alarmField.value === alarmFields.severity.value) { return this.translate.instant(alarmSeverityTranslations.get(value)); } else if (alarmField.value === alarmFields.status.value) { From 762c6dae558e0d25ebffd3b54222801a2a977560 Mon Sep 17 00:00:00 2001 From: Serhii Mikhnytskyi Date: Wed, 23 Sep 2020 11:10:40 +0300 Subject: [PATCH 09/14] improved performance of table widgets - removed unused ngZone.run and detectChanges, changed functions trackByRowIndex - now is used index, not id, minor improvements for functions, used after data updating. --- .../lib/alarms-table-widget.component.html | 2 +- .../lib/alarms-table-widget.component.ts | 25 ++++++++--- .../lib/entities-table-widget.component.html | 2 +- .../lib/entities-table-widget.component.ts | 25 ++++++++--- .../lib/timeseries-table-widget.component.ts | 44 ++++++++++--------- 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 7e9a67c485..d269fbbe92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -61,7 +61,7 @@
- diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 81834ff9c9..26055c55b2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -247,11 +247,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } public onDataUpdated() { - this.ngZone.run(() => { - this.updateTitle(true); - this.alarmsDatasource.updateAlarms(); - this.ctx.detectChanges(); - }); + this.updateTitle(true); + this.alarmsDatasource.updateAlarms(); } public pageLinkSortDirection(): SortDirection { @@ -565,6 +562,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, return column.def; } + public trackByRowIndex(index: number) { + return index; + } + public headerStyle(key: EntityColumn): any { const columnWidth = this.columnWidth[key.def]; return widthStyle(columnWidth); @@ -606,7 +607,19 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } else { content = this.defaultContent(key, contentInfo, value); } - return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : ''; + + if (!isDefined(content)) { + return ''; + + } else { + switch (typeof content) { + case 'string': + return this.domSanitizer.bypassSecurityTrustHtml(content); + default: + return content; + } + } + } else { return ''; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index a2c70a3a89..2eb4b372b9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -38,7 +38,7 @@
-
{{ column.title }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index ef560dbfc5..dae33f3cfe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -206,11 +206,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni } public onDataUpdated() { - this.ngZone.run(() => { - this.updateTitle(true); - this.entityDatasource.dataUpdated(); - this.ctx.detectChanges(); - }); + this.updateTitle(true); + this.entityDatasource.dataUpdated(); } public pageLinkSortDirection(): SortDirection { @@ -488,6 +485,10 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni return column.def; } + public trackByRowIndex(index: number) { + return index; + } + public headerStyle(key: EntityColumn): any { const columnWidth = this.columnWidth[key.def]; return widthStyle(columnWidth); @@ -529,7 +530,19 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni } else { content = this.defaultContent(key, contentInfo, value); } - return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : ''; + + if (!isDefined(content)) { + return ''; + + } else { + switch (typeof content) { + case 'string': + return this.domSanitizer.bypassSecurityTrustHtml(content); + default: + return content; + } + } + } else { return ''; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 28e6e58c25..e6cf7af811 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -40,7 +40,7 @@ import { } from '@shared/models/widget.models'; import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; -import { hashCode, isDefined, isNumber } from '@core/utils'; +import {hashCode, isDefined, isDefinedAndNotNull, isNumber} from '@core/utils'; import cssjs from '@core/css/css'; import { PageLink } from '@shared/models/page/page-link'; import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; @@ -197,11 +197,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } public onDataUpdated() { - this.ngZone.run(() => { - this.sources.forEach((source) => { - source.timeseriesDatasource.dataUpdated(this.data); - }); - this.ctx.detectChanges(); + this.sources.forEach((source) => { + source.timeseriesDatasource.dataUpdated(this.data); }); } @@ -410,7 +407,18 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI const units = contentInfo.units || this.ctx.widgetConfig.units; content = this.ctx.utils.formatValue(value, decimals, units, true); } - return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : ''; + + if (!isDefined(content)) { + return ''; + + } else { + switch (typeof content) { + case 'string': + return this.domSanitizer.bypassSecurityTrustHtml(content); + default: + return content; + } + } } } @@ -515,26 +523,22 @@ class TimeseriesDatasource implements DataSource { row[d + 1] = cellData[1]; }); } + const rows: TimeseriesRow[] = []; - for (const t of Object.keys(rowsMap)) { - if (this.hideEmptyLines) { - let hideLine = true; - for (let c = 0; (c < data.length) && hideLine; c++) { - if (rowsMap[t][c + 1]) { - hideLine = false; - } - } - if (!hideLine) { - rows.push(rowsMap[t]); - } + + for (const value of Object.values(rowsMap)) { + this.hideEmptyLines = true; + + if (this.hideEmptyLines && isDefinedAndNotNull(value[1])) { + rows.push(value); } else { - rows.push(rowsMap[t]); + rows.push(value); } } + return rows; } - isEmpty(): Observable { return this.rowsSubject.pipe( map((rows) => !rows.length) From 0227234a6d50bd2235662fd39845fba5b22475bc Mon Sep 17 00:00:00 2001 From: Serhii Mikhnytskyi Date: Wed, 23 Sep 2020 11:14:44 +0300 Subject: [PATCH 10/14] removed test component property --- .../components/widget/lib/timeseries-table-widget.component.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index e6cf7af811..ebf5387862 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -527,8 +527,6 @@ class TimeseriesDatasource implements DataSource { const rows: TimeseriesRow[] = []; for (const value of Object.values(rowsMap)) { - this.hideEmptyLines = true; - if (this.hideEmptyLines && isDefinedAndNotNull(value[1])) { rows.push(value); } else { From 0faef1ad164a728a1b2d12417b5b0bb52bdbc34e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 1 Oct 2020 15:49:15 +0300 Subject: [PATCH 11/14] rest client improvments --- .../thingsboard/rest/client/RestClient.java | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 89b39d2b89..52023a6450 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -45,7 +45,6 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; @@ -56,6 +55,7 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.AuditLog; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; @@ -73,6 +73,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -890,7 +891,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { }, params).getBody(); } - public PageData getCustomerDashboards(CustomerId customerId, TimePageLink pageLink) { + public PageData getCustomerDashboards(CustomerId customerId, PageLink pageLink) { Map params = new HashMap<>(); params.put("customerId", customerId.getId().toString()); addPageLinkToParam(params, pageLink); @@ -1634,17 +1635,35 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { } public List getTimeseries(EntityId entityId, List keys, Long interval, Aggregation agg, TimePageLink pageLink, boolean useStrictDataTypes) { + SortOrder sortOrder = pageLink.getSortOrder(); + return getTimeseries(entityId, keys, interval, agg, sortOrder != null ? sortOrder.getDirection() : null, pageLink.getStartTime(), pageLink.getEndTime(), 100, useStrictDataTypes); + } + + public List getTimeseries(EntityId entityId, List keys, Long interval, Aggregation agg, SortOrder.Direction sortOrder, Long startTime, Long endTime, Integer limit, boolean useStrictDataTypes) { Map params = new HashMap<>(); params.put("entityType", entityId.getEntityType().name()); params.put("entityId", entityId.getId().toString()); params.put("keys", listToString(keys)); params.put("interval", interval == null ? "0" : interval.toString()); params.put("agg", agg == null ? "NONE" : agg.name()); + params.put("limit", limit != null ? limit.toString() : "100"); + params.put("orderBy", sortOrder != null ? sortOrder.name() : "DESC"); params.put("useStrictDataTypes", Boolean.toString(useStrictDataTypes)); - addPageLinkToParam(params, pageLink); + + StringBuilder urlBuilder = new StringBuilder(baseURL); + urlBuilder.append("/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&orderBy={orderBy}"); + + if (startTime != null) { + urlBuilder.append("&startTs={startTs}"); + params.put("startTs", String.valueOf(startTime)); + } + if (endTime != null) { + urlBuilder.append("&endTs={endTs}"); + params.put("endTs", String.valueOf(endTime)); + } Map> timeseries = restTemplate.exchange( - baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&" + getUrlParamsTs(pageLink), + urlBuilder.toString(), HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>>() { @@ -1996,23 +2015,12 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { } private String getTimeUrlParams(TimePageLink pageLink) { - return this.getUrlParams(pageLink); - } - private String getUrlParams(TimePageLink pageLink) { - return getUrlParams(pageLink, "startTime", "endTime"); - } - - private String getUrlParamsTs(TimePageLink pageLink) { - return getUrlParams(pageLink, "startTs", "endTs"); - } - - private String getUrlParams(TimePageLink pageLink, String startTime, String endTime) { String urlParams = "limit={limit}&ascOrder={ascOrder}"; if (pageLink.getStartTime() != null) { - urlParams += "&" + startTime + "={startTime}"; + urlParams += "&startTime={startTime}"; } if (pageLink.getEndTime() != null) { - urlParams += "&" + endTime + "={endTime}"; + urlParams += "&endTime={endTime}"; } return urlParams; } From 3bcebb06669a9697d82ff13917eae91ddf6bf3c1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 1 Oct 2020 16:03:11 +0300 Subject: [PATCH 12/14] added annotation @Deprecated to the old methods "getTimeseries" --- .../src/main/java/org/thingsboard/rest/client/RestClient.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 52023a6450..d2ba4d43b4 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -1630,10 +1630,12 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { return RestJsonConverter.toTimeseries(timeseries); } + @Deprecated public List getTimeseries(EntityId entityId, List keys, Long interval, Aggregation agg, TimePageLink pageLink) { return getTimeseries(entityId, keys, interval, agg, pageLink, true); } + @Deprecated public List getTimeseries(EntityId entityId, List keys, Long interval, Aggregation agg, TimePageLink pageLink, boolean useStrictDataTypes) { SortOrder sortOrder = pageLink.getSortOrder(); return getTimeseries(entityId, keys, interval, agg, sortOrder != null ? sortOrder.getDirection() : null, pageLink.getStartTime(), pageLink.getEndTime(), 100, useStrictDataTypes); From 95921a847ae542bdd80dfb0791e9f57b327ab3c3 Mon Sep 17 00:00:00 2001 From: "Seok Hyun, Ga" Date: Fri, 2 Oct 2020 14:54:35 +0900 Subject: [PATCH 13/14] Update locale.constant-ko_KR.json Adding additional translation items. --- .../assets/locale/locale.constant-ko_KR.json | 571 +++++++++--------- 1 file changed, 288 insertions(+), 283 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index e5f09184b9..c255440ba7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -1,12 +1,14 @@ { "access": { - "unauthorized": "권한 없음.", - "unauthorized-access": "허가되지 않은 접근", + "unauthorized": "승인되지 않음", + "unauthorized-access": "승인되지 않은 접근", "unauthorized-access-text": "이 리소스에 접근하려면 로그인해야 합니다!", "access-forbidden": "접근 금지", - "access-forbidden-text": "접근 권한이 없습니다.!
만일 이 페이지에 계속 접근하려면 다른 사용자로 로그인 하세요.", - "refresh-token-expired": "세션이 만료되었습니다.", - "refresh-token-failed": "세션을 새로 고칠 수 없습니다." + "access-forbidden-text": "접근 권한이 없습니다!
만일 이 페이지에 계속 접근하려면 다른 사용자로 로그인 하세요.", + "refresh-token-expired": "세션이 만료되었습니다", + "refresh-token-failed": "세션을 새로 고칠 수 없습니다.", + "permission-denied": "권한이 없습니다", + "permission-denied-text": "이 작업을 수행할 권한이 없습니다!" }, "action": { "activate": "활설화", @@ -22,11 +24,11 @@ "update": "업데이트", "remove": "제거", "search": "검색", - "clear-search": "Clear search", + "clear-search": "검색 초기화", "assign": "할당", "unassign": "비할당", "share": "Share", - "make-private": "Make private", + "make-private": "비공개로 설정", "apply": "적용", "apply-changes": "변경사항 적용", "edit-mode": "수정 모드", @@ -44,8 +46,8 @@ "undo": "취소", "copy": "복사", "paste": "붙여넣기", - "copy-reference": "Copy reference", - "paste-reference": "Paste reference", + "copy-reference": "참조 복사", + "paste-reference": "참조 붙여넣기", "import": "가져오기", "export": "내보내기", "share-via": "Share via {{provider}}" @@ -79,26 +81,26 @@ "smtp-port": "SMTP 포트", "smtp-port-required": "SMTP 포트를 입력해야 합니다.", "smtp-port-invalid": "올바른 SMTP 포트가 아닙니다.", - "timeout-msec": "제한시간 (msec)", - "timeout-required": "제한시간을 입력해야 합니다.", - "timeout-invalid": "올바른 제한시간이 아닙니다.", + "timeout-msec": "제한시간 (ms)", + "timeout-required": "제한시이 입력되지 않았습니다.", + "timeout-invalid": "제한시간이 올바르게 입력되지 않았습니다.", "enable-tls": "TLS 사용", "tls-version" : "TLS 버전", "send-test-mail": "테스트 메일 보내기" }, "alarm": { - "alarm": "Alarm", - "alarms": "Alarms", - "select-alarm": "Select alarm", - "no-alarms-matching": "No alarms matching '{{entity}}' were found.", - "alarm-required": "Alarm is required", - "alarm-status": "Alarm status", + "alarm": "알람", + "alarms": "알람", + "select-alarm": "알람 선택", + "no-alarms-matching": "'{{entity}}'에 대한 알람이 존재하지 않습니다.", + "alarm-required": "알람이 필요합니다", + "alarm-status": "알람 상태", "search-status": { "ANY": "Any", - "ACTIVE": "Active", + "ACTIVE": "활성", "CLEARED": "Cleared", - "ACK": "Acknowledged", - "UNACK": "Unacknowledged" + "ACK": "수용", + "UNACK": "불수용" }, "display-status": { "ACTIVE_UNACK": "Active Unacknowledged", @@ -107,28 +109,28 @@ "CLEARED_ACK": "Cleared Acknowledged" }, "no-alarms-prompt": "No alarms found", - "created-time": "Created time", - "type": "Type", - "severity": "Severity", - "originator": "Originator", - "originator-type": "Originator type", - "details": "Details", - "status": "Status", + "created-time": "생성된 시간", + "type": "종류", + "severity": "심각도", + "originator": "창시자", + "originator-type": "창시자 종류", + "details": "자세히", + "status": "상태", "alarm-details": "Alarm details", - "start-time": "Start time", - "end-time": "End time", + "start-time": "시작 시각", + "end-time": "마지막 시각", "ack-time": "Acknowledged time", "clear-time": "Cleared time", - "severity-critical": "Critical", - "severity-major": "Major", - "severity-minor": "Minor", - "severity-warning": "Warning", - "severity-indeterminate": "Indeterminate", - "acknowledge": "Acknowledge", - "clear": "Clear", - "search": "Search alarms", - "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } selected", - "no-data": "No data to display", + "severity-critical": "심각한", + "severity-major": "주요한", + "severity-minor": "작은", + "severity-warning": "경고", + "severity-indeterminate": "중간", + "acknowledge": "수용", + "clear": "지우기", + "search": "알람 검색", + "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } 선택됨", + "no-data": "표시할 데이터가 없습니다", "polling-interval": "Alarms polling interval (sec)", "polling-interval-required": "Alarms polling interval is required.", "min-polling-interval-message": "At least 1 sec polling interval is allowed.", @@ -178,46 +180,46 @@ "any-relation": "any" }, "asset": { - "asset": "Asset", - "assets": "Assets", - "management": "Asset management", - "view-assets": "View Assets", - "add": "Add Asset", - "assign-to-customer": "Assign to customer", - "assign-asset-to-customer": "Assign Asset(s) To Customer", - "assign-asset-to-customer-text": "Please select the assets to assign to the customer", - "no-assets-text": "No assets found", - "assign-to-customer-text": "Please select the customer to assign the asset(s)", - "public": "Public", - "assignedToCustomer": "Assigned to customer", - "make-public": "Make asset public", - "make-private": "Make asset private", - "unassign-from-customer": "Unassign from customer", - "delete": "Delete asset", - "asset-public": "Asset is public", - "asset-type": "Asset type", - "asset-type-required": "Asset type is required.", - "select-asset-type": "Select asset type", - "enter-asset-type": "Enter asset type", - "any-asset": "Any asset", - "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", - "asset-type-list-empty": "No asset types selected.", - "asset-types": "Asset types", - "name": "Name", - "name-required": "Name is required.", - "description": "Description", - "type": "Type", - "type-required": "Type is required.", - "details": "Details", - "events": "Events", - "add-asset-text": "Add new asset", - "asset-details": "Asset details", - "assign-assets": "Assign assets", - "assign-assets-text": "Assign { count, plural, 1 {1 asset} other {# assets} } to customer", - "delete-assets": "Delete assets", - "unassign-assets": "Unassign assets", + "asset": "자산", + "assets": "자산", + "management": "자산 관리", + "view-assets": "자산 보기", + "add": "자산 추가", + "assign-to-customer": "고객에게 자산 지정", + "assign-asset-to-customer": "자산을 고객에게 지정", + "assign-asset-to-customer-text": "고객에게 지정할 자산을 선택하세요", + "no-assets-text": "아무 자산도 없습니다", + "assign-to-customer-text": "자산에 지정될 고객을 선택하세요", + "public": "공개", + "assignedToCustomer": "지정된 고객", + "make-public": "자산을 공개로 설정", + "make-private": "자산을 비공개로 설정", + "unassign-from-customer": "고객 지정 해제", + "delete": "자산 삭제", + "asset-public": "공개된 자산", + "asset-type": "자산 종류", + "asset-type-required": "자산 종류를 선택하세요.", + "select-asset-type": "자산 종류 선택", + "enter-asset-type": "자산 종류 입력", + "any-asset": "모든 자산", + "no-asset-types-matching": "'{{entitySubtype}}'과 일치하는 자산 종류가 없습니다.", + "asset-type-list-empty": "아무 자산 종류도 선택되지 않았습니다.", + "asset-types": "자산 종류", + "name": "이름", + "name-required": "이름을 입력하세요.", + "description": "설명", + "type": "종류", + "type-required": "종류를 입력하세요.", + "details": "자세히", + "events": "이벤트", + "add-asset-text": "새로운 자산 추가", + "asset-details": "자산 자세히", + "assign-assets": "자산 지정", + "assign-assets-text": "자산 { count, plural, 1 {1 asset} other {# assets} }을 고객에게 지정", + "delete-assets": "자산 삭제", + "unassign-assets": "자산 지정 해제", "unassign-assets-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from customer", - "assign-new-asset": "Assign new asset", + "assign-new-asset": "새로운 자산 지정", "delete-asset-title": "Are you sure you want to delete the asset '{{assetName}}'?", "delete-asset-text": "Be careful, after the confirmation the asset and all related data will become unrecoverable.", "delete-assets-title": "Are you sure you want to delete { count, plural, 1 {1 asset} other {# assets} }?", @@ -248,10 +250,11 @@ "scope-server": "서버 속성", "scope-shared": "공유 속성", "add": "속성 추가", - "key": "Key", - "key-required": "속성 key를 입력하세요.", + "key": "키", + "last-update-time": "마지막 수정된 시간", + "key-required": "속성 키를 입력하세요.", "value": "Value", - "value-required": "속성 value를 입력하세요.", + "value-required": "속성 값을 입력하세요.", "delete-attributes-title": "{ count, plural, 1 {속성} other {여러 속성들을} } 삭제하시겠습니까??", "delete-attributes-text": "모든 선택된 속성들이 제거 될 것이므로 주의하십시오.", "delete-attributes": "속성 삭제", @@ -264,38 +267,40 @@ "add-widget-to-dashboard": "대시보드에 위젯 추가", "selected-attributes": "{ count, plural, 1 {속성 1개} other {속성 #개} } 선택됨", "selected-telemetry": "{ count, plural, 1 {최근 데이터 1개} other {최근 데이터 #개} } 선택됨" + "no-attributes-text": "아무 속성도 찾을 수 없습니다", + "no-telemetry-text": "아무 텔레메트리도 찾을 수 없습니다." }, "audit-log": { - "audit": "Audit", - "audit-logs": "Audit Logs", - "timestamp": "Timestamp", - "entity-type": "Entity Type", - "entity-name": "Entity Name", - "user": "User", - "type": "Type", - "status": "Status", - "details": "Details", - "type-added": "Added", - "type-deleted": "Deleted", - "type-updated": "Updated", - "type-attributes-updated": "Attributes updated", - "type-attributes-deleted": "Attributes deleted", + "audit": "감사", + "audit-logs": "감사 로그", + "timestamp": "타임스탬프", + "entity-type": "기체 종류", + "entity-name": "개체 이름", + "user": "사용자", + "type": "종류", + "status": "상태", + "details": "자세히", + "type-added": "추가됨", + "type-deleted": "삭제됨", + "type-updated": "수정됨", + "type-attributes-updated": "속성이 수정되었습니다", + "type-attributes-deleted": "속성이 삭제되었습니다", "type-rpc-call": "RPC call", - "type-credentials-updated": "Credentials updated", - "type-assigned-to-customer": "Assigned to Customer", - "type-unassigned-from-customer": "Unassigned from Customer", - "type-activated": "Activated", - "type-suspended": "Suspended", - "type-credentials-read": "Credentials read", - "type-attributes-read": "Attributes read", - "status-success": "Success", - "status-failure": "Failure", - "audit-log-details": "Audit log details", - "no-audit-logs-prompt": "No logs found", - "action-data": "Action data", - "failure-details": "Failure details", - "search": "Search audit logs", - "clear-search": "Clear search" + "type-credentials-updated": "자격 증명이 갱신되었습니다", + "type-assigned-to-customer": "고객에게 지정", + "type-unassigned-from-customer": "지정된 고객 해제", + "type-activated": "활성", + "type-suspended": "일시 중지", + "type-credentials-read": "자격 증명 읽기", + "type-attributes-read": "속성 읽기", + "status-success": "성공", + "status-failure": "실패", + "audit-log-details": "감사 로그 세부 사항", + "no-audit-logs-prompt": "아무 로그도 없습니다.", + "action-data": "액션 데이터", + "failure-details": "실패 세부 사항", + "search": "감사 로그 검색", + "clear-search": "검색 초기화" }, "confirm-on-exit": { "message": "변경 사항을 저장하지 않았습니다. 이 페이지를 나가시겠습니까?", @@ -323,8 +328,8 @@ }, "content-type": { "json": "Json", - "text": "Text", - "binary": "Binary (Base64)" + "text": "텍스트", + "binary": "바이너리 (Base64)" }, "customer": { "customers": "커스터머", @@ -337,10 +342,10 @@ "manage-customer-users": "커스터머 사용자 관리", "manage-customer-devices": "커스터머 디바이스 관리", "manage-customer-dashboards": "커스터머 대시보드 관리", - "manage-public-devices": "Manage public devices", - "manage-public-dashboards": "Manage public dashboards", - "manage-customer-assets": "Manage customer assets", - "manage-public-assets": "Manage public assets", + "manage-public-devices": "공개된 디바이스 관리", + "manage-public-dashboards": "공개된 대시보드 관리", + "manage-customer-assets": "고객 자산 관리", + "manage-public-assets": "공개된 자산 관리", "add-customer-text": "커스터머 추가", "no-customers-text": "커스터머가 없습니다.", "customer-details": "커스터머 상세정보", @@ -355,16 +360,16 @@ "title": "타이틀", "title-required": "타이틀을 입력하세요.", "description": "설명", - "details": "Details", - "events": "Events", - "copyId": "Copy customer Id", - "idCopiedMessage": "Customer Id has been copied to clipboard", - "select-customer": "Select customer", - "no-customers-matching": "No customers matching '{{entity}}' were found.", - "customer-required": "Customer is required", - "select-default-customer": "Select default customer", - "default-customer": "Default customer", - "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level" + "details": "자세히", + "events": "이벤트", + "copyId": "고객 ID 복사", + "idCopiedMessage": "고객 ID가 클립 보드에 복사되었습니다.", + "select-customer": "선택된 고객", + "no-customers-matching": "'{{entity}}'에 해당하는 고객을 찾을 수 없습니다.", + "customer-required": "고객을 입력하세요.", + "select-default-customer": "기본 고객 선택", + "default-customer": "기본 고객", + "default-customer-required": "테넌트 수준에서 대시보드를 디버그 하기 위해서는 기본 고객이 필요합니다." }, "datetime": { "date-from": "시작 날짜", @@ -522,8 +527,8 @@ "assign-to-customer-text": "디바이스를 할당할 커스터머를 선택하세요.", "device-details": "디바이스 상세정보", "add-device-text": "디바이스 추가", - "credentials": "크리덴셜", - "manage-credentials": "크리덴셜 관리", + "credentials": "자격 증명", + "manage-credentials": "자격 증명 관리", "delete": "디바이스 삭제", "assign-devices": "디바이스 할당", "assign-devices-text": "{ count, plural, 1 {디바이스 1개} other {디바이스 #개} }를 커서터머에 할당", @@ -575,8 +580,8 @@ "unknown-error": "알 수 없는 오류" }, "entity": { - "entity": "Entity", - "entities": "Entities", + "entity": "개체", + "entities": "개체", "aliases": "Entity aliases", "entity-alias": "Entity alias", "unable-delete-entity-alias-title": "Unable to delete entity alias", @@ -588,70 +593,70 @@ "alias-required": "Entity alias is required.", "remove-alias": "Remove entity alias", "add-alias": "Add entity alias", - "entity-list": "Entity list", - "entity-type": "Entity type", - "entity-types": "Entity types", - "entity-type-list": "Entity type list", - "any-entity": "Any entity", - "enter-entity-type": "Enter entity type", + "entity-list": "개체 목록", + "entity-type": "개체 종류", + "entity-types": "개체 종류", + "entity-type-list": "개체 종류 목록", + "any-entity": "모든 개체", + "enter-entity-type": "개체 종류 입력", "no-entities-matching": "No entities matching '{{entity}}' were found.", "no-entity-types-matching": "No entity types matching '{{entityType}}' were found.", - "name-starts-with": "Name starts with", + "name-starts-with": "다음으로 시작하는 이름", "use-entity-name-filter": "Use filter", - "entity-list-empty": "No entities selected.", - "entity-type-list-empty": "No entity types selected.", + "entity-list-empty": "아무 개체도 선택되지 않았습니다.", + "entity-type-list-empty": "개체 종류가 선택되지 않았습니다.", "entity-name-filter-required": "Entity name filter is required.", "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.", - "all-subtypes": "All", - "select-entities": "Select entities", + "all-subtypes": "모두", + "select-entities": "선택된 개체", "no-aliases-found": "No aliases found.", "no-alias-matching": "'{{alias}}' not found.", - "create-new-alias": "Create a new one!", - "key": "Key", - "key-name": "Key name", - "no-keys-found": "No keys found.", - "no-key-matching": "'{{key}}' not found.", - "create-new-key": "Create a new one!", - "type": "Type", - "type-required": "Entity type is required.", - "type-device": "Device", - "type-devices": "Devices", + "create-new-alias": "생성 완료!", + "key": "키", + "key-name": "키 이름", + "no-keys-found": "아무 키도 찾을 수 없습니다..", + "no-key-matching": "'{{key}}'를 찾을 수 없습니다.", + "create-new-key": "생성 완료!", + "type": "종류", + "type-required": "개체의 종류를 입력하세요.", + "type-device": "장치", + "type-devices": "장치", "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", "device-name-starts-with": "Devices whose names start with '{{prefix}}'", - "type-asset": "Asset", - "type-assets": "Assets", + "type-asset": "자산", + "type-assets": "자산", "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", - "type-rule": "Rule", - "type-rules": "Rules", + "type-rule": "규칙", + "type-rules": "규칙", "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }", "rule-name-starts-with": "Rules whose names start with '{{prefix}}'", - "type-plugin": "Plugin", - "type-plugins": "Plugins", + "type-plugin": "플러그인", + "type-plugins": "플러그인", "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }", "plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'", - "type-tenant": "Tenant", - "type-tenants": "Tenants", + "type-tenant": "테넌트", + "type-tenants": "테넌트", "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", - "type-customer": "Customer", - "type-customers": "Customers", + "type-customer": "고객", + "type-customers": "고객", "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", "customer-name-starts-with": "Customers whose names start with '{{prefix}}'", - "type-user": "User", - "type-users": "Users", + "type-user": "사용자", + "type-users": "사용자", "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }", "user-name-starts-with": "Users whose names start with '{{prefix}}'", - "type-dashboard": "Dashboard", - "type-dashboards": "Dashboards", + "type-dashboard": "대시보드", + "type-dashboards": "대시보드", "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }", "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", - "type-alarm": "Alarm", - "type-alarms": "Alarms", + "type-alarm": "알람", + "type-alarms": "알람", "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'", - "type-rulechain": "Rule chain", - "type-rulechains": "Rule chains", + "type-rulechain": "규칙 사슬", + "type-rulechains": "규칙 사슬", "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", "rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'", "type-current-customer": "Current Customer", @@ -667,23 +672,23 @@ "type-error": "에러", "type-lc-event": "주기적 이벤트", "type-stats": "통계", - "type-debug-rule-node": "Debug", - "type-debug-rule-chain": "Debug", + "type-debug-rule-node": "디버그", + "type-debug-rule-chain": "디버그", "no-events-prompt": "이벤트 없음", "error": "에러", "alarm": "알람", "event-time": "이벤트 발생 시간", "server": "서버", "body": "Body", - "method": "Method", - "type": "Type", - "entity": "Entity", - "message-id": "Message Id", - "message-type": "Message Type", - "data-type": "Data Type", - "relation-type": "Relation Type", - "metadata": "Metadata", - "data": "Data", + "method": "방법", + "type": "종류", + "entity": "개체", + "message-id": "메시지 ID", + "message-type": "메시지 종류", + "data-type": "데이터 종류", + "relation-type": "관계 종류", + "metadata": "메타데이터", + "data": "데이터", "event": "이벤트", "status": "상태", "success": "성공", @@ -692,11 +697,11 @@ "errors-occurred": "오류가 발생했습니다" }, "extension": { - "extensions": "Extensions", + "extensions": "확장", "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} } selected", - "type": "Type", - "key": "Key", - "value": "Value", + "type": "종류", + "key": "키", + "value": "값", "id": "Id", "extension-id": "Extension id", "extension-type": "Extension type", @@ -992,14 +997,14 @@ "invalid-additional-info": "Unable to parse additional info json." }, "rulechain": { - "rulechain": "Rule chain", - "rulechains": "Rule chains", + "rulechain": "규칙 사슬", + "rulechains": "규칙 사슬", "root": "Root", "delete": "Delete rule chain", - "name": "Name", - "name-required": "Name is required.", - "description": "Description", - "add": "Add Rule Chain", + "name": "이름", + "name-required": "이름을 입력하세요.", + "description": "설명", + "add": "규칙 사슬 추가", "set-root": "Make rule chain root", "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?", "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.", @@ -1008,14 +1013,14 @@ "delete-rulechains-title": "Are you sure you want to delete { count, plural, 1 {1 rule chain} other {# rule chains} }?", "delete-rulechains-action-title": "Delete { count, plural, 1 {1 rule chain} other {# rule chains} }", "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.", - "add-rulechain-text": "Add new rule chain", - "no-rulechains-text": "No rule chains found", - "rulechain-details": "Rule chain details", - "details": "Details", - "events": "Events", - "system": "System", - "import": "Import rule chain", - "export": "Export rule chain", + "add-rulechain-text": "새로운 규칙 사슬 추가", + "no-rulechains-text": "아무 규칙 사슬도 없습니다.", + "rulechain-details": "규칙 사슬 상세 정보", + "details": "자세히", + "events": "이벤트", + "system": "시스템", + "import": "규칙 사슬 불러오기", + "export": "규칙 사슬 내보내기", "export-failed-error": "Unable to export rule chain: {{error}}", "create-new-rulechain": "Create new rule chain", "rulechain-file": "Rule chain file", @@ -1029,70 +1034,70 @@ "debug-mode": "Debug mode" }, "rulenode": { - "details": "Details", - "events": "Events", - "search": "Search nodes", - "open-node-library": "Open node library", - "add": "Add rule node", - "name": "Name", - "name-required": "Name is required.", - "type": "Type", - "description": "Description", - "delete": "Delete rule node", - "select-all-objects": "Select all nodes and connections", - "deselect-all-objects": "Deselect all nodes and connections", - "delete-selected-objects": "Delete selected nodes and connections", - "delete-selected": "Delete selected", - "select-all": "Select all", - "copy-selected": "Copy selected", - "deselect-all": "Deselect all", - "rulenode-details": "Rule node details", - "debug-mode": "Debug mode", - "configuration": "Configuration", - "link": "Link", - "link-details": "Rule node link details", - "add-link": "Add link", - "link-label": "Link label", - "link-label-required": "Link label is required.", - "custom-link-label": "Custom link label", - "custom-link-label-required": "Custom link label is required.", - "type-filter": "Filter", + "details": "자세히", + "events": "이벤트", + "search": "노드 검색", + "open-node-library": "노드 라이브러리 열기", + "add": "규칙 노드 추가", + "name": "이름", + "name-required": "이름을 입력하세요.", + "type": "종류", + "description": "설명", + "delete": "규칙 노드 삭제", + "select-all-objects": "모든 노드와 연결을 선택", + "deselect-all-objects": "모든 노드와 연결을 선택 해제", + "delete-selected-objects": "선택된 노드와 연결을 삭제", + "delete-selected": "선택 삭제", + "select-all": "모두 선택", + "copy-selected": "선택 복사", + "deselect-all": "선택 해제", + "rulenode-details": "규칙 노드 상세 정보", + "debug-mode": "디버그 모드", + "configuration": "설정", + "link": "링크", + "link-details": "규칙 노드 링크 상세 정보", + "add-link": "링크 추가", + "link-label": "링크 라벨", + "link-label-required": "링크 라벨을 입력하세요.", + "custom-link-label": "링크 라벨 사용자 정의", + "custom-link-label-required": "링크 라벨 사용자 정의를 입력하세요.", + "type-filter": "필터", "type-filter-details": "Filter incoming messages with configured conditions", "type-enrichment": "Enrichment", "type-enrichment-details": "Add additional information into Message Metadata", "type-transformation": "Transformation", "type-transformation-details": "Change Message payload and Metadata", - "type-action": "Action", + "type-action": "", "type-action-details": "Perform special action", - "type-external": "External", + "type-external": "외부", "type-external-details": "Interacts with external system", "type-rule-chain": "Rule Chain", "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", - "type-input": "Input", + "type-input": "입력", "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.", "ui-resources-load-error": "Failed to load configuration ui resources.", "invalid-target-rulechain": "Unable to resolve target rule chain!", "test-script-function": "Test script function", - "message": "Message", - "message-type": "Message type", - "message-type-required": "Message type is required", - "metadata": "Metadata", - "metadata-required": "Metadata entries can't be empty.", - "output": "Output", - "test": "Test", - "help": "Help" + "message": "메시지", + "message-type": "메시지 종류", + "message-type-required": "메시지 종류를 입력하세요.", + "metadata": "메타데이터", + "metadata-required": "메타데이터 엔트리를 입력하세요.", + "output": "출력", + "test": "테스트", + "help": "도움말" }, "tenant": { "tenants": "테넌트", "management": "테넌트 관리", "add": "테넌트 추가", - "admins": "Admins", + "admins": "관리자", "manage-tenant-admins": "테넌트 관리자 관리", "delete": "테넌트 삭제", "add-tenant-text": "테넌트 추가", "no-tenants-text": "테넌트가 없습니다.", - "tenant-details": "테넌트 상세정보", + "tenant-details": "테넌트 상세 정보", "delete-tenant-title": "'{{tenantTitle}}' 테넌트를 삭제하시겠습니까?", "delete-tenant-text": "테넌트와 관련된 모든 정보를 복구할 수 없으므로 주의하십시오.", "delete-tenants-title": "{ count, plural, 1 {테넌트 1개} other {테넌트 #개} }를 삭제하시겠습니까?", @@ -1101,23 +1106,23 @@ "title": "타이틀", "title-required": "타이틀을 입력하세요.", "description": "설명", - "details": "Details", - "events": "Events", - "copyId": "Copy tenant Id", - "idCopiedMessage": "Tenant Id has been copied to clipboard", - "select-tenant": "Select tenant", + "details": "자세히", + "events": "이벤트", + "copyId": "테넌트 ID 복사", + "idCopiedMessage": "테넌트 ID를 클립보드로 복사", + "select-tenant": "테넌트 선택", "no-tenants-matching": "No tenants matching '{{entity}}' were found.", - "tenant-required": "Tenant is required" + "tenant-required": "테넌트가 필요합니다." }, "timeinterval": { "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", "hours-interval": "{ hours, plural, 1 {1 hour} other {# hours} }", "days-interval": "{ days, plural, 1 {1 day} other {# days} }", - "days": "Days", - "hours": "Hours", - "minutes": "Minutes", - "seconds": "Seconds", + "days": "일", + "hours": "시간", + "minutes": "분", + "seconds": "초", "advanced": "고급" }, "timewindow": { @@ -1125,13 +1130,13 @@ "hours": "{ hours, plural, 0 { hour } 1 {1 hour } other {# hours } }", "minutes": "{ minutes, plural, 0 { minute } 1 {1 minute } other {# minutes } }", "seconds": "{ seconds, plural, 0 { second } 1 {1 second } other {# seconds } }", - "realtime": "Realtime", - "history": "History", - "last-prefix": "last", - "period": "from {{ startTime }} to {{ endTime }}", + "realtime": "실시간", + "history": "기록", + "last-prefix": "과거", + "period": "{{ startTime }}부터 {{ endTime }}까지", "edit": "타임윈도우 편집", "date-range": "날짜 범위", - "last": "Last", + "last": "과거", "time-period": "기간" }, "user": { @@ -1146,7 +1151,7 @@ "delete": "사용자 삭제", "add-user-text": "새로운 사용자 추가", "no-users-text": "사용자가 없습니다.", - "user-details": "사용자 상세정보", + "user-details": "사용자 상세 정보", "delete-user-title": "'{{userEmail}}' 사용자를 삭제하시겠습니까?", "delete-user-text": "사용자와 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", "delete-users-title": "{ count, plural, 1 {사용자 1명} other {사용자 #명} }을 삭제하시겠니까?", @@ -1242,10 +1247,10 @@ "update-dashboard-state": "Update current dashboard state", "open-dashboard": "Navigate to other dashboard", "custom": "Custom action", - "target-dashboard-state": "Target dashboard state", - "target-dashboard-state-required": "Target dashboard state is required", - "set-entity-from-widget": "Set entity from widget", - "target-dashboard": "Target dashboard", + "target-dashboard-state": "대상 대시보드 상태", + "target-dashboard-state-required": "대상 대시보드 상태가 필요합니다.", + "set-entity-from-widget": "위젯으로 부터 객체 설정", + "target-dashboard": "대상 대시보드", "open-right-layout": "Open right dashboard layout (mobile view)" }, "widgets-bundle": { @@ -1253,13 +1258,13 @@ "widgets-bundles": "위젯 번들", "add": "위젯 번들 추가", "delete": "위젯 번들 삭제", - "title": "타이틀", - "title-required": "타이틀을 입력하세요.", + "title": "제목", + "title-required": "제목을 입력하세요.", "add-widgets-bundle-text": "위젯 번들 추가", "no-widgets-bundles-text": "위젯 번들이 없습니다.", "empty": "위젯 번들이 비어있습니다.", "details": "상세", - "widgets-bundle-details": "위젯 번들 상세정보", + "widgets-bundle-details": "위젯 번들 상세 정보", "delete-widgets-bundle-title": "'{{widgetsBundleTitle}}' 위젯 번들을 삭제하시겠습니까?", "delete-widgets-bundle-text": "위젯 번들과 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", "delete-widgets-bundles-title": "{ count, plural, 1 {위젯 번들 1개} other {위젯 번들 #개} }를 삭제하시겠습니까?", @@ -1279,15 +1284,15 @@ "data": "데이터", "settings": "설정", "advanced": "고급", - "title": "타이틀", + "title": "제목", "general-settings": "일반 설정", - "display-title": "타이틀 표시", + "display-title": "제목 표시", "drop-shadow": "그림자", "enable-fullscreen": "전체화면 사용 ", "background-color": "배경 색", "text-color": "글자 색", "padding": "패딩", - "title-style": "타이틀 스타일", + "title-style": "제목 스타일", "mobile-mode-settings": "모바일 모드 설정", "order": "순서", "height": "높이", @@ -1333,18 +1338,18 @@ "Oct": "10월", "Nov": "11월", "Dec": "12월", - "January": "일월", - "February": "이월", - "March": "행진", - "April": "4 월", - "June": "유월", - "July": "칠월", - "August": "팔월", - "September": "구월", - "October": "십월", - "November": "십일월", - "December": "12 월", - "Custom Date Range": "맞춤 기간", + "January": "1월", + "February": "2월", + "March": "3월", + "April": "4월", + "June": "6월", + "July": "7월", + "August": "8월", + "September": "9월", + "October": "10월", + "November": "11월", + "December": "12월", + "Custom Date Range": "임의 기간 범위", "Date Range Template": "기간 템플릿", "Today": "오늘", "Yesterday": "어제", @@ -1359,22 +1364,22 @@ "Hour": "시간", "Day": "일", "Week": "주", - "2 weeks": "이주", + "2 weeks": "2 주", "Month": "달", "3 months": "3 개월", "6 months": "6 개월", "Custom interval": "사용자 지정 간격", "Interval": "간격", "Step size": "단계 크기", - "Ok": "Ok" + "Ok": "확인" } } }, "icon": { - "icon": "Icon", - "select-icon": "Select icon", + "icon": "아이콘", + "select-icon": "선택된 아이콘", "material-icons": "Material icons", - "show-all": "Show all icons" + "show-all": "모든 아이콘 보기" }, "custom": { "widget-action": { From aa82a478cbc704a37a5449b844e752868ca9cd82 Mon Sep 17 00:00:00 2001 From: Chantsova Ekaterina Date: Tue, 6 Oct 2020 10:36:21 +0300 Subject: [PATCH 14/14] Fix wrong number of digits after floating point in legend --- ui-ngx/src/app/core/api/widget-subscription.ts | 4 ++-- .../src/app/modules/home/components/widget/lib/flot-widget.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 9d046bbf83..c574fd426a 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -47,7 +47,7 @@ import { import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'; import { CancelAnimationFrame } from '@core/services/raf.service'; import { EntityType } from '@shared/models/entity-type.models'; -import { createLabelFromDatasource, deepClone, isDefined, isEqual } from '@core/utils'; +import { createLabelFromDatasource, deepClone, isDefined, isDefinedAndNotNull, isEqual } from '@core/utils'; import { EntityId } from '@app/shared/models/id/entity-id'; import * as moment_ from 'moment'; import { emptyPageData, PageData } from '@shared/models/page/page-data'; @@ -1332,7 +1332,7 @@ export class WidgetSubscription implements IWidgetSubscription { private updateLegend(dataIndex: number, data: DataSet, detectChanges: boolean) { const dataKey = this.legendData.keys.find(key => key.dataIndex === dataIndex).dataKey; - const decimals = isDefined(dataKey.decimals) ? dataKey.decimals : this.decimals; + const decimals = isDefinedAndNotNull(dataKey.decimals) ? dataKey.decimals : this.decimals; const units = dataKey.units && dataKey.units.length ? dataKey.units : this.units; const legendKeyData = this.legendData.data[dataIndex]; if (this.legendConfig.showMin) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index d334d5c99a..03f6d1b975 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -380,7 +380,7 @@ export class TbFlot { const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; const predefinedThresholds: TbFlotThresholdMarking[] = []; const thresholdsDatasources: Datasource[] = []; - if (this.settings.customLegendEnabled) { + if (this.settings.customLegendEnabled && this.settings.dataKeysListForLabels?.length) { this.labelPatternsSourcesData = []; const labelPatternsDatasources: Datasource[] = []; this.settings.dataKeysListForLabels.forEach((item) => {