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