Commit f9574d7041a453efaa9cc72a836c6231b3880b76

Authored by Adsumus
2 parents 8979a511 a868f006

Merge branch 'develop/3.0' of https://github.com/thingsboard/thingsboard into map/3.0

Showing 34 changed files with 187 additions and 174 deletions
... ... @@ -13,9 +13,9 @@ Before performing initial installation you can configure the type of database to
13 13 In order to set database type change the value of `DATABASE` variable in `.env` file to one of the following:
14 14
15 15 - `postgres` - use PostgreSQL database;
16   -- `cassandra` - use Cassandra database;
  16 +- `hybrid` - use PostgreSQL for entities database and Cassandra for timeseries database;
17 17
18   -**NOTE**: According to the database type corresponding docker service will be deployed (see `docker-compose.postgres.yml`, `docker-compose.cassandra.yml` for details).
  18 +**NOTE**: According to the database type corresponding docker service will be deployed (see `docker-compose.postgres.yml`, `docker-compose.hybrid.yml` for details).
19 19
20 20 Execute the following command to create log folders for the services and chown of these folders to the docker container users.
21 21 To be able to change user, **chown** command is used, which requires sudo permissions (script will request password for a sudo access):
... ...
1 1 {
2 2 "name": "thingsboard-js-executor",
3   - "version": "2.4.3",
  3 + "version": "3.0.0",
4 4 "lockfileVersion": 1,
5 5 "requires": true,
6 6 "dependencies": {
... ...
1 1 {
2 2 "name": "thingsboard-web-ui",
3   - "version": "2.4.3",
  3 + "version": "3.0.0",
4 4 "lockfileVersion": 1,
5 5 "requires": true,
6 6 "dependencies": {
... ...
... ... @@ -49,7 +49,6 @@
49 49 ]
50 50 },
51 51 "scripts": [
52   - "node_modules/javascript-detect-element-resize/detect-element-resize.js",
53 52 "node_modules/jquery/dist/jquery.min.js",
54 53 "node_modules/jquery.terminal/js/jquery.terminal.min.js",
55 54 "node_modules/flot/lib/jquery.colorhelpers.js",
... ...
... ... @@ -1561,6 +1561,11 @@
1561 1561 }
1562 1562 }
1563 1563 },
  1564 + "@juggle/resize-observer": {
  1565 + "version": "3.1.3",
  1566 + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.1.3.tgz",
  1567 + "integrity": "sha512-y7qc6SzZBlSpx8hEDfV0S9Cx6goROX/vBhS2Ru1Q78Jp1FlCMbxp7UcAN90rLgB3X8DSMBgDFxcmoG/VfdAhFA=="
  1568 + },
1564 1569 "@mat-datetimepicker/core": {
1565 1570 "version": "4.1.0",
1566 1571 "resolved": "https://registry.npmjs.org/@mat-datetimepicker/core/-/core-4.1.0.tgz",
... ... @@ -7083,11 +7088,6 @@
7083 7088 "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=",
7084 7089 "dev": true
7085 7090 },
7086   - "javascript-detect-element-resize": {
7087   - "version": "0.5.3",
7088   - "resolved": "https://registry.npmjs.org/javascript-detect-element-resize/-/javascript-detect-element-resize-0.5.3.tgz",
7089   - "integrity": "sha1-GnHNUd/lZZB/KZAS/nOilBBAJd4="
7090   - },
7091 7091 "jest-worker": {
7092 7092 "version": "25.1.0",
7093 7093 "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz",
... ...
... ... @@ -28,6 +28,7 @@
28 28 "@date-io/date-fns": "^2.6.1",
29 29 "@flowjs/flow.js": "^2.14.0",
30 30 "@flowjs/ngx-flow": "^0.4.3",
  31 + "@juggle/resize-observer": "^3.1.3",
31 32 "@mat-datetimepicker/core": "^4.1.0",
32 33 "@material-ui/core": "^4.9.11",
33 34 "@material-ui/icons": "^4.9.1",
... ... @@ -49,7 +50,6 @@
49 50 "flot": "git://github.com/thingsboard/flot.git#0.9-work",
50 51 "flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master",
51 52 "font-awesome": "^4.7.0",
52   - "javascript-detect-element-resize": "^0.5.3",
53 53 "jquery": "^3.5.0",
54 54 "jquery.terminal": "^2.15.4",
55 55 "js-beautify": "^1.11.0",
... ...
... ... @@ -123,7 +123,7 @@ export class AliasController implements IAliasController {
123 123 }
124 124
125 125 getAliasInfo(aliasId: string): Observable<AliasInfo> {
126   - const aliasInfo = this.resolvedAliases[aliasId];
  126 + let aliasInfo = this.resolvedAliases[aliasId];
127 127 if (aliasInfo) {
128 128 return of(aliasInfo);
129 129 } else if (this.resolvedAliasesObservable[aliasId]) {
... ... @@ -159,7 +159,12 @@ export class AliasController implements IAliasController {
159 159 delete this.resolvedAliasesObservable[aliasId];
160 160 return res;
161 161 }
162   - return this.resolvedAliasesObservable[aliasId];
  162 + aliasInfo = this.resolvedAliases[aliasId];
  163 + if (aliasInfo) {
  164 + return of(aliasInfo);
  165 + } else {
  166 + return this.resolvedAliasesObservable[aliasId];
  167 + }
163 168 }
164 169 }
165 170
... ...
... ... @@ -19,7 +19,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
19 19 import { Store } from '@ngrx/store';
20 20 import { AppState } from '@core/core.state';
21 21 import { FormBuilder, FormGroup } from '@angular/forms';
22   -import { Observable, Subject } from 'rxjs';
  22 +import { Observable, ReplaySubject } from 'rxjs';
23 23 import { Router } from '@angular/router';
24 24 import { DialogComponent } from '@app/shared/components/dialog.component';
25 25 import {
... ... @@ -30,7 +30,7 @@ import {
30 30 alarmStatusTranslations
31 31 } from '@app/shared/models/alarm.models';
32 32 import { AlarmService } from '@core/http/alarm.service';
33   -import { share, tap } from 'rxjs/operators';
  33 +import { tap } from 'rxjs/operators';
34 34 import { DatePipe } from '@angular/common';
35 35 import { TranslateService } from '@ngx-translate/core';
36 36
... ... @@ -54,10 +54,9 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
54 54 allowClear: boolean;
55 55 displayDetails: boolean;
56 56
57   - loadAlarmSubject = new Subject<AlarmInfo>();
  57 + loadAlarmSubject = new ReplaySubject<AlarmInfo>();
58 58 alarm$: Observable<AlarmInfo> = this.loadAlarmSubject.asObservable().pipe(
59   - tap(alarm => this.loadAlarmFields(alarm)),
60   - share()
  59 + tap(alarm => this.loadAlarmFields(alarm))
61 60 );
62 61
63 62 alarmSeverityColorsMap = alarmSeverityColors;
... ...
... ... @@ -43,6 +43,6 @@ export class AlarmTableHeaderComponent extends EntityTableHeaderComponent<AlarmI
43 43
44 44 searchStatusChanged(searchStatus: AlarmSearchStatus) {
45 45 this.alarmTableConfig.searchStatus = searchStatus;
46   - this.alarmTableConfig.table.updateData();
  46 + this.alarmTableConfig.table.resetSortAndFilter(true, true);
47 47 }
48 48 }
... ...
... ... @@ -63,12 +63,16 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
63 63 ngOnInit(): void {
64 64 this.rxSubscriptions.push(this.aliasController.entityAliasesChanged.subscribe(
65 65 () => {
66   - this.updateDisplayValue();
  66 + setTimeout(() => {
  67 + this.updateDisplayValue();
  68 + }, 0);
67 69 }
68 70 ));
69 71 this.rxSubscriptions.push(this.aliasController.entityAliasResolved.subscribe(
70 72 () => {
71   - this.updateDisplayValue();
  73 + setTimeout(() => {
  74 + this.updateDisplayValue();
  75 + }, 0);
72 76 }
73 77 ));
74 78 }
... ...
... ... @@ -53,6 +53,7 @@ import { Widget, WidgetPosition } from '@app/shared/models/widget.models';
53 53 import { MatMenuTrigger } from '@angular/material/menu';
54 54 import { SafeStyle } from '@angular/platform-browser';
55 55 import { distinct } from 'rxjs/operators';
  56 +import { ResizeObserver } from '@juggle/resize-observer';
56 57
57 58 @Component({
58 59 selector: 'tb-dashboard',
... ... @@ -166,7 +167,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
166 167
167 168 private optionsChangeNotificationsPaused = false;
168 169
169   - private gridsterResizeListener = null;
  170 + private gridsterResize$: ResizeObserver;
170 171
171 172 constructor(protected store: Store<AppState>,
172 173 private timeService: TimeService,
... ... @@ -225,9 +226,8 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
225 226
226 227 ngOnDestroy(): void {
227 228 super.ngOnDestroy();
228   - if (this.gridsterResizeListener) {
229   - // @ts-ignore
230   - removeResizeListener(this.gridster.el, this.gridsterResizeListener);
  229 + if (this.gridsterResize$) {
  230 + this.gridsterResize$.disconnect();
231 231 }
232 232 if (this.breakpointObserverSubscription) {
233 233 this.breakpointObserverSubscription.unsubscribe();
... ... @@ -290,9 +290,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
290 290 }
291 291
292 292 ngAfterViewInit(): void {
293   - this.gridsterResizeListener = this.onGridsterParentResize.bind(this);
294   - // @ts-ignore
295   - addResizeListener(this.gridster.el, this.gridsterResizeListener);
  293 + this.gridsterResize$ = new ResizeObserver(() => {
  294 + this.onGridsterParentResize()
  295 + });
  296 + this.gridsterResize$.observe(this.gridster.el);
296 297 }
297 298
298 299 onUpdateTimewindow(startTimeMs: number, endTimeMs: number, interval?: number, persist?: boolean): void {
... ... @@ -491,8 +492,8 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
491 492 const parentHeight = this.gridster.el.offsetHeight;
492 493 if (this.isMobileSize && this.mobileAutofillHeight && parentHeight) {
493 494 this.updateMobileOpts(parentHeight);
494   - this.notifyGridsterOptionsChanged();
495 495 }
  496 + this.notifyGridsterOptionsChanged();
496 497 }
497 498
498 499 private updateLayoutOpts() {
... ...
... ... @@ -434,9 +434,9 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn
434 434 this.updateData();
435 435 }
436 436
437   - resetSortAndFilter(update: boolean = true) {
  437 + resetSortAndFilter(update: boolean = true, preserveTimewindow: boolean = false) {
438 438 this.pageLink.textSearch = null;
439   - if (this.entitiesTableConfig.useTimePageLink) {
  439 + if (this.entitiesTableConfig.useTimePageLink && !preserveTimewindow) {
440 440 this.timewindow = historyInterval(DAY);
441 441 }
442 442 if (this.displayPagination) {
... ...
... ... @@ -40,6 +40,6 @@ export class EventTableHeaderComponent extends EntityTableHeaderComponent<Event>
40 40
41 41 eventTypeChanged(eventType: EventType | DebugEventType) {
42 42 this.eventTableConfig.eventType = eventType;
43   - this.eventTableConfig.table.updateData();
  43 + this.eventTableConfig.table.resetSortAndFilter(true, true);
44 44 }
45 45 }
... ...
... ... @@ -35,6 +35,7 @@ import { CustomActionDescriptor } from '@shared/models/widget.models';
35 35 import * as ace from 'ace-builds';
36 36 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
37 37 import { css_beautify, html_beautify } from 'js-beautify';
  38 +import { ResizeObserver } from '@juggle/resize-observer';
38 39
39 40 @Component({
40 41 selector: 'tb-custom-action-pretty-resources-tabs',
... ... @@ -64,7 +65,7 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
64 65
65 66 aceEditors: ace.Ace.Editor[] = [];
66 67 editorsResizeCafs: {[editorId: string]: CancelAnimationFrame} = {};
67   - aceResizeListeners: { element: any, resizeListener: any }[] = [];
  68 + aceResize$: ResizeObserver;
68 69 htmlEditor: ace.Ace.Editor;
69 70 cssEditor: ace.Ace.Editor;
70 71 setValuesPending = false;
... ... @@ -84,10 +85,7 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
84 85 }
85 86
86 87 ngOnDestroy(): void {
87   - this.aceResizeListeners.forEach((resizeListener) => {
88   - // @ts-ignore
89   - removeResizeListener(resizeListener.element, resizeListener.resizeListener);
90   - });
  88 + this.aceResize$.disconnect();
91 89 }
92 90
93 91 ngOnChanges(changes: SimpleChanges): void {
... ... @@ -153,6 +151,12 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
153 151 }
154 152
155 153 private initAceEditors() {
  154 + this.aceResize$ = new ResizeObserver((entries) => {
  155 + entries.forEach((entry) => {
  156 + const editor = this.aceEditors.find(aceEditor => aceEditor.container === entry.target);
  157 + this.onAceEditorResize(editor);
  158 + })
  159 + });
156 160 this.htmlEditor = this.createAceEditor(this.htmlInputElmRef, 'html');
157 161 this.htmlEditor.on('input', () => {
158 162 const editorValue = this.htmlEditor.getValue();
... ... @@ -187,12 +191,7 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
187 191 const aceEditor = ace.edit(editorElement, editorOptions);
188 192 aceEditor.session.setUseWrapMode(true);
189 193 this.aceEditors.push(aceEditor);
190   -
191   - const resizeListener = this.onAceEditorResize.bind(this, aceEditor);
192   -
193   - // @ts-ignore
194   - addResizeListener(editorElement, resizeListener);
195   - this.aceResizeListeners.push({element: editorElement, resizeListener});
  194 + this.aceResize$.observe(editorElement);
196 195 return aceEditor;
197 196 }
198 197
... ...
... ... @@ -84,9 +84,6 @@ export class DateRangeNavigatorWidgetComponent extends PageComponent implements
84 84 }
85 85
86 86 ngOnInit(): void {
87   - this.dashboardTimewindowChangedSubscription = this.ctx.dashboard.dashboardTimewindowChanged.subscribe(() => {
88   - this.widgetContextTimewindowSync();
89   - });
90 87 this.settings = this.ctx.settings;
91 88 this.settings.useSessionStorage = isDefined(this.settings.useSessionStorage) ? this.settings.useSessionStorage : true;
92 89 let selection;
... ... @@ -110,6 +107,9 @@ export class DateRangeNavigatorWidgetComponent extends PageComponent implements
110 107 }
111 108 this.selectedStepSize = this.datesMap[this.settings.stepSize || 'day'].ts;
112 109 this.widgetContextTimewindowSync();
  110 + this.dashboardTimewindowChangedSubscription = this.ctx.dashboard.dashboardTimewindowChanged.subscribe(() => {
  111 + this.widgetContextTimewindowSync();
  112 + });
113 113 }
114 114
115 115 ngOnDestroy(): void {
... ...
... ... @@ -58,6 +58,7 @@ import { AttributeData, AttributeScope } from '@shared/models/telemetry/telemetr
58 58 import { forkJoin, Observable } from 'rxjs';
59 59 import { tap } from 'rxjs/operators';
60 60 import { ImportExportService } from '@home/components/import-export/import-export.service';
  61 +import { ResizeObserver } from '@juggle/resize-observer';
61 62
62 63 // @dynamic
63 64 @Component({
... ... @@ -93,7 +94,7 @@ export class GatewayFormComponent extends PageComponent implements OnInit, OnDes
93 94 private successfulSaved: string;
94 95 private gatewayNameExists: string;
95 96 private archiveFileName: string;
96   - private formResizeListener: any;
  97 + private formResize$: ResizeObserver;
97 98 private subscribeStorageType$: any;
98 99 private subscribeGateway$: any;
99 100
... ... @@ -116,15 +117,15 @@ export class GatewayFormComponent extends PageComponent implements OnInit, OnDes
116 117
117 118 this.buildForm();
118 119 this.ctx.updateWidgetParams();
119   - this.formResizeListener = this.resize.bind(this);
120   - // @ts-ignore
121   - addResizeListener(this.formContainerRef.nativeElement, this.formResizeListener);
  120 + this.formResize$ = new ResizeObserver(() => {
  121 + this.resize();
  122 + });
  123 + this.formResize$.observe(this.formContainerRef.nativeElement);
122 124 }
123 125
124 126 ngOnDestroy(): void {
125   - if (this.formResizeListener) {
126   - // @ts-ignore
127   - removeResizeListener(this.formContainerRef.nativeElement, this.formResizeListener);
  127 + if (this.formResize$) {
  128 + this.formResize$.disconnect();
128 129 }
129 130 this.subscribeGateway$.unsubscribe();
130 131 this.subscribeStorageType$.unsubscribe();
... ...
... ... @@ -33,6 +33,7 @@ import { AttributeService } from '@core/http/attribute.service';
33 33 import { AttributeData, AttributeScope, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
34 34 import { forkJoin, Observable } from 'rxjs';
35 35 import { EntityId } from '@shared/models/id/entity-id';
  36 +import { ResizeObserver } from '@juggle/resize-observer';
36 37
37 38 type FieldAlignment = 'row' | 'column';
38 39
... ... @@ -94,7 +95,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
94 95 @Input()
95 96 ctx: WidgetContext;
96 97
97   - private formResizeListener: any;
  98 + private formResize$: ResizeObserver;
98 99 private settings: MultipleInputWidgetSettings;
99 100 private widgetConfig: WidgetConfig;
100 101 private subscription: IWidgetSubscription;
... ... @@ -135,15 +136,15 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
135 136 this.updateDatasources();
136 137 this.buildForm();
137 138 this.ctx.updateWidgetParams();
138   - this.formResizeListener = this.resize.bind(this);
139   - // @ts-ignore
140   - addResizeListener(this.formContainerRef.nativeElement, this.formResizeListener);
  139 + this.formResize$ = new ResizeObserver(() => {
  140 + this.resize();
  141 + });
  142 + this.formResize$.observe(this.formContainerRef.nativeElement);
141 143 }
142 144
143 145 ngOnDestroy(): void {
144   - if (this.formResizeListener) {
145   - // @ts-ignore
146   - removeResizeListener(this.formContainerRef.nativeElement, this.formResizeListener);
  146 + if (this.formResize$) {
  147 + this.formResize$.disconnect();
147 148 }
148 149 }
149 150
... ...
... ... @@ -22,9 +22,9 @@ import { Store } from '@ngrx/store';
22 22 import { AppState } from '@core/core.state';
23 23 import { isDefined, isNumber } from '@core/utils';
24 24 import { CanvasDigitalGauge, CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge';
25   -import GenericOptions = CanvasGauges.GenericOptions;
26 25 import * as tinycolor_ from 'tinycolor2';
27   -import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
  26 +import GenericOptions = CanvasGauges.GenericOptions;
  27 +import { ResizeObserver } from '@juggle/resize-observer';
28 28
29 29 const tinycolor = tinycolor_;
30 30
... ... @@ -103,7 +103,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
103 103
104 104 private canvasBar: CanvasDigitalGauge;
105 105
106   - private knobResizeListener: any;
  106 + private knobResize$: ResizeObserver;
107 107
108 108 constructor(private utils: UtilsService,
109 109 protected store: Store<AppState>) {
... ... @@ -126,16 +126,16 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
126 126 this.textMeasure = $(this.textMeasureRef.nativeElement);
127 127 this.canvasBarElement = this.canvasBarElementRef.nativeElement;
128 128
129   - this.knobResizeListener = this.resize.bind(this);
130   - // @ts-ignore
131   - addResizeListener(this.knobContainerRef.nativeElement, this.knobResizeListener);
  129 + this.knobResize$ = new ResizeObserver(() => {
  130 + this.resize();
  131 + });
  132 + this.knobResize$.observe(this.knobContainerRef.nativeElement);
132 133 this.init();
133 134 }
134 135
135 136 ngOnDestroy(): void {
136   - if (this.knobResizeListener) {
137   - // @ts-ignore
138   - removeResizeListener(this.knobContainerRef.nativeElement, this.knobResizeListener);
  137 + if (this.knobResize$) {
  138 + this.knobResize$.disconnect();
139 139 }
140 140 }
141 141
... ...
... ... @@ -25,6 +25,7 @@ import { UtilsService } from '@core/services/utils.service';
25 25 import { IWidgetSubscription, SubscriptionInfo, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
26 26 import { DatasourceType, widgetType } from '@shared/models/widget.models';
27 27 import { EntityType } from '@shared/models/entity-type.models';
  28 +import { ResizeObserver } from '@juggle/resize-observer';
28 29 import Timeout = NodeJS.Timeout;
29 30
30 31 const tinycolor = tinycolor_;
... ... @@ -93,7 +94,7 @@ export class LedIndicatorComponent extends PageComponent implements OnInit, OnDe
93 94 private ledErrorContainer: JQuery<HTMLElement>;
94 95 private ledError: JQuery<HTMLElement>;
95 96
96   - private ledResizeListener: any;
  97 + private ledResize$: ResizeObserver;
97 98
98 99 private subscriptionOptions: WidgetSubscriptionOptions = {
99 100 callbacks: {
... ... @@ -122,9 +123,10 @@ export class LedIndicatorComponent extends PageComponent implements OnInit, OnDe
122 123 this.ledErrorContainer = $(this.ledErrorContainerRef.nativeElement);
123 124 this.ledError = $(this.ledErrorRef.nativeElement);
124 125
125   - this.ledResizeListener = this.resize.bind(this);
126   - // @ts-ignore
127   - addResizeListener(this.ledContainerRef.nativeElement, this.ledResizeListener);
  126 + this.ledResize$ = new ResizeObserver(() => {
  127 + this.resize();
  128 + });
  129 + this.ledResize$.observe(this.ledContainerRef.nativeElement);
128 130 this.init();
129 131 }
130 132
... ... @@ -136,9 +138,8 @@ export class LedIndicatorComponent extends PageComponent implements OnInit, OnDe
136 138 if (this.subscription) {
137 139 this.ctx.subscriptionApi.removeSubscription(this.subscription.id);
138 140 }
139   - if (this.ledResizeListener) {
140   - // @ts-ignore
141   - removeResizeListener(this.ledContainerRef.nativeElement, this.ledResizeListener);
  141 + if (this.ledResize$) {
  142 + this.ledResize$.disconnect();
142 143 }
143 144 }
144 145
... ...
... ... @@ -14,7 +14,7 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
  17 +import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
18 18 import { PageComponent } from '@shared/components/page.component';
19 19 import { WidgetContext } from '@home/models/widget-component.models';
20 20 import { UtilsService } from '@core/services/utils.service';
... ... @@ -24,6 +24,7 @@ import { isDefined } from '@core/utils';
24 24 import { IWidgetSubscription, SubscriptionInfo, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
25 25 import { DatasourceType, widgetType } from '@shared/models/widget.models';
26 26 import { EntityType } from '@shared/models/entity-type.models';
  27 +import { ResizeObserver } from '@juggle/resize-observer';
27 28
28 29 type RetrieveValueMethod = 'rpc' | 'attribute' | 'timeseries';
29 30
... ... @@ -88,7 +89,7 @@ export class RoundSwitchComponent extends PageComponent implements OnInit, OnDes
88 89 private switchErrorContainer: JQuery<HTMLElement>;
89 90 private switchError: JQuery<HTMLElement>;
90 91
91   - private switchResizeListener: any;
  92 + private switchResize$: ResizeObserver;
92 93
93 94 constructor(private utils: UtilsService,
94 95 protected store: Store<AppState>) {
... ... @@ -110,20 +111,19 @@ export class RoundSwitchComponent extends PageComponent implements OnInit, OnDes
110 111 this.onValue();
111 112 });
112 113
113   - this.switchResizeListener = this.resize.bind(this);
114   - // @ts-ignore
115   - addResizeListener(this.switchContainerRef.nativeElement, this.switchResizeListener);
  114 + this.switchResize$ = new ResizeObserver(() => {
  115 + this.resize();
  116 + });
  117 + this.switchResize$.observe(this.switchContainerRef.nativeElement);
116 118 this.init();
117   - // this.ctx.resize = this.resize.bind(this);
118 119 }
119 120
120 121 ngOnDestroy(): void {
121 122 if (this.valueSubscription) {
122 123 this.ctx.subscriptionApi.removeSubscription(this.valueSubscription.id);
123 124 }
124   - if (this.switchResizeListener) {
125   - // @ts-ignore
126   - removeResizeListener(this.switchContainerRef.nativeElement, this.switchResizeListener);
  125 + if (this.switchResize$) {
  126 + this.switchResize$.disconnect();
127 127 }
128 128 }
129 129
... ...
... ... @@ -25,6 +25,7 @@ import { IWidgetSubscription, SubscriptionInfo, WidgetSubscriptionOptions } from
25 25 import { DatasourceType, widgetType } from '@shared/models/widget.models';
26 26 import { EntityType } from '@shared/models/entity-type.models';
27 27 import { MatSlideToggle } from '@angular/material/slide-toggle';
  28 +import { ResizeObserver } from '@juggle/resize-observer';
28 29
29 30 const switchAspectRation = 2.7893;
30 31
... ... @@ -98,7 +99,7 @@ export class SwitchComponent extends PageComponent implements OnInit, OnDestroy
98 99 private switchErrorContainer: JQuery<HTMLElement>;
99 100 private switchError: JQuery<HTMLElement>;
100 101
101   - private switchResizeListener: any;
  102 + private switchResize$: ResizeObserver;
102 103
103 104 constructor(private utils: UtilsService,
104 105 protected store: Store<AppState>) {
... ... @@ -118,9 +119,10 @@ export class SwitchComponent extends PageComponent implements OnInit, OnDestroy
118 119 this.switchErrorContainer = $(this.switchErrorContainerRef.nativeElement);
119 120 this.switchError = $(this.switchErrorRef.nativeElement);
120 121
121   - this.switchResizeListener = this.resize.bind(this);
122   - // @ts-ignore
123   - addResizeListener(this.switchContainerRef.nativeElement, this.switchResizeListener);
  122 + this.switchResize$ = new ResizeObserver(() => {
  123 + this.resize();
  124 + })
  125 + this.switchResize$.observe(this.switchContainerRef.nativeElement);
124 126 this.init();
125 127 }
126 128
... ... @@ -128,9 +130,8 @@ export class SwitchComponent extends PageComponent implements OnInit, OnDestroy
128 130 if (this.valueSubscription) {
129 131 this.ctx.subscriptionApi.removeSubscription(this.valueSubscription.id);
130 132 }
131   - if (this.switchResizeListener) {
132   - // @ts-ignore
133   - removeResizeListener(this.switchContainerRef.nativeElement, this.switchResizeListener);
  133 + if (this.switchResize$) {
  134 + this.switchResize$.disconnect();
134 135 }
135 136 }
136 137
... ...
... ... @@ -91,6 +91,7 @@ import { DatasourceService } from '@core/api/datasource.service';
91 91 import { WidgetSubscription } from '@core/api/widget-subscription';
92 92 import { EntityService } from '@core/http/entity.service';
93 93 import { ServicesMap } from '@home/models/services.map';
  94 +import { ResizeObserver } from '@juggle/resize-observer';
94 95
95 96 @Component({
96 97 selector: 'tb-widget',
... ... @@ -140,7 +141,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
140 141
141 142 cafs: {[cafId: string]: CancelAnimationFrame} = {};
142 143
143   - onResizeListener = null;
  144 + private widgetResize$: ResizeObserver;
144 145
145 146 private cssParser = new cssjs();
146 147
... ... @@ -647,10 +648,8 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
647 648 }
648 649
649 650 private destroyDynamicWidgetComponent() {
650   - if (this.widgetContext.$containerParent && this.onResizeListener) {
651   - // @ts-ignore
652   - removeResizeListener(this.widgetContext.$containerParent[0], this.onResizeListener);
653   - this.onResizeListener = null;
  651 + if (this.widgetContext.$containerParent && this.widgetResize$) {
  652 + this.widgetResize$.disconnect()
654 653 }
655 654 if (this.dynamicWidgetComponentRef) {
656 655 this.dynamicWidgetComponentRef.destroy();
... ... @@ -709,9 +708,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
709 708 }
710 709 }
711 710
712   - this.onResizeListener = this.onResize.bind(this);
713   - // @ts-ignore
714   - addResizeListener(this.widgetContext.$containerParent[0], this.onResizeListener);
  711 + this.widgetResize$ = new ResizeObserver(() => {
  712 + this.onResize();
  713 + });
  714 + this.widgetResize$.observe(this.widgetContext.$containerParent[0]);
715 715 }
716 716
717 717 private createSubscription(options: WidgetSubscriptionOptions, subscribe?: boolean): Observable<IWidgetSubscription> {
... ...
... ... @@ -389,7 +389,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
389 389 padding: this.padding,
390 390 margin: this.margin};
391 391 if (this.widget.config.widgetStyle) {
392   - this.style = {...this.widget.config.widgetStyle, ...this.style};
  392 + this.style = {...this.style, ...this.widget.config.widgetStyle};
393 393 }
394 394
395 395 this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false :
... ... @@ -474,7 +474,8 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
474 474 if (mobileHeight) {
475 475 res = mobileHeight;
476 476 } else {
477   - res = this.widget.sizeY * 24 / this.dashboard.gridsterOpts.minCols;
  477 + const sizeY = this.widgetLayout ? this.widgetLayout.sizeY : this.widget.sizeY;
  478 + res = sizeY * 24 / this.dashboard.gridsterOpts.minCols;
478 479 }
479 480 } else {
480 481 if (this.widgetLayout) {
... ...
... ... @@ -36,7 +36,7 @@ export class AssetTableHeaderComponent extends EntityTableHeaderComponent<AssetI
36 36
37 37 assetTypeChanged(assetType: string) {
38 38 this.entitiesTableConfig.componentsData.assetType = assetType;
39   - this.entitiesTableConfig.table.updateData();
  39 + this.entitiesTableConfig.table.resetSortAndFilter(true);
40 40 }
41 41
42 42 }
... ...
... ... @@ -14,8 +14,7 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import { Component, OnDestroy, OnInit, ViewEncapsulation, Input, Output, EventEmitter } from '@angular/core';
18   -import { PageComponent } from '@shared/components/page.component';
  17 +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
19 18
20 19 @Component({
21 20 selector: 'tb-dashboard-toolbar',
... ...
... ... @@ -36,7 +36,7 @@ export class DeviceTableHeaderComponent extends EntityTableHeaderComponent<Devic
36 36
37 37 deviceTypeChanged(deviceType: string) {
38 38 this.entitiesTableConfig.componentsData.deviceType = deviceType;
39   - this.entitiesTableConfig.table.updateData();
  39 + this.entitiesTableConfig.table.resetSortAndFilter(true);
40 40 }
41 41
42 42 }
... ...
... ... @@ -36,7 +36,7 @@ export class EntityViewTableHeaderComponent extends EntityTableHeaderComponent<E
36 36
37 37 entityViewTypeChanged(entityViewType: string) {
38 38 this.entitiesTableConfig.componentsData.entityViewType = entityViewType;
39   - this.entitiesTableConfig.table.updateData();
  39 + this.entitiesTableConfig.table.resetSortAndFilter(true);
40 40 }
41 41
42 42 }
... ...
... ... @@ -46,6 +46,7 @@ import {
46 46 } from '@home/pages/widget/save-widget-type-as-dialog.component';
47 47 import { Subscription } from 'rxjs';
48 48 import Timeout = NodeJS.Timeout;
  49 +import { ResizeObserver } from '@juggle/resize-observer';
49 50
50 51 // @dynamic
51 52 @Component({
... ... @@ -124,7 +125,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
124 125 jsonSettingsEditor: ace.Ace.Editor;
125 126 dataKeyJsonSettingsEditor: ace.Ace.Editor;
126 127 jsEditor: ace.Ace.Editor;
127   - aceResizeListeners: { element: any, resizeListener: any }[] = [];
  128 + aceResize$: ResizeObserver;
128 129
129 130 onWindowMessageListener = this.onWindowMessage.bind(this);
130 131
... ... @@ -193,10 +194,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
193 194
194 195 ngOnDestroy(): void {
195 196 this.window.removeEventListener('message', this.onWindowMessageListener);
196   - this.aceResizeListeners.forEach((resizeListener) => {
197   - // @ts-ignore
198   - removeResizeListener(resizeListener.element, resizeListener.resizeListener);
199   - });
  197 + this.aceResize$.disconnect();
200 198 this.rxSubscriptions.forEach((subscription) => {
201 199 subscription.unsubscribe();
202 200 });
... ... @@ -272,6 +270,12 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
272 270 }
273 271
274 272 private initAceEditors() {
  273 + this.aceResize$ = new ResizeObserver((entries) => {
  274 + entries.forEach((entry) => {
  275 + const editor = this.aceEditors.find(aceEditor => aceEditor.container === entry.target);
  276 + this.onAceEditorResize(editor);
  277 + })
  278 + });
275 279 this.htmlEditor = this.createAceEditor(this.htmlInputElmRef, 'html');
276 280 this.htmlEditor.on('input', () => {
277 281 const editorValue = this.htmlEditor.getValue();
... ... @@ -342,12 +346,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
342 346 const aceEditor = ace.edit(editorElement, editorOptions);
343 347 aceEditor.session.setUseWrapMode(true);
344 348 this.aceEditors.push(aceEditor);
345   -
346   - const resizeListener = this.onAceEditorResize.bind(this, aceEditor);
347   -
348   - // @ts-ignore
349   - addResizeListener(editorElement, resizeListener);
350   - this.aceResizeListeners.push({element: editorElement, resizeListener});
  349 + this.aceResize$.observe(editorElement);
351 350 return aceEditor;
352 351 }
353 352
... ...
... ... @@ -93,7 +93,6 @@ export class BreadcrumbComponent implements OnInit, OnDestroy {
93 93 const icon = breadcrumbConfig.icon || 'home';
94 94 const isMdiIcon = icon.startsWith('mdi:');
95 95 const link = [ route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/') ];
96   - const queryParams = route.queryParams;
97 96 const breadcrumb = {
98 97 label,
99 98 labelFunction,
... ... @@ -101,7 +100,7 @@ export class BreadcrumbComponent implements OnInit, OnDestroy {
101 100 icon,
102 101 isMdiIcon,
103 102 link,
104   - queryParams
  103 + queryParams: null
105 104 };
106 105 newBreadcrumbs = [...breadcrumbs, breadcrumb];
107 106 }
... ...
... ... @@ -29,6 +29,7 @@ import {
29 29 } from '@angular/core';
30 30 import { WINDOW } from '@core/services/window.service';
31 31 import { CanColorCtor, mixinColor } from '@angular/material/core';
  32 +import { ResizeObserver } from '@juggle/resize-observer';
32 33
33 34 export declare type FabToolbarDirection = 'left' | 'right';
34 35
... ... @@ -77,14 +78,14 @@ export class FabActionsDirective implements OnInit {
77 78 })
78 79 export class FabToolbarComponent extends MatFabToolbarMixinBase implements OnInit, OnDestroy, AfterViewInit, OnChanges {
79 80
  81 + private fabToolbarResize$: ResizeObserver;
  82 +
80 83 @Input()
81 84 isOpen: boolean;
82 85
83 86 @Input()
84 87 direction: FabToolbarDirection;
85 88
86   - fabToolbarResizeListener = this.onFabToolbarResize.bind(this);
87   -
88 89 constructor(private el: ElementRef<HTMLElement>,
89 90 @Inject(WINDOW) private window: Window) {
90 91 super(el);
... ... @@ -96,13 +97,14 @@ export class FabToolbarComponent extends MatFabToolbarMixinBase implements OnIni
96 97 element.find('mat-fab-trigger').find('button')
97 98 .prepend('<div class="mat-fab-toolbar-background"></div>');
98 99 element.addClass(`mat-${this.direction}`);
99   - // @ts-ignore
100   - addResizeListener(this.el.nativeElement, this.fabToolbarResizeListener);
  100 + this.fabToolbarResize$ = new ResizeObserver(() => {
  101 + this.onFabToolbarResize();
  102 + });
  103 + this.fabToolbarResize$.observe(this.el.nativeElement);
101 104 }
102 105
103 106 ngOnDestroy(): void {
104   - // @ts-ignore
105   - removeResizeListener(this.el.nativeElement, this.fabToolbarResizeListener);
  107 + this.fabToolbarResize$.disconnect();
106 108 }
107 109
108 110 ngAfterViewInit(): void {
... ...
... ... @@ -15,11 +15,11 @@
15 15 ///
16 16
17 17 import {
18   - ChangeDetectionStrategy,
19 18 Component,
20 19 ElementRef,
21 20 forwardRef,
22   - Input, OnDestroy,
  21 + Input,
  22 + OnDestroy,
23 23 OnInit,
24 24 ViewChild,
25 25 ViewEncapsulation
... ... @@ -34,6 +34,7 @@ import { UtilsService } from '@core/services/utils.service';
34 34 import { guid, isUndefined } from '@app/core/utils';
35 35 import { TranslateService } from '@ngx-translate/core';
36 36 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
  37 +import { ResizeObserver } from '@juggle/resize-observer';
37 38
38 39 @Component({
39 40 selector: 'tb-js-func',
... ... @@ -60,7 +61,7 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
60 61
61 62 private jsEditor: ace.Ace.Editor;
62 63 private editorsResizeCaf: CancelAnimationFrame;
63   - private editorResizeListener: any;
  64 + private editorResize$: ResizeObserver;
64 65
65 66 toastTargetId = `jsFuncEditor-${guid()}`;
66 67
... ... @@ -152,16 +153,15 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
152 153 this.cleanupJsErrors();
153 154 this.updateView();
154 155 });
155   - this.editorResizeListener = this.onAceEditorResize.bind(this);
156   - // @ts-ignore
157   - addResizeListener(editorElement, this.editorResizeListener);
  156 + this.editorResize$ = new ResizeObserver(() => {
  157 + this.onAceEditorResize();
  158 + });
  159 + this.editorResize$.observe(editorElement);
158 160 }
159 161
160 162 ngOnDestroy(): void {
161   - if (this.editorResizeListener) {
162   - const editorElement = this.javascriptEditorElmRef.nativeElement;
163   - // @ts-ignore
164   - removeResizeListener(editorElement, this.editorResizeListener);
  163 + if (this.editorResize$) {
  164 + this.editorResize$.disconnect();
165 165 }
166 166 }
167 167
... ...
... ... @@ -20,10 +20,10 @@ import {
20 20 forwardRef,
21 21 Input,
22 22 OnChanges,
  23 + OnDestroy,
23 24 OnInit,
24   - ViewChild,
25 25 SimpleChanges,
26   - OnDestroy
  26 + ViewChild
27 27 } from '@angular/core';
28 28 import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms';
29 29 import * as ace from 'ace-builds';
... ... @@ -34,6 +34,7 @@ import { AppState } from '@core/core.state';
34 34 import { ContentType, contentTypesMap } from '@shared/models/constants';
35 35 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
36 36 import { guid } from '@core/utils';
  37 +import { ResizeObserver } from '@juggle/resize-observer';
37 38
38 39 @Component({
39 40 selector: 'tb-json-content',
... ... @@ -59,7 +60,7 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid
59 60
60 61 private jsonEditor: ace.Ace.Editor;
61 62 private editorsResizeCaf: CancelAnimationFrame;
62   - private editorResizeListener: any;
  63 + private editorResize$: ResizeObserver;
63 64
64 65 toastTargetId = `jsonContentEditor-${guid()}`;
65 66
... ... @@ -97,8 +98,6 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid
97 98
98 99 contentValid: boolean;
99 100
100   - validationError: string;
101   -
102 101 errorShowed = false;
103 102
104 103 private propagateChange = null;
... ... @@ -135,16 +134,15 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid
135 134 this.cleanupJsonErrors();
136 135 this.updateView();
137 136 });
138   - this.editorResizeListener = this.onAceEditorResize.bind(this);
139   - // @ts-ignore
140   - addResizeListener(editorElement, this.editorResizeListener);
  137 + this.editorResize$ = new ResizeObserver(() => {
  138 + this.onAceEditorResize();
  139 + });
  140 + this.editorResize$.observe(editorElement);
141 141 }
142 142
143 143 ngOnDestroy(): void {
144   - if (this.editorResizeListener) {
145   - const editorElement = this.jsonEditorElmRef.nativeElement;
146   - // @ts-ignore
147   - removeResizeListener(editorElement, this.editorResizeListener);
  144 + if (this.editorResize$) {
  145 + this.editorResize$.disconnect();
148 146 }
149 147 }
150 148
... ...
... ... @@ -15,7 +15,6 @@
15 15 ///
16 16
17 17 import {
18   - ChangeDetectionStrategy,
19 18 Component,
20 19 ElementRef,
21 20 forwardRef,
... ... @@ -106,6 +105,8 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
106 105
107 106 private propagateChange = null;
108 107 private propagateChangePending = false;
  108 + private writingValue = false;
  109 + private updateViewPending = false;
109 110
110 111 constructor(public elementRef: ElementRef,
111 112 private translate: TranslateService,
... ... @@ -143,6 +144,7 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
143 144 }
144 145
145 146 writeValue(data: JsonFormComponentData): void {
  147 + this.writingValue = true;
146 148 this.data = data;
147 149 this.schema = this.data && this.data.schema ? deepClone(this.data.schema) : {
148 150 type: 'object'
... ... @@ -154,19 +156,29 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato
154 156 this.model = inspector.sanitize(this.schema, this.model).data;
155 157 this.updateAndRender();
156 158 this.isModelValid = this.validateModel();
157   - if (!this.isModelValid) {
  159 + this.writingValue = false;
  160 + if (!this.isModelValid || this.updateViewPending) {
158 161 this.updateView();
159 162 }
160 163 }
161 164
162 165 updateView() {
163   - if (this.data) {
164   - this.data.model = this.model;
165   - if (this.propagateChange) {
166   - this.propagateChange(this.data);
167   - } else {
168   - this.propagateChangePending = true;
  166 + if (!this.writingValue) {
  167 + this.updateViewPending = false;
  168 + if (this.data) {
  169 + this.data.model = this.model;
  170 + if (this.propagateChange) {
  171 + try {
  172 + this.propagateChange(this.data);
  173 + } catch (e) {
  174 + this.propagateChangePending = true;
  175 + }
  176 + } else {
  177 + this.propagateChangePending = true;
  178 + }
169 179 }
  180 + } else {
  181 + this.updateViewPending = true;
170 182 }
171 183 }
172 184
... ...
... ... @@ -14,16 +14,8 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import {
18   - Attribute, ChangeDetectionStrategy,
19   - Component,
20   - ElementRef,
21   - forwardRef,
22   - Input, OnDestroy,
23   - OnInit,
24   - ViewChild
25   -} from '@angular/core';
26   -import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, Validator, NG_VALIDATORS } from '@angular/forms';
  17 +import { Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
  18 +import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms';
27 19 import * as ace from 'ace-builds';
28 20 import { coerceBooleanProperty } from '@angular/cdk/coercion';
29 21 import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions';
... ... @@ -31,6 +23,7 @@ import { Store } from '@ngrx/store';
31 23 import { AppState } from '@core/core.state';
32 24 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
33 25 import { guid } from '@core/utils';
  26 +import { ResizeObserver } from '@juggle/resize-observer';
34 27
35 28 @Component({
36 29 selector: 'tb-json-object-edit',
... ... @@ -56,7 +49,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
56 49
57 50 private jsonEditor: ace.Ace.Editor;
58 51 private editorsResizeCaf: CancelAnimationFrame;
59   - private editorResizeListener: any;
  52 + private editorResize$: ResizeObserver;
60 53
61 54 toastTargetId = `jsonObjectEditor-${guid()}`;
62 55
... ... @@ -128,16 +121,15 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
128 121 this.cleanupJsonErrors();
129 122 this.updateView();
130 123 });
131   - this.editorResizeListener = this.onAceEditorResize.bind(this);
132   - // @ts-ignore
133   - addResizeListener(editorElement, this.editorResizeListener);
  124 + this.editorResize$ = new ResizeObserver(() => {
  125 + this.onAceEditorResize();
  126 + });
  127 + this.editorResize$.observe(editorElement);
134 128 }
135 129
136 130 ngOnDestroy(): void {
137   - if (this.editorResizeListener) {
138   - const editorElement = this.jsonEditorElmRef.nativeElement;
139   - // @ts-ignore
140   - removeResizeListener(editorElement, this.editorResizeListener);
  131 + if (this.editorResize$) {
  132 + this.editorResize$.disconnect();
141 133 }
142 134 }
143 135
... ...