Showing
23 changed files
with
535 additions
and
287 deletions
@@ -86,25 +86,9 @@ | @@ -86,25 +86,9 @@ | ||
86 | ] | 86 | ] |
87 | }, | 87 | }, |
88 | "scripts": [ | 88 | "scripts": [ |
89 | - "node_modules/jquery/dist/jquery.min.js", | ||
90 | - "node_modules/jquery.terminal/js/jquery.terminal.min.js", | ||
91 | - "node_modules/flot/lib/jquery.colorhelpers.js", | ||
92 | - "node_modules/flot/src/jquery.flot.js", | ||
93 | - "node_modules/flot/src/plugins/jquery.flot.time.js", | ||
94 | - "node_modules/flot/src/plugins/jquery.flot.selection.js", | ||
95 | - "node_modules/flot/src/plugins/jquery.flot.pie.js", | ||
96 | - "node_modules/flot/src/plugins/jquery.flot.crosshair.js", | ||
97 | - "node_modules/flot/src/plugins/jquery.flot.stack.js", | ||
98 | - "node_modules/flot/src/plugins/jquery.flot.symbol.js", | ||
99 | - "node_modules/flot.curvedlines/curvedLines.js", | ||
100 | "node_modules/tinycolor2/dist/tinycolor-min.js", | 89 | "node_modules/tinycolor2/dist/tinycolor-min.js", |
101 | - "node_modules/tooltipster/dist/js/tooltipster.bundle.min.js", | ||
102 | - "node_modules/split.js/dist/split.js", | ||
103 | - "node_modules/js-beautify/js/lib/beautify.js", | ||
104 | - "node_modules/js-beautify/js/lib/beautify-css.js", | ||
105 | - "node_modules/js-beautify/js/lib/beautify-html.js", | ||
106 | - "node_modules/systemjs/dist/system.js", | ||
107 | - "node_modules/jstree/dist/jstree.min.js" | 90 | + "node_modules/split.js/dist/split.min.js", |
91 | + "node_modules/systemjs/dist/system.js" | ||
108 | ], | 92 | ], |
109 | "customWebpackConfig": { | 93 | "customWebpackConfig": { |
110 | "path": "./extra-webpack.config.js" | 94 | "path": "./extra-webpack.config.js" |
@@ -130,7 +114,11 @@ | @@ -130,7 +114,11 @@ | ||
130 | "tinycolor2", | 114 | "tinycolor2", |
131 | "json-schema-defaults", | 115 | "json-schema-defaults", |
132 | "leaflet-providers", | 116 | "leaflet-providers", |
133 | - "lodash" | 117 | + "lodash", |
118 | + "jquery", | ||
119 | + "jquery.terminal", | ||
120 | + "tooltipster", | ||
121 | + "jstree" | ||
134 | ] | 122 | ] |
135 | }, | 123 | }, |
136 | "configurations": { | 124 | "configurations": { |
@@ -35,6 +35,13 @@ module.exports = (config, options) => { | @@ -35,6 +35,13 @@ module.exports = (config, options) => { | ||
35 | }) | 35 | }) |
36 | ); | 36 | ); |
37 | config.plugins.push( | 37 | config.plugins.push( |
38 | + new webpack.ProvidePlugin( | ||
39 | + { | ||
40 | + $: "jquery" | ||
41 | + } | ||
42 | + ) | ||
43 | + ); | ||
44 | + config.plugins.push( | ||
38 | new CompressionPlugin({ | 45 | new CompressionPlugin({ |
39 | filename: "[path][base].gz[query]", | 46 | filename: "[path][base].gz[query]", |
40 | algorithm: "gzip", | 47 | algorithm: "gzip", |
@@ -44,6 +51,9 @@ module.exports = (config, options) => { | @@ -44,6 +51,9 @@ module.exports = (config, options) => { | ||
44 | deleteOriginalAssets: false, | 51 | deleteOriginalAssets: false, |
45 | }) | 52 | }) |
46 | ); | 53 | ); |
54 | + config.plugins.push( | ||
55 | + new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) | ||
56 | + ); | ||
47 | 57 | ||
48 | if (config.mode === 'production') { | 58 | if (config.mode === 'production') { |
49 | const index = config.plugins.findIndex(p => p instanceof AngularCompilerPlugin.AngularCompilerPlugin); | 59 | const index = config.plugins.findIndex(p => p instanceof AngularCompilerPlugin.AngularCompilerPlugin); |
@@ -24,6 +24,9 @@ import { DialogComponent } from '@shared/components/dialog.component'; | @@ -24,6 +24,9 @@ import { DialogComponent } from '@shared/components/dialog.component'; | ||
24 | import { Router } from '@angular/router'; | 24 | import { Router } from '@angular/router'; |
25 | import { ContentType, contentTypesMap } from '@shared/models/constants'; | 25 | import { ContentType, contentTypesMap } from '@shared/models/constants'; |
26 | import { getAce } from '@shared/models/ace/ace.models'; | 26 | import { getAce } from '@shared/models/ace/ace.models'; |
27 | +import { Observable } from 'rxjs/internal/Observable'; | ||
28 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
29 | +import { of } from 'rxjs'; | ||
27 | 30 | ||
28 | export interface EventContentDialogData { | 31 | export interface EventContentDialogData { |
29 | content: string; | 32 | content: string; |
@@ -64,33 +67,42 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia | @@ -64,33 +67,42 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia | ||
64 | createEditor(editorElementRef: ElementRef, content: string) { | 67 | createEditor(editorElementRef: ElementRef, content: string) { |
65 | const editorElement = editorElementRef.nativeElement; | 68 | const editorElement = editorElementRef.nativeElement; |
66 | let mode = 'java'; | 69 | let mode = 'java'; |
70 | + let content$: Observable<string> = null; | ||
67 | if (this.contentType) { | 71 | if (this.contentType) { |
68 | mode = contentTypesMap.get(this.contentType).code; | 72 | mode = contentTypesMap.get(this.contentType).code; |
69 | if (this.contentType === ContentType.JSON && content) { | 73 | if (this.contentType === ContentType.JSON && content) { |
70 | - content = js_beautify(content, {indent_size: 4}); | 74 | + content$ = beautifyJs(content, {indent_size: 4}); |
71 | } | 75 | } |
72 | } | 76 | } |
73 | - let editorOptions: Partial<Ace.EditorOptions> = { | ||
74 | - mode: `ace/mode/${mode}`, | ||
75 | - theme: 'ace/theme/github', | ||
76 | - showGutter: false, | ||
77 | - showPrintMargin: false, | ||
78 | - readOnly: true | ||
79 | - }; | 77 | + if (!content$) { |
78 | + content$ = of(content); | ||
79 | + } | ||
80 | + | ||
81 | + content$.subscribe( | ||
82 | + (processedContent) => { | ||
83 | + let editorOptions: Partial<Ace.EditorOptions> = { | ||
84 | + mode: `ace/mode/${mode}`, | ||
85 | + theme: 'ace/theme/github', | ||
86 | + showGutter: false, | ||
87 | + showPrintMargin: false, | ||
88 | + readOnly: true | ||
89 | + }; | ||
80 | 90 | ||
81 | - const advancedOptions = { | ||
82 | - enableSnippets: false, | ||
83 | - enableBasicAutocompletion: false, | ||
84 | - enableLiveAutocompletion: false | ||
85 | - }; | 91 | + const advancedOptions = { |
92 | + enableSnippets: false, | ||
93 | + enableBasicAutocompletion: false, | ||
94 | + enableLiveAutocompletion: false | ||
95 | + }; | ||
86 | 96 | ||
87 | - editorOptions = {...editorOptions, ...advancedOptions}; | ||
88 | - getAce().subscribe( | ||
89 | - (ace) => { | ||
90 | - const editor = ace.edit(editorElement, editorOptions); | ||
91 | - editor.session.setUseWrapMode(false); | ||
92 | - editor.setValue(content, -1); | ||
93 | - this.updateEditorSize(editorElement, content, editor); | 97 | + editorOptions = {...editorOptions, ...advancedOptions}; |
98 | + getAce().subscribe( | ||
99 | + (ace) => { | ||
100 | + const editor = ace.edit(editorElement, editorOptions); | ||
101 | + editor.session.setUseWrapMode(false); | ||
102 | + editor.setValue(processedContent, -1); | ||
103 | + this.updateEditorSize(editorElement, processedContent, editor); | ||
104 | + } | ||
105 | + ); | ||
94 | } | 106 | } |
95 | ); | 107 | ); |
96 | } | 108 | } |
@@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
29 | </mat-form-field> | 29 | </mat-form-field> |
30 | <div *ngIf="alarmScheduleForm.get('type').value !== alarmScheduleType.ANY_TIME"> | 30 | <div *ngIf="alarmScheduleForm.get('type').value !== alarmScheduleType.ANY_TIME"> |
31 | <tb-timezone-select | 31 | <tb-timezone-select |
32 | - [defaultTimezone]="defaultTimezone" | 32 | + [defaultTimezone]="defaultTimezone$ | async" |
33 | required | 33 | required |
34 | formControlName="timezone"> | 34 | formControlName="timezone"> |
35 | </tb-timezone-select> | 35 | </tb-timezone-select> |
@@ -32,11 +32,15 @@ import { | @@ -32,11 +32,15 @@ import { | ||
32 | AlarmSchedule, | 32 | AlarmSchedule, |
33 | AlarmScheduleType, | 33 | AlarmScheduleType, |
34 | AlarmScheduleTypeTranslationMap, | 34 | AlarmScheduleTypeTranslationMap, |
35 | - dayOfWeekTranslations, getAlarmScheduleRangeText, timeOfDayToUTCTimestamp, utcTimestampToTimeOfDay | 35 | + dayOfWeekTranslations, |
36 | + getAlarmScheduleRangeText, | ||
37 | + timeOfDayToUTCTimestamp, | ||
38 | + utcTimestampToTimeOfDay | ||
36 | } from '@shared/models/device.models'; | 39 | } from '@shared/models/device.models'; |
37 | import { isDefined, isDefinedAndNotNull } from '@core/utils'; | 40 | import { isDefined, isDefinedAndNotNull } from '@core/utils'; |
38 | -import * as _moment from 'moment-timezone'; | ||
39 | import { MatCheckboxChange } from '@angular/material/checkbox'; | 41 | import { MatCheckboxChange } from '@angular/material/checkbox'; |
42 | +import { getDefaultTimezone } from '@shared/models/time/time.models'; | ||
43 | +import { share } from 'rxjs/operators'; | ||
40 | 44 | ||
41 | @Component({ | 45 | @Component({ |
42 | selector: 'tb-alarm-schedule', | 46 | selector: 'tb-alarm-schedule', |
@@ -58,7 +62,9 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, | @@ -58,7 +62,9 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, | ||
58 | 62 | ||
59 | alarmScheduleForm: FormGroup; | 63 | alarmScheduleForm: FormGroup; |
60 | 64 | ||
61 | - defaultTimezone = _moment.tz.guess(); | 65 | + defaultTimezone$ = getDefaultTimezone().pipe( |
66 | + share() | ||
67 | + ); | ||
62 | 68 | ||
63 | alarmScheduleTypes = Object.keys(AlarmScheduleType); | 69 | alarmScheduleTypes = Object.keys(AlarmScheduleType); |
64 | alarmScheduleType = AlarmScheduleType; | 70 | alarmScheduleType = AlarmScheduleType; |
@@ -93,9 +99,11 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, | @@ -93,9 +99,11 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, | ||
93 | items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i)), this.validateItems) | 99 | items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i)), this.validateItems) |
94 | }); | 100 | }); |
95 | this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => { | 101 | this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => { |
96 | - this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: this.defaultTimezone}, {emitEvent: false}); | ||
97 | - this.updateValidators(type, true); | ||
98 | - this.alarmScheduleForm.updateValueAndValidity(); | 102 | + getDefaultTimezone().subscribe((defaultTimezone) => { |
103 | + this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: defaultTimezone}, {emitEvent: false}); | ||
104 | + this.updateValidators(type, true); | ||
105 | + this.alarmScheduleForm.updateValueAndValidity(); | ||
106 | + }); | ||
99 | }); | 107 | }); |
100 | this.alarmScheduleForm.valueChanges.subscribe(() => { | 108 | this.alarmScheduleForm.valueChanges.subscribe(() => { |
101 | this.updateModel(); | 109 | this.updateModel(); |
@@ -34,13 +34,13 @@ import { AppState } from '@core/core.state'; | @@ -34,13 +34,13 @@ import { AppState } from '@core/core.state'; | ||
34 | import { CustomActionDescriptor } from '@shared/models/widget.models'; | 34 | import { CustomActionDescriptor } from '@shared/models/widget.models'; |
35 | import { Ace } from 'ace-builds'; | 35 | import { 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'; | ||
38 | import { ResizeObserver } from '@juggle/resize-observer'; | 37 | import { ResizeObserver } from '@juggle/resize-observer'; |
39 | import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models'; | 38 | import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models'; |
40 | import { Observable } from 'rxjs/internal/Observable'; | 39 | import { Observable } from 'rxjs/internal/Observable'; |
41 | import { forkJoin, from } from 'rxjs'; | 40 | import { forkJoin, from } from 'rxjs'; |
42 | import { map, tap } from 'rxjs/operators'; | 41 | import { map, tap } from 'rxjs/operators'; |
43 | import { getAce } from '@shared/models/ace/ace.models'; | 42 | import { getAce } from '@shared/models/ace/ace.models'; |
43 | +import { beautifyCss, beautifyHtml } from '@shared/models/beautify.models'; | ||
44 | 44 | ||
45 | @Component({ | 45 | @Component({ |
46 | selector: 'tb-custom-action-pretty-resources-tabs', | 46 | selector: 'tb-custom-action-pretty-resources-tabs', |
@@ -140,21 +140,27 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl | @@ -140,21 +140,27 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl | ||
140 | } | 140 | } |
141 | 141 | ||
142 | public beautifyCss(): void { | 142 | public beautifyCss(): void { |
143 | - const res = css_beautify(this.action.customCss, {indent_size: 4}); | ||
144 | - if (this.action.customCss !== res) { | ||
145 | - this.action.customCss = res; | ||
146 | - this.cssEditor.setValue(this.action.customCss ? this.action.customCss : '', -1); | ||
147 | - this.notifyActionUpdated(); | ||
148 | - } | 143 | + beautifyCss(this.action.customCss, {indent_size: 4}).subscribe( |
144 | + (res) => { | ||
145 | + if (this.action.customCss !== res) { | ||
146 | + this.action.customCss = res; | ||
147 | + this.cssEditor.setValue(this.action.customCss ? this.action.customCss : '', -1); | ||
148 | + this.notifyActionUpdated(); | ||
149 | + } | ||
150 | + } | ||
151 | + ); | ||
149 | } | 152 | } |
150 | 153 | ||
151 | public beautifyHtml(): void { | 154 | public beautifyHtml(): void { |
152 | - const res = html_beautify(this.action.customHtml, {indent_size: 4, wrap_line_length: 60}); | ||
153 | - if (this.action.customHtml !== res) { | ||
154 | - this.action.customHtml = res; | ||
155 | - this.htmlEditor.setValue(this.action.customHtml ? this.action.customHtml : '', -1); | ||
156 | - this.notifyActionUpdated(); | ||
157 | - } | 155 | + beautifyHtml(this.action.customHtml, {indent_size: 4, wrap_line_length: 60}).subscribe( |
156 | + (res) => { | ||
157 | + if (this.action.customHtml !== res) { | ||
158 | + this.action.customHtml = res; | ||
159 | + this.htmlEditor.setValue(this.action.customHtml ? this.action.customHtml : '', -1); | ||
160 | + this.notifyActionUpdated(); | ||
161 | + } | ||
162 | + } | ||
163 | + ); | ||
158 | } | 164 | } |
159 | 165 | ||
160 | private initAceEditors(): Observable<any> { | 166 | private initAceEditors(): Observable<any> { |
@@ -111,11 +111,32 @@ export class WidgetComponentService { | @@ -111,11 +111,32 @@ export class WidgetComponentService { | ||
111 | const initSubject = new ReplaySubject(); | 111 | const initSubject = new ReplaySubject(); |
112 | this.init$ = initSubject.asObservable(); | 112 | this.init$ = initSubject.asObservable(); |
113 | 113 | ||
114 | - (window as any).tinycolor = tinycolor; | ||
115 | - (window as any).cssjs = cssjs; | ||
116 | - (window as any).moment = moment; | 114 | + const w = (this.window as any); |
115 | + | ||
116 | + w.tinycolor = tinycolor; | ||
117 | + w.cssjs = cssjs; | ||
118 | + w.moment = moment; | ||
119 | + w.$ = $; | ||
120 | + w.jQuery = $; | ||
117 | 121 | ||
118 | const widgetModulesTasks: Observable<any>[] = []; | 122 | const widgetModulesTasks: Observable<any>[] = []; |
123 | + widgetModulesTasks.push(from(import('jquery.terminal'))); | ||
124 | + | ||
125 | + widgetModulesTasks.push(from(import('flot/src/jquery.flot.js')).pipe( | ||
126 | + mergeMap(() => { | ||
127 | + const flotJsPluginsTasks: Observable<any>[] = []; | ||
128 | + flotJsPluginsTasks.push(from(import('flot/lib/jquery.colorhelpers.js'))); | ||
129 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.time.js'))); | ||
130 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.selection.js'))); | ||
131 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.pie.js'))); | ||
132 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.crosshair.js'))); | ||
133 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.stack.js'))); | ||
134 | + flotJsPluginsTasks.push(from(import('flot/src/plugins/jquery.flot.symbol.js'))); | ||
135 | + flotJsPluginsTasks.push(from(import('flot.curvedlines/curvedLines.js'))); | ||
136 | + return forkJoin(flotJsPluginsTasks); | ||
137 | + }) | ||
138 | + )); | ||
139 | + | ||
119 | widgetModulesTasks.push(from(import('@home/components/widget/lib/flot-widget')).pipe( | 140 | widgetModulesTasks.push(from(import('@home/components/widget/lib/flot-widget')).pipe( |
120 | tap((mod) => { | 141 | tap((mod) => { |
121 | (window as any).TbFlot = mod.TbFlot; | 142 | (window as any).TbFlot = mod.TbFlot; |
@@ -29,7 +29,7 @@ import { | @@ -29,7 +29,7 @@ import { | ||
29 | import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; | 29 | import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; |
30 | import { Authority } from '@shared/models/authority.enum'; | 30 | import { Authority } from '@shared/models/authority.enum'; |
31 | import { RuleChainsTableConfigResolver } from '@modules/home/pages/rulechain/rulechains-table-config.resolver'; | 31 | import { RuleChainsTableConfigResolver } from '@modules/home/pages/rulechain/rulechains-table-config.resolver'; |
32 | -import { Observable } from 'rxjs'; | 32 | +import { from, Observable } from 'rxjs'; |
33 | import { BreadCrumbConfig, BreadCrumbLabelFunction } from '@shared/components/breadcrumb'; | 33 | import { BreadCrumbConfig, BreadCrumbLabelFunction } from '@shared/components/breadcrumb'; |
34 | import { ResolvedRuleChainMetaData, RuleChain } from '@shared/models/rule-chain.models'; | 34 | import { ResolvedRuleChainMetaData, RuleChain } from '@shared/models/rule-chain.models'; |
35 | import { RuleChainService } from '@core/http/rule-chain.service'; | 35 | import { RuleChainService } from '@core/http/rule-chain.service'; |
@@ -76,6 +76,17 @@ export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeCompone | @@ -76,6 +76,17 @@ export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeCompone | ||
76 | } | 76 | } |
77 | 77 | ||
78 | @Injectable() | 78 | @Injectable() |
79 | +export class TooltipsterResolver implements Resolve<any> { | ||
80 | + | ||
81 | + constructor() { | ||
82 | + } | ||
83 | + | ||
84 | + resolve(route: ActivatedRouteSnapshot): Observable<any> { | ||
85 | + return from(import('tooltipster')); | ||
86 | + } | ||
87 | +} | ||
88 | + | ||
89 | +@Injectable() | ||
79 | export class RuleChainImportGuard implements CanActivate { | 90 | export class RuleChainImportGuard implements CanActivate { |
80 | 91 | ||
81 | constructor(private itembuffer: ItemBufferService, | 92 | constructor(private itembuffer: ItemBufferService, |
@@ -144,7 +155,8 @@ const routes: Routes = [ | @@ -144,7 +155,8 @@ const routes: Routes = [ | ||
144 | resolve: { | 155 | resolve: { |
145 | ruleChain: RuleChainResolver, | 156 | ruleChain: RuleChainResolver, |
146 | ruleChainMetaData: ResolvedRuleChainMetaDataResolver, | 157 | ruleChainMetaData: ResolvedRuleChainMetaDataResolver, |
147 | - ruleNodeComponents: RuleNodeComponentsResolver | 158 | + ruleNodeComponents: RuleNodeComponentsResolver, |
159 | + tooltipster: TooltipsterResolver | ||
148 | } | 160 | } |
149 | }, | 161 | }, |
150 | { | 162 | { |
@@ -162,7 +174,8 @@ const routes: Routes = [ | @@ -162,7 +174,8 @@ const routes: Routes = [ | ||
162 | import: true | 174 | import: true |
163 | }, | 175 | }, |
164 | resolve: { | 176 | resolve: { |
165 | - ruleNodeComponents: RuleNodeComponentsResolver | 177 | + ruleNodeComponents: RuleNodeComponentsResolver, |
178 | + tooltipster: TooltipsterResolver | ||
166 | } | 179 | } |
167 | } | 180 | } |
168 | ] | 181 | ] |
@@ -178,6 +191,7 @@ const routes: Routes = [ | @@ -178,6 +191,7 @@ const routes: Routes = [ | ||
178 | RuleChainResolver, | 191 | RuleChainResolver, |
179 | ResolvedRuleChainMetaDataResolver, | 192 | ResolvedRuleChainMetaDataResolver, |
180 | RuleNodeComponentsResolver, | 193 | RuleNodeComponentsResolver, |
194 | + TooltipsterResolver, | ||
181 | RuleChainImportGuard | 195 | RuleChainImportGuard |
182 | ] | 196 | ] |
183 | }) | 197 | }) |
@@ -34,7 +34,6 @@ import { TranslateService } from '@ngx-translate/core'; | @@ -34,7 +34,6 @@ import { TranslateService } from '@ngx-translate/core'; | ||
34 | import { getCurrentIsLoading } from '@app/core/interceptors/load.selectors'; | 34 | import { getCurrentIsLoading } from '@app/core/interceptors/load.selectors'; |
35 | import { Ace } from 'ace-builds'; | 35 | import { Ace } from 'ace-builds'; |
36 | import { getAce, Range } from '@shared/models/ace/ace.models'; | 36 | import { getAce, Range } from '@shared/models/ace/ace.models'; |
37 | -import { css_beautify, html_beautify } from 'js-beautify'; | ||
38 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | 37 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
39 | import { WINDOW } from '@core/services/window.service'; | 38 | import { WINDOW } from '@core/services/window.service'; |
40 | import { WindowMessage } from '@shared/models/window-message.model'; | 39 | import { WindowMessage } from '@shared/models/window-message.model'; |
@@ -51,6 +50,7 @@ import Timeout = NodeJS.Timeout; | @@ -51,6 +50,7 @@ import Timeout = NodeJS.Timeout; | ||
51 | import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; | 50 | import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; |
52 | import { Observable } from 'rxjs/internal/Observable'; | 51 | import { Observable } from 'rxjs/internal/Observable'; |
53 | import { map, tap } from 'rxjs/operators'; | 52 | import { map, tap } from 'rxjs/operators'; |
53 | +import { beautifyCss, beautifyHtml, beautifyJs } from '@shared/models/beautify.models'; | ||
54 | 54 | ||
55 | // @dynamic | 55 | // @dynamic |
56 | @Component({ | 56 | @Component({ |
@@ -618,48 +618,63 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe | @@ -618,48 +618,63 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe | ||
618 | } | 618 | } |
619 | 619 | ||
620 | beautifyCss(): void { | 620 | beautifyCss(): void { |
621 | - const res = css_beautify(this.widget.templateCss, {indent_size: 4}); | ||
622 | - if (this.widget.templateCss !== res) { | ||
623 | - this.isDirty = true; | ||
624 | - this.widget.templateCss = res; | ||
625 | - this.cssEditor.setValue(this.widget.templateCss ? this.widget.templateCss : '', -1); | ||
626 | - } | 621 | + beautifyCss(this.widget.templateCss, {indent_size: 4}).subscribe( |
622 | + (res) => { | ||
623 | + if (this.widget.templateCss !== res) { | ||
624 | + this.isDirty = true; | ||
625 | + this.widget.templateCss = res; | ||
626 | + this.cssEditor.setValue(this.widget.templateCss ? this.widget.templateCss : '', -1); | ||
627 | + } | ||
628 | + } | ||
629 | + ); | ||
627 | } | 630 | } |
628 | 631 | ||
629 | beautifyHtml(): void { | 632 | beautifyHtml(): void { |
630 | - const res = html_beautify(this.widget.templateHtml, {indent_size: 4, wrap_line_length: 60}); | ||
631 | - if (this.widget.templateHtml !== res) { | ||
632 | - this.isDirty = true; | ||
633 | - this.widget.templateHtml = res; | ||
634 | - this.htmlEditor.setValue(this.widget.templateHtml ? this.widget.templateHtml : '', -1); | ||
635 | - } | 633 | + beautifyHtml(this.widget.templateHtml, {indent_size: 4, wrap_line_length: 60}).subscribe( |
634 | + (res) => { | ||
635 | + if (this.widget.templateHtml !== res) { | ||
636 | + this.isDirty = true; | ||
637 | + this.widget.templateHtml = res; | ||
638 | + this.htmlEditor.setValue(this.widget.templateHtml ? this.widget.templateHtml : '', -1); | ||
639 | + } | ||
640 | + } | ||
641 | + ); | ||
636 | } | 642 | } |
637 | 643 | ||
638 | beautifyJson(): void { | 644 | beautifyJson(): void { |
639 | - const res = js_beautify(this.widget.settingsSchema, {indent_size: 4}); | ||
640 | - if (this.widget.settingsSchema !== res) { | ||
641 | - this.isDirty = true; | ||
642 | - this.widget.settingsSchema = res; | ||
643 | - this.jsonSettingsEditor.setValue(this.widget.settingsSchema ? this.widget.settingsSchema : '', -1); | ||
644 | - } | 645 | + beautifyJs(this.widget.settingsSchema, {indent_size: 4}).subscribe( |
646 | + (res) => { | ||
647 | + if (this.widget.settingsSchema !== res) { | ||
648 | + this.isDirty = true; | ||
649 | + this.widget.settingsSchema = res; | ||
650 | + this.jsonSettingsEditor.setValue(this.widget.settingsSchema ? this.widget.settingsSchema : '', -1); | ||
651 | + } | ||
652 | + } | ||
653 | + ); | ||
645 | } | 654 | } |
646 | 655 | ||
647 | beautifyDataKeyJson(): void { | 656 | beautifyDataKeyJson(): void { |
648 | - const res = js_beautify(this.widget.dataKeySettingsSchema, {indent_size: 4}); | ||
649 | - if (this.widget.dataKeySettingsSchema !== res) { | ||
650 | - this.isDirty = true; | ||
651 | - this.widget.dataKeySettingsSchema = res; | ||
652 | - this.dataKeyJsonSettingsEditor.setValue(this.widget.dataKeySettingsSchema ? this.widget.dataKeySettingsSchema : '', -1); | ||
653 | - } | 657 | + beautifyJs(this.widget.dataKeySettingsSchema, {indent_size: 4}).subscribe( |
658 | + (res) => { | ||
659 | + if (this.widget.dataKeySettingsSchema !== res) { | ||
660 | + this.isDirty = true; | ||
661 | + this.widget.dataKeySettingsSchema = res; | ||
662 | + this.dataKeyJsonSettingsEditor.setValue(this.widget.dataKeySettingsSchema ? this.widget.dataKeySettingsSchema : '', -1); | ||
663 | + } | ||
664 | + } | ||
665 | + ); | ||
654 | } | 666 | } |
655 | 667 | ||
656 | beautifyJs(): void { | 668 | beautifyJs(): void { |
657 | - const res = js_beautify(this.widget.controllerScript, {indent_size: 4, wrap_line_length: 60}); | ||
658 | - if (this.widget.controllerScript !== res) { | ||
659 | - this.isDirty = true; | ||
660 | - this.widget.controllerScript = res; | ||
661 | - this.jsEditor.setValue(this.widget.controllerScript ? this.widget.controllerScript : '', -1); | ||
662 | - } | 669 | + beautifyJs(this.widget.controllerScript, {indent_size: 4, wrap_line_length: 60}).subscribe( |
670 | + (res) => { | ||
671 | + if (this.widget.controllerScript !== res) { | ||
672 | + this.isDirty = true; | ||
673 | + this.widget.controllerScript = res; | ||
674 | + this.jsEditor.setValue(this.widget.controllerScript ? this.widget.controllerScript : '', -1); | ||
675 | + } | ||
676 | + } | ||
677 | + ); | ||
663 | } | 678 | } |
664 | 679 | ||
665 | removeResource(index: number) { | 680 | removeResource(index: number) { |
@@ -41,6 +41,7 @@ import { TestScriptInputParams } from '@shared/models/rule-node.models'; | @@ -41,6 +41,7 @@ import { TestScriptInputParams } from '@shared/models/rule-node.models'; | ||
41 | import { RuleChainService } from '@core/http/rule-chain.service'; | 41 | import { RuleChainService } from '@core/http/rule-chain.service'; |
42 | import { mergeMap } from 'rxjs/operators'; | 42 | import { mergeMap } from 'rxjs/operators'; |
43 | import { ActionNotificationShow } from '@core/notification/notification.actions'; | 43 | import { ActionNotificationShow } from '@core/notification/notification.actions'; |
44 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
44 | 45 | ||
45 | export interface NodeScriptTestDialogData { | 46 | export interface NodeScriptTestDialogData { |
46 | script: string; | 47 | script: string; |
@@ -110,12 +111,17 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes | @@ -110,12 +111,17 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes | ||
110 | this.nodeScriptTestFormGroup = this.fb.group({ | 111 | this.nodeScriptTestFormGroup = this.fb.group({ |
111 | payload: this.fb.group({ | 112 | payload: this.fb.group({ |
112 | msgType: [this.data.msgType, [Validators.required]], | 113 | msgType: [this.data.msgType, [Validators.required]], |
113 | - msg: [js_beautify(JSON.stringify(this.data.msg), {indent_size: 4}), []], | 114 | + msg: [null, []], |
114 | }), | 115 | }), |
115 | metadata: [this.data.metadata, [Validators.required]], | 116 | metadata: [this.data.metadata, [Validators.required]], |
116 | script: [this.data.script, []], | 117 | script: [this.data.script, []], |
117 | output: ['', []] | 118 | output: ['', []] |
118 | }); | 119 | }); |
120 | + beautifyJs(JSON.stringify(this.data.msg), {indent_size: 4}).subscribe( | ||
121 | + (res) => { | ||
122 | + this.nodeScriptTestFormGroup.get('payload').get('msg').patchValue(res, {emitEvent: false}); | ||
123 | + } | ||
124 | + ); | ||
119 | } | 125 | } |
120 | 126 | ||
121 | ngAfterViewInit(): void { | 127 | ngAfterViewInit(): void { |
@@ -166,7 +172,11 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes | @@ -166,7 +172,11 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes | ||
166 | 172 | ||
167 | test(): void { | 173 | test(): void { |
168 | this.testNodeScript().subscribe((output) => { | 174 | this.testNodeScript().subscribe((output) => { |
169 | - this.nodeScriptTestFormGroup.get('output').setValue(js_beautify(output, {indent_size: 4})); | 175 | + beautifyJs(output, {indent_size: 4}).subscribe( |
176 | + (res) => { | ||
177 | + this.nodeScriptTestFormGroup.get('output').setValue(res); | ||
178 | + } | ||
179 | + ); | ||
170 | }); | 180 | }); |
171 | } | 181 | } |
172 | 182 |
@@ -37,6 +37,7 @@ import { TranslateService } from '@ngx-translate/core'; | @@ -37,6 +37,7 @@ import { TranslateService } from '@ngx-translate/core'; | ||
37 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | 37 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
38 | import { ResizeObserver } from '@juggle/resize-observer'; | 38 | import { ResizeObserver } from '@juggle/resize-observer'; |
39 | import { TbEditorCompleter } from '@shared/models/ace/completion.models'; | 39 | import { TbEditorCompleter } from '@shared/models/ace/completion.models'; |
40 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
40 | 41 | ||
41 | @Component({ | 42 | @Component({ |
42 | selector: 'tb-js-func', | 43 | selector: 'tb-js-func', |
@@ -214,9 +215,12 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -214,9 +215,12 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
214 | } | 215 | } |
215 | 216 | ||
216 | beautifyJs() { | 217 | beautifyJs() { |
217 | - const res = js_beautify(this.modelValue, {indent_size: 4, wrap_line_length: 60}); | ||
218 | - this.jsEditor.setValue(res ? res : '', -1); | ||
219 | - this.updateView(); | 218 | + beautifyJs(this.modelValue, {indent_size: 4, wrap_line_length: 60}).subscribe( |
219 | + (res) => { | ||
220 | + this.jsEditor.setValue(res ? res : '', -1); | ||
221 | + this.updateView(); | ||
222 | + } | ||
223 | + ); | ||
220 | } | 224 | } |
221 | 225 | ||
222 | validateOnSubmit(): void { | 226 | validateOnSubmit(): void { |
@@ -36,6 +36,7 @@ import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | @@ -36,6 +36,7 @@ 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 | import { ResizeObserver } from '@juggle/resize-observer'; |
38 | import { getAce } from '@shared/models/ace/ace.models'; | 38 | import { getAce } from '@shared/models/ace/ace.models'; |
39 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
39 | 40 | ||
40 | @Component({ | 41 | @Component({ |
41 | selector: 'tb-json-content', | 42 | selector: 'tb-json-content', |
@@ -286,9 +287,12 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | @@ -286,9 +287,12 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | ||
286 | } | 287 | } |
287 | 288 | ||
288 | beautifyJSON() { | 289 | beautifyJSON() { |
289 | - const res = js_beautify(this.contentBody, {indent_size: 4, wrap_line_length: 60}); | ||
290 | - this.jsonEditor.setValue(res ? res : '', -1); | ||
291 | - this.updateView(); | 290 | + beautifyJs(this.contentBody, {indent_size: 4, wrap_line_length: 60}).subscribe( |
291 | + (res) => { | ||
292 | + this.jsonEditor.setValue(res ? res : '', -1); | ||
293 | + this.updateView(); | ||
294 | + } | ||
295 | + ); | ||
292 | } | 296 | } |
293 | 297 | ||
294 | minifyJSON() { | 298 | minifyJSON() { |
@@ -22,6 +22,7 @@ import { IEditorProps } from 'react-ace/src/types'; | @@ -22,6 +22,7 @@ import { IEditorProps } from 'react-ace/src/types'; | ||
22 | import { map, mergeMap } from 'rxjs/operators'; | 22 | import { map, mergeMap } from 'rxjs/operators'; |
23 | import { loadAceDependencies } from '@shared/models/ace/ace.models'; | 23 | import { loadAceDependencies } from '@shared/models/ace/ace.models'; |
24 | import { from } from 'rxjs'; | 24 | import { from } from 'rxjs'; |
25 | +import { Observable } from 'rxjs/internal/Observable'; | ||
25 | 26 | ||
26 | const ReactAce = React.lazy(() => { | 27 | const ReactAce = React.lazy(() => { |
27 | return loadAceDependencies().pipe( | 28 | return loadAceDependencies().pipe( |
@@ -33,7 +34,7 @@ const ReactAce = React.lazy(() => { | @@ -33,7 +34,7 @@ const ReactAce = React.lazy(() => { | ||
33 | 34 | ||
34 | interface ThingsboardAceEditorProps extends JsonFormFieldProps { | 35 | interface ThingsboardAceEditorProps extends JsonFormFieldProps { |
35 | mode: string; | 36 | mode: string; |
36 | - onTidy: (value: string) => string; | 37 | + onTidy: (value: string) => Observable<string>; |
37 | } | 38 | } |
38 | 39 | ||
39 | interface ThingsboardAceEditorState extends JsonFormFieldState { | 40 | interface ThingsboardAceEditorState extends JsonFormFieldState { |
@@ -84,15 +85,18 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th | @@ -84,15 +85,18 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th | ||
84 | onTidy() { | 85 | onTidy() { |
85 | if (!this.props.form.readonly) { | 86 | if (!this.props.form.readonly) { |
86 | let value = this.state.value; | 87 | let value = this.state.value; |
87 | - value = this.props.onTidy(value); | ||
88 | - this.setState({ | ||
89 | - value | ||
90 | - }); | ||
91 | - this.props.onChangeValidate({ | ||
92 | - target: { | ||
93 | - value | ||
94 | - } | ||
95 | - }); | 88 | + this.props.onTidy(value).subscribe( |
89 | + (processedValue) => { | ||
90 | + this.setState({ | ||
91 | + value: processedValue | ||
92 | + }); | ||
93 | + this.props.onChangeValidate({ | ||
94 | + target: { | ||
95 | + value: processedValue | ||
96 | + } | ||
97 | + }); | ||
98 | + } | ||
99 | + ); | ||
96 | } | 100 | } |
97 | } | 101 | } |
98 | 102 |
@@ -16,7 +16,8 @@ | @@ -16,7 +16,8 @@ | ||
16 | import * as React from 'react'; | 16 | import * as React from 'react'; |
17 | import ThingsboardAceEditor from './json-form-ace-editor'; | 17 | import ThingsboardAceEditor from './json-form-ace-editor'; |
18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; | 18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; |
19 | -import { css_beautify } from 'js-beautify'; | 19 | +import { Observable } from 'rxjs/internal/Observable'; |
20 | +import { beautifyCss } from '@shared/models/beautify.models'; | ||
20 | 21 | ||
21 | class ThingsboardCss extends React.Component<JsonFormFieldProps, JsonFormFieldState> { | 22 | class ThingsboardCss extends React.Component<JsonFormFieldProps, JsonFormFieldState> { |
22 | 23 | ||
@@ -25,8 +26,8 @@ class ThingsboardCss extends React.Component<JsonFormFieldProps, JsonFormFieldSt | @@ -25,8 +26,8 @@ class ThingsboardCss extends React.Component<JsonFormFieldProps, JsonFormFieldSt | ||
25 | this.onTidyCss = this.onTidyCss.bind(this); | 26 | this.onTidyCss = this.onTidyCss.bind(this); |
26 | } | 27 | } |
27 | 28 | ||
28 | - onTidyCss(css: string): string { | ||
29 | - return css_beautify(css, {indent_size: 4}); | 29 | + onTidyCss(css: string): Observable<string> { |
30 | + return beautifyCss(css, {indent_size: 4}); | ||
30 | } | 31 | } |
31 | 32 | ||
32 | render() { | 33 | render() { |
@@ -15,8 +15,9 @@ | @@ -15,8 +15,9 @@ | ||
15 | */ | 15 | */ |
16 | import * as React from 'react'; | 16 | import * as React from 'react'; |
17 | import ThingsboardAceEditor from './json-form-ace-editor'; | 17 | import ThingsboardAceEditor from './json-form-ace-editor'; |
18 | -import { html_beautify } from 'js-beautify'; | ||
19 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; | 18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; |
19 | +import { Observable } from 'rxjs/internal/Observable'; | ||
20 | +import { beautifyHtml } from '@shared/models/beautify.models'; | ||
20 | 21 | ||
21 | class ThingsboardHtml extends React.Component<JsonFormFieldProps, JsonFormFieldState> { | 22 | class ThingsboardHtml extends React.Component<JsonFormFieldProps, JsonFormFieldState> { |
22 | 23 | ||
@@ -25,8 +26,8 @@ class ThingsboardHtml extends React.Component<JsonFormFieldProps, JsonFormFieldS | @@ -25,8 +26,8 @@ class ThingsboardHtml extends React.Component<JsonFormFieldProps, JsonFormFieldS | ||
25 | this.onTidyHtml = this.onTidyHtml.bind(this); | 26 | this.onTidyHtml = this.onTidyHtml.bind(this); |
26 | } | 27 | } |
27 | 28 | ||
28 | - onTidyHtml(html: string): string { | ||
29 | - return html_beautify(html, {indent_size: 4}); | 29 | + onTidyHtml(html: string): Observable<string> { |
30 | + return beautifyHtml(html, {indent_size: 4}); | ||
30 | } | 31 | } |
31 | 32 | ||
32 | render() { | 33 | render() { |
@@ -16,6 +16,8 @@ | @@ -16,6 +16,8 @@ | ||
16 | import * as React from 'react'; | 16 | import * as React from 'react'; |
17 | import ThingsboardAceEditor from './json-form-ace-editor'; | 17 | import ThingsboardAceEditor from './json-form-ace-editor'; |
18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; | 18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; |
19 | +import { Observable } from 'rxjs/internal/Observable'; | ||
20 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
19 | 21 | ||
20 | class ThingsboardJavaScript extends React.Component<JsonFormFieldProps, JsonFormFieldState> { | 22 | class ThingsboardJavaScript extends React.Component<JsonFormFieldProps, JsonFormFieldState> { |
21 | 23 | ||
@@ -24,8 +26,8 @@ class ThingsboardJavaScript extends React.Component<JsonFormFieldProps, JsonForm | @@ -24,8 +26,8 @@ class ThingsboardJavaScript extends React.Component<JsonFormFieldProps, JsonForm | ||
24 | this.onTidyJavascript = this.onTidyJavascript.bind(this); | 26 | this.onTidyJavascript = this.onTidyJavascript.bind(this); |
25 | } | 27 | } |
26 | 28 | ||
27 | - onTidyJavascript(javascript: string): string { | ||
28 | - return js_beautify(javascript, {indent_size: 4, wrap_line_length: 60}); | 29 | + onTidyJavascript(javascript: string): Observable<string> { |
30 | + return beautifyJs(javascript, {indent_size: 4, wrap_line_length: 60}); | ||
29 | } | 31 | } |
30 | 32 | ||
31 | render() { | 33 | render() { |
@@ -16,6 +16,8 @@ | @@ -16,6 +16,8 @@ | ||
16 | import * as React from 'react'; | 16 | import * as React from 'react'; |
17 | import ThingsboardAceEditor from './json-form-ace-editor'; | 17 | import ThingsboardAceEditor from './json-form-ace-editor'; |
18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; | 18 | import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; |
19 | +import { Observable } from 'rxjs/internal/Observable'; | ||
20 | +import { beautifyJs } from '@shared/models/beautify.models'; | ||
19 | 21 | ||
20 | class ThingsboardJson extends React.Component<JsonFormFieldProps, JsonFormFieldState> { | 22 | class ThingsboardJson extends React.Component<JsonFormFieldProps, JsonFormFieldState> { |
21 | 23 | ||
@@ -24,8 +26,8 @@ class ThingsboardJson extends React.Component<JsonFormFieldProps, JsonFormFieldS | @@ -24,8 +26,8 @@ class ThingsboardJson extends React.Component<JsonFormFieldProps, JsonFormFieldS | ||
24 | this.onTidyJson = this.onTidyJson.bind(this); | 26 | this.onTidyJson = this.onTidyJson.bind(this); |
25 | } | 27 | } |
26 | 28 | ||
27 | - onTidyJson(json: string): string { | ||
28 | - return js_beautify(json, {indent_size: 4}); | 29 | + onTidyJson(json: string): Observable<string> { |
30 | + return beautifyJs(json, {indent_size: 4}); | ||
29 | } | 31 | } |
30 | 32 | ||
31 | render() { | 33 | render() { |
@@ -145,128 +145,131 @@ export class NavTreeComponent implements OnInit { | @@ -145,128 +145,131 @@ export class NavTreeComponent implements OnInit { | ||
145 | }; | 145 | }; |
146 | } | 146 | } |
147 | 147 | ||
148 | - this.treeElement = $('.tb-nav-tree-container', this.elementRef.nativeElement).jstree(config); | 148 | + import('jstree').then(() => { |
149 | 149 | ||
150 | - this.treeElement.on('changed.jstree', (e: any, data) => { | ||
151 | - const node: NavTreeNode = data.instance.get_selected(true)[0]; | ||
152 | - if (this.onNodeSelected) { | ||
153 | - this.ngZone.run(() => this.onNodeSelected(node, e as Event)); | ||
154 | - } | ||
155 | - }); | ||
156 | - | ||
157 | - this.treeElement.on('model.jstree', (e: any, data) => { | ||
158 | - if (this.onNodesInserted) { | ||
159 | - this.ngZone.run(() => this.onNodesInserted(data.nodes, data.parent)); | ||
160 | - } | ||
161 | - }); | 150 | + this.treeElement = $('.tb-nav-tree-container', this.elementRef.nativeElement).jstree(config); |
162 | 151 | ||
163 | - if (this.editCallbacks) { | ||
164 | - this.editCallbacks.selectNode = id => { | ||
165 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
166 | - if (node) { | ||
167 | - this.treeElement.jstree('deselect_all', true); | ||
168 | - this.treeElement.jstree('select_node', node); | ||
169 | - } | ||
170 | - }; | ||
171 | - this.editCallbacks.deselectAll = () => { | ||
172 | - this.treeElement.jstree('deselect_all'); | ||
173 | - }; | ||
174 | - this.editCallbacks.getNode = (id) => { | ||
175 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
176 | - return node; | ||
177 | - }; | ||
178 | - this.editCallbacks.getParentNodeId = (id) => { | ||
179 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
180 | - if (node) { | ||
181 | - return this.treeElement.jstree('get_parent', node); | 152 | + this.treeElement.on('changed.jstree', (e: any, data) => { |
153 | + const node: NavTreeNode = data.instance.get_selected(true)[0]; | ||
154 | + if (this.onNodeSelected) { | ||
155 | + this.ngZone.run(() => this.onNodeSelected(node, e as Event)); | ||
182 | } | 156 | } |
183 | - }; | ||
184 | - this.editCallbacks.openNode = (id, cb) => { | ||
185 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
186 | - if (node) { | ||
187 | - this.treeElement.jstree('open_node', node, cb); | ||
188 | - } | ||
189 | - }; | ||
190 | - this.editCallbacks.nodeIsOpen = (id) => { | ||
191 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
192 | - if (node) { | ||
193 | - return this.treeElement.jstree('is_open', node); | ||
194 | - } else { | ||
195 | - return true; | ||
196 | - } | ||
197 | - }; | ||
198 | - this.editCallbacks.nodeIsLoaded = (id) => { | ||
199 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
200 | - if (node) { | ||
201 | - return this.treeElement.jstree('is_loaded', node); | ||
202 | - } else { | ||
203 | - return true; | 157 | + }); |
158 | + | ||
159 | + this.treeElement.on('model.jstree', (e: any, data) => { | ||
160 | + if (this.onNodesInserted) { | ||
161 | + this.ngZone.run(() => this.onNodesInserted(data.nodes, data.parent)); | ||
204 | } | 162 | } |
205 | - }; | ||
206 | - this.editCallbacks.refreshNode = (id) => { | ||
207 | - if (id === '#') { | ||
208 | - this.treeElement.jstree('refresh'); | ||
209 | - this.treeElement.jstree('redraw'); | ||
210 | - } else { | 163 | + }); |
164 | + | ||
165 | + if (this.editCallbacks) { | ||
166 | + this.editCallbacks.selectNode = id => { | ||
167 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
168 | + if (node) { | ||
169 | + this.treeElement.jstree('deselect_all', true); | ||
170 | + this.treeElement.jstree('select_node', node); | ||
171 | + } | ||
172 | + }; | ||
173 | + this.editCallbacks.deselectAll = () => { | ||
174 | + this.treeElement.jstree('deselect_all'); | ||
175 | + }; | ||
176 | + this.editCallbacks.getNode = (id) => { | ||
177 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
178 | + return node; | ||
179 | + }; | ||
180 | + this.editCallbacks.getParentNodeId = (id) => { | ||
211 | const node: NavTreeNode = this.treeElement.jstree('get_node', id); | 181 | const node: NavTreeNode = this.treeElement.jstree('get_node', id); |
212 | if (node) { | 182 | if (node) { |
213 | - const opened = this.treeElement.jstree('is_open', node); | ||
214 | - this.treeElement.jstree('refresh_node', node); | 183 | + return this.treeElement.jstree('get_parent', node); |
184 | + } | ||
185 | + }; | ||
186 | + this.editCallbacks.openNode = (id, cb) => { | ||
187 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
188 | + if (node) { | ||
189 | + this.treeElement.jstree('open_node', node, cb); | ||
190 | + } | ||
191 | + }; | ||
192 | + this.editCallbacks.nodeIsOpen = (id) => { | ||
193 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
194 | + if (node) { | ||
195 | + return this.treeElement.jstree('is_open', node); | ||
196 | + } else { | ||
197 | + return true; | ||
198 | + } | ||
199 | + }; | ||
200 | + this.editCallbacks.nodeIsLoaded = (id) => { | ||
201 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
202 | + if (node) { | ||
203 | + return this.treeElement.jstree('is_loaded', node); | ||
204 | + } else { | ||
205 | + return true; | ||
206 | + } | ||
207 | + }; | ||
208 | + this.editCallbacks.refreshNode = (id) => { | ||
209 | + if (id === '#') { | ||
210 | + this.treeElement.jstree('refresh'); | ||
215 | this.treeElement.jstree('redraw'); | 211 | this.treeElement.jstree('redraw'); |
216 | - if (node.children && opened/* && !node.children.length*/) { | ||
217 | - this.treeElement.jstree('open_node', node); | 212 | + } else { |
213 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
214 | + if (node) { | ||
215 | + const opened = this.treeElement.jstree('is_open', node); | ||
216 | + this.treeElement.jstree('refresh_node', node); | ||
217 | + this.treeElement.jstree('redraw'); | ||
218 | + if (node.children && opened/* && !node.children.length*/) { | ||
219 | + this.treeElement.jstree('open_node', node); | ||
220 | + } | ||
218 | } | 221 | } |
219 | } | 222 | } |
220 | - } | ||
221 | - }; | ||
222 | - this.editCallbacks.updateNode = (id, newName) => { | ||
223 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
224 | - if (node) { | ||
225 | - this.treeElement.jstree('rename_node', node, newName); | ||
226 | - } | ||
227 | - }; | ||
228 | - this.editCallbacks.createNode = (parentId, node, pos) => { | ||
229 | - const parentNode: NavTreeNode = this.treeElement.jstree('get_node', parentId); | ||
230 | - if (parentNode) { | ||
231 | - this.treeElement.jstree('create_node', parentNode, node, pos); | ||
232 | - } | ||
233 | - }; | ||
234 | - this.editCallbacks.deleteNode = (id) => { | ||
235 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
236 | - if (node) { | ||
237 | - this.treeElement.jstree('delete_node', node); | ||
238 | - } | ||
239 | - }; | ||
240 | - this.editCallbacks.disableNode = (id) => { | ||
241 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
242 | - if (node) { | ||
243 | - this.treeElement.jstree('disable_node', node); | ||
244 | - } | ||
245 | - }; | ||
246 | - this.editCallbacks.enableNode = (id) => { | ||
247 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
248 | - if (node) { | ||
249 | - this.treeElement.jstree('enable_node', node); | ||
250 | - } | ||
251 | - }; | ||
252 | - this.editCallbacks.setNodeHasChildren = (id, hasChildren) => { | ||
253 | - const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
254 | - if (node) { | ||
255 | - if (!node.children || (Array.isArray(node.children) && !node.children.length)) { | ||
256 | - node.children = hasChildren; | ||
257 | - node.state.loaded = !hasChildren; | ||
258 | - node.state.opened = false; | ||
259 | - this.treeElement.jstree('_node_changed', node.id); | ||
260 | - this.treeElement.jstree('redraw'); | 223 | + }; |
224 | + this.editCallbacks.updateNode = (id, newName) => { | ||
225 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
226 | + if (node) { | ||
227 | + this.treeElement.jstree('rename_node', node, newName); | ||
261 | } | 228 | } |
262 | - } | ||
263 | - }; | ||
264 | - this.editCallbacks.search = (searchText) => { | ||
265 | - this.treeElement.jstree('search', searchText); | ||
266 | - }; | ||
267 | - this.editCallbacks.clearSearch = () => { | ||
268 | - this.treeElement.jstree('clear_search'); | ||
269 | - }; | ||
270 | - } | 229 | + }; |
230 | + this.editCallbacks.createNode = (parentId, node, pos) => { | ||
231 | + const parentNode: NavTreeNode = this.treeElement.jstree('get_node', parentId); | ||
232 | + if (parentNode) { | ||
233 | + this.treeElement.jstree('create_node', parentNode, node, pos); | ||
234 | + } | ||
235 | + }; | ||
236 | + this.editCallbacks.deleteNode = (id) => { | ||
237 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
238 | + if (node) { | ||
239 | + this.treeElement.jstree('delete_node', node); | ||
240 | + } | ||
241 | + }; | ||
242 | + this.editCallbacks.disableNode = (id) => { | ||
243 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
244 | + if (node) { | ||
245 | + this.treeElement.jstree('disable_node', node); | ||
246 | + } | ||
247 | + }; | ||
248 | + this.editCallbacks.enableNode = (id) => { | ||
249 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
250 | + if (node) { | ||
251 | + this.treeElement.jstree('enable_node', node); | ||
252 | + } | ||
253 | + }; | ||
254 | + this.editCallbacks.setNodeHasChildren = (id, hasChildren) => { | ||
255 | + const node: NavTreeNode = this.treeElement.jstree('get_node', id); | ||
256 | + if (node) { | ||
257 | + if (!node.children || (Array.isArray(node.children) && !node.children.length)) { | ||
258 | + node.children = hasChildren; | ||
259 | + node.state.loaded = !hasChildren; | ||
260 | + node.state.opened = false; | ||
261 | + this.treeElement.jstree('_node_changed', node.id); | ||
262 | + this.treeElement.jstree('redraw'); | ||
263 | + } | ||
264 | + } | ||
265 | + }; | ||
266 | + this.editCallbacks.search = (searchText) => { | ||
267 | + this.treeElement.jstree('search', searchText); | ||
268 | + }; | ||
269 | + this.editCallbacks.clearSearch = () => { | ||
270 | + this.treeElement.jstree('clear_search'); | ||
271 | + }; | ||
272 | + } | ||
273 | + }); | ||
271 | } | 274 | } |
272 | } | 275 | } |
@@ -16,21 +16,14 @@ | @@ -16,21 +16,14 @@ | ||
16 | 16 | ||
17 | import { AfterViewInit, Component, forwardRef, Input, NgZone, OnInit, ViewChild } from '@angular/core'; | 17 | import { AfterViewInit, Component, forwardRef, Input, NgZone, OnInit, ViewChild } from '@angular/core'; |
18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; | 18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; |
19 | -import { Observable, of } from 'rxjs'; | 19 | +import { Observable } from 'rxjs'; |
20 | import { map, mergeMap, share, tap } from 'rxjs/operators'; | 20 | import { map, mergeMap, share, tap } from 'rxjs/operators'; |
21 | import { Store } from '@ngrx/store'; | 21 | import { Store } from '@ngrx/store'; |
22 | import { AppState } from '@app/core/core.state'; | 22 | import { AppState } from '@app/core/core.state'; |
23 | import { TranslateService } from '@ngx-translate/core'; | 23 | import { TranslateService } from '@ngx-translate/core'; |
24 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 24 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
25 | -import * as _moment from 'moment-timezone'; | ||
26 | import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; | 25 | import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; |
27 | - | ||
28 | -interface TimezoneInfo { | ||
29 | - id: string; | ||
30 | - name: string; | ||
31 | - offset: string; | ||
32 | - nOffset: number; | ||
33 | -} | 26 | +import { getTimezoneInfo, getTimezones, TimezoneInfo } from '@shared/models/time/time.models'; |
34 | 27 | ||
35 | @Component({ | 28 | @Component({ |
36 | selector: 'tb-timezone-select', | 29 | selector: 'tb-timezone-select', |
@@ -50,28 +43,14 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | @@ -50,28 +43,14 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | ||
50 | 43 | ||
51 | defaultTimezoneId: string = null; | 44 | defaultTimezoneId: string = null; |
52 | 45 | ||
53 | - defaultTimezoneInfo: TimezoneInfo = null; | ||
54 | - | ||
55 | - timezones: TimezoneInfo[] = _moment.tz.names().map((zoneName) => { | ||
56 | - const tz = _moment.tz(zoneName); | ||
57 | - return { | ||
58 | - id: zoneName, | ||
59 | - name: zoneName.replace(/_/g, ' '), | ||
60 | - offset: `UTC${tz.format('Z')}`, | ||
61 | - nOffset: tz.utcOffset() | ||
62 | - } | ||
63 | - }); | 46 | + timezones$ = getTimezones().pipe( |
47 | + share() | ||
48 | + ); | ||
64 | 49 | ||
65 | @Input() | 50 | @Input() |
66 | set defaultTimezone(timezone: string) { | 51 | set defaultTimezone(timezone: string) { |
67 | if (this.defaultTimezoneId !== timezone) { | 52 | if (this.defaultTimezoneId !== timezone) { |
68 | this.defaultTimezoneId = timezone; | 53 | this.defaultTimezoneId = timezone; |
69 | - if (this.defaultTimezoneId) { | ||
70 | - this.defaultTimezoneInfo = | ||
71 | - this.timezones.find((timezoneInfo) => timezoneInfo.id === this.defaultTimezoneId); | ||
72 | - } else { | ||
73 | - this.defaultTimezoneInfo = null; | ||
74 | - } | ||
75 | } | 54 | } |
76 | } | 55 | } |
77 | 56 | ||
@@ -150,23 +129,27 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | @@ -150,23 +129,27 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | ||
150 | 129 | ||
151 | writeValue(value: string | null): void { | 130 | writeValue(value: string | null): void { |
152 | this.searchText = ''; | 131 | this.searchText = ''; |
153 | - let foundTimezone: TimezoneInfo = null; | ||
154 | if (value !== null) { | 132 | if (value !== null) { |
155 | - foundTimezone = this.timezones.find(timezoneInfo => timezoneInfo.id === value); | ||
156 | - } | ||
157 | - if (foundTimezone !== null) { | ||
158 | - this.modelValue = value; | ||
159 | - this.selectTimezoneFormGroup.get('timezone').patchValue(foundTimezone, {emitEvent: false}); | 133 | + getTimezoneInfo(value, this.defaultTimezoneId).subscribe( |
134 | + (foundTimezone) => { | ||
135 | + if (foundTimezone !== null) { | ||
136 | + this.selectTimezoneFormGroup.get('timezone').patchValue(foundTimezone, {emitEvent: false}); | ||
137 | + if (foundTimezone.id !== value) { | ||
138 | + setTimeout(() => { | ||
139 | + this.updateView(foundTimezone.id); | ||
140 | + }, 0); | ||
141 | + } else { | ||
142 | + this.modelValue = value; | ||
143 | + } | ||
144 | + } else { | ||
145 | + this.modelValue = null; | ||
146 | + this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false}); | ||
147 | + } | ||
148 | + } | ||
149 | + ); | ||
160 | } else { | 150 | } else { |
161 | - if (this.defaultTimezoneInfo) { | ||
162 | - this.selectTimezoneFormGroup.get('timezone').patchValue(this.defaultTimezoneInfo, {emitEvent: false}); | ||
163 | - setTimeout(() => { | ||
164 | - this.updateView(this.defaultTimezoneInfo.id); | ||
165 | - }, 0); | ||
166 | - } else { | ||
167 | - this.modelValue = null; | ||
168 | - this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false}); | ||
169 | - } | 151 | + this.modelValue = null; |
152 | + this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false}); | ||
170 | } | 153 | } |
171 | this.dirty = true; | 154 | this.dirty = true; |
172 | } | 155 | } |
@@ -182,10 +165,15 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | @@ -182,10 +165,15 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | ||
182 | if (this.ignoreClosePanel) { | 165 | if (this.ignoreClosePanel) { |
183 | this.ignoreClosePanel = false; | 166 | this.ignoreClosePanel = false; |
184 | } else { | 167 | } else { |
185 | - if (!this.modelValue && this.defaultTimezoneInfo) { | ||
186 | - this.ngZone.run(() => { | ||
187 | - this.selectTimezoneFormGroup.get('timezone').reset(this.defaultTimezoneInfo, {emitEvent: true}); | ||
188 | - }); | 168 | + if (!this.modelValue && this.defaultTimezoneId) { |
169 | + getTimezoneInfo(this.defaultTimezoneId).subscribe( | ||
170 | + (defaultTimezoneInfo) => { | ||
171 | + if (defaultTimezoneInfo !== null) { | ||
172 | + this.ngZone.run(() => { | ||
173 | + this.selectTimezoneFormGroup.get('timezone').reset(defaultTimezoneInfo, {emitEvent: true}); | ||
174 | + }); | ||
175 | + } | ||
176 | + }); | ||
189 | } | 177 | } |
190 | } | 178 | } |
191 | } | 179 | } |
@@ -203,12 +191,13 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | @@ -203,12 +191,13 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af | ||
203 | 191 | ||
204 | fetchTimezones(searchText?: string): Observable<Array<TimezoneInfo>> { | 192 | fetchTimezones(searchText?: string): Observable<Array<TimezoneInfo>> { |
205 | this.searchText = searchText; | 193 | this.searchText = searchText; |
206 | - let result = this.timezones; | ||
207 | if (searchText && searchText.length) { | 194 | if (searchText && searchText.length) { |
208 | - result = this.timezones.filter((timezoneInfo) => | ||
209 | - timezoneInfo.name.toLowerCase().includes(searchText.toLowerCase())); | 195 | + return getTimezones().pipe( |
196 | + map((timezones) => timezones.filter((timezoneInfo) => | ||
197 | + timezoneInfo.name.toLowerCase().includes(searchText.toLowerCase()))) | ||
198 | + ); | ||
210 | } | 199 | } |
211 | - return of(result); | 200 | + return getTimezones(); |
212 | } | 201 | } |
213 | 202 | ||
214 | clear() { | 203 | clear() { |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Observable } from 'rxjs/internal/Observable'; | ||
18 | +import { from, of } from 'rxjs'; | ||
19 | +import { map, tap } from 'rxjs/operators'; | ||
20 | + | ||
21 | +let jsBeautifyModule: any; | ||
22 | +let htmlBeautifyModule: any; | ||
23 | +let cssBeautifyModule: any; | ||
24 | + | ||
25 | +function loadJsBeautify(): Observable<any> { | ||
26 | + if (jsBeautifyModule) { | ||
27 | + return of(jsBeautifyModule); | ||
28 | + } else { | ||
29 | + return from(import('js-beautify/js/lib/beautify.js')).pipe( | ||
30 | + tap((module) => { | ||
31 | + jsBeautifyModule = module; | ||
32 | + }) | ||
33 | + ); | ||
34 | + } | ||
35 | +} | ||
36 | + | ||
37 | +function loadHtmlBeautify(): Observable<any> { | ||
38 | + if (htmlBeautifyModule) { | ||
39 | + return of(htmlBeautifyModule); | ||
40 | + } else { | ||
41 | + return from(import('js-beautify/js/lib/beautify-html.js')).pipe( | ||
42 | + tap((module) => { | ||
43 | + htmlBeautifyModule = module; | ||
44 | + }) | ||
45 | + ); | ||
46 | + } | ||
47 | +} | ||
48 | + | ||
49 | +function loadCssBeautify(): Observable<any> { | ||
50 | + if (cssBeautifyModule) { | ||
51 | + return of(cssBeautifyModule); | ||
52 | + } else { | ||
53 | + return from(import('js-beautify/js/lib/beautify-css.js')).pipe( | ||
54 | + tap((module) => { | ||
55 | + cssBeautifyModule = module; | ||
56 | + }) | ||
57 | + ); | ||
58 | + } | ||
59 | +} | ||
60 | + | ||
61 | +export function beautifyJs(source: string, options?: JSBeautifyOptions): Observable<string> { | ||
62 | + return loadJsBeautify().pipe( | ||
63 | + map((mod) => { | ||
64 | + return mod.js_beautify(source, options); | ||
65 | + }) | ||
66 | + ); | ||
67 | +} | ||
68 | + | ||
69 | +export function beautifyCss(source: string, options?: CSSBeautifyOptions): Observable<string> { | ||
70 | + return loadCssBeautify().pipe( | ||
71 | + map((mod) => mod.css_beautify(source, options)) | ||
72 | + ); | ||
73 | +} | ||
74 | + | ||
75 | +export function beautifyHtml(source: string, options?: HTMLBeautifyOptions): Observable<string> { | ||
76 | + return loadHtmlBeautify().pipe( | ||
77 | + map((mod) => mod.html_beautify(source, options)) | ||
78 | + ); | ||
79 | +} |
@@ -25,7 +25,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id'; | @@ -25,7 +25,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id'; | ||
25 | import { EntityInfoData } from '@shared/models/entity.models'; | 25 | import { EntityInfoData } from '@shared/models/entity.models'; |
26 | import { KeyFilter } from '@shared/models/query/query.models'; | 26 | import { KeyFilter } from '@shared/models/query/query.models'; |
27 | import { TimeUnit } from '@shared/models/time/time.models'; | 27 | import { TimeUnit } from '@shared/models/time/time.models'; |
28 | -import * as _moment from 'moment-timezone'; | 28 | +import * as _moment from 'moment'; |
29 | import { AbstractControl, ValidationErrors } from '@angular/forms'; | 29 | import { AbstractControl, ValidationErrors } from '@angular/forms'; |
30 | 30 | ||
31 | export enum DeviceProfileType { | 31 | export enum DeviceProfileType { |
@@ -17,6 +17,9 @@ | @@ -17,6 +17,9 @@ | ||
17 | import { TimeService } from '@core/services/time.service'; | 17 | import { TimeService } from '@core/services/time.service'; |
18 | import { deepClone, isDefined, isUndefined } from '@app/core/utils'; | 18 | import { deepClone, isDefined, isUndefined } from '@app/core/utils'; |
19 | import * as moment_ from 'moment'; | 19 | import * as moment_ from 'moment'; |
20 | +import { Observable } from 'rxjs/internal/Observable'; | ||
21 | +import { from, of } from 'rxjs'; | ||
22 | +import { map, tap } from 'rxjs/operators'; | ||
20 | 23 | ||
21 | const moment = moment_; | 24 | const moment = moment_; |
22 | 25 | ||
@@ -481,3 +484,63 @@ export const timeUnitTranslationMap = new Map<TimeUnit, string>( | @@ -481,3 +484,63 @@ export const timeUnitTranslationMap = new Map<TimeUnit, string>( | ||
481 | [TimeUnit.DAYS, 'timeunit.days'] | 484 | [TimeUnit.DAYS, 'timeunit.days'] |
482 | ] | 485 | ] |
483 | ); | 486 | ); |
487 | + | ||
488 | +export interface TimezoneInfo { | ||
489 | + id: string; | ||
490 | + name: string; | ||
491 | + offset: string; | ||
492 | + nOffset: number; | ||
493 | +} | ||
494 | + | ||
495 | +let timezones: TimezoneInfo[] = null; | ||
496 | +let defaultTimezone: string = null; | ||
497 | + | ||
498 | +export function getTimezones(): Observable<TimezoneInfo[]> { | ||
499 | + if (timezones) { | ||
500 | + return of(timezones); | ||
501 | + } else { | ||
502 | + return from(import('moment-timezone')).pipe( | ||
503 | + map((monentTz) => { | ||
504 | + return monentTz.tz.names().map((zoneName) => { | ||
505 | + const tz = monentTz.tz(zoneName); | ||
506 | + return { | ||
507 | + id: zoneName, | ||
508 | + name: zoneName.replace(/_/g, ' '), | ||
509 | + offset: `UTC${tz.format('Z')}`, | ||
510 | + nOffset: tz.utcOffset() | ||
511 | + }; | ||
512 | + }); | ||
513 | + }), | ||
514 | + tap((zones) => { | ||
515 | + timezones = zones; | ||
516 | + }) | ||
517 | + ); | ||
518 | + } | ||
519 | +} | ||
520 | + | ||
521 | +export function getTimezoneInfo(timezoneId: string, defaultTimezoneId?: string): Observable<TimezoneInfo> { | ||
522 | + return getTimezones().pipe( | ||
523 | + map((timezoneList) => { | ||
524 | + let foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === timezoneId); | ||
525 | + if (!foundTimezone && defaultTimezoneId) { | ||
526 | + foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === defaultTimezoneId); | ||
527 | + } | ||
528 | + return foundTimezone; | ||
529 | + }) | ||
530 | + ); | ||
531 | +} | ||
532 | + | ||
533 | +export function getDefaultTimezone(): Observable<string> { | ||
534 | + if (defaultTimezone) { | ||
535 | + return of(defaultTimezone); | ||
536 | + } else { | ||
537 | + return from(import('moment-timezone')).pipe( | ||
538 | + map((monentTz) => { | ||
539 | + return monentTz.tz.guess(); | ||
540 | + }), | ||
541 | + tap((zone) => { | ||
542 | + defaultTimezone = zone; | ||
543 | + }) | ||
544 | + ); | ||
545 | + } | ||
546 | +} |
@@ -37,6 +37,18 @@ | @@ -37,6 +37,18 @@ | ||
37 | ], | 37 | ], |
38 | "ace": [ | 38 | "ace": [ |
39 | "node_modules/ace-builds/src-noconflict/ace.js" | 39 | "node_modules/ace-builds/src-noconflict/ace.js" |
40 | + ], | ||
41 | + "jquery": [ | ||
42 | + "node_modules/jquery/dist/jquery.min.js" | ||
43 | + ], | ||
44 | + "jquery.terminal": [ | ||
45 | + "node_modules/jquery.terminal/js/jquery.terminal.js" | ||
46 | + ], | ||
47 | + "tooltipster": [ | ||
48 | + "node_modules/tooltipster/dist/js/tooltipster.bundle.min.js" | ||
49 | + ], | ||
50 | + "jstree": [ | ||
51 | + "node_modules/jstree/dist/jstree.min.js" | ||
40 | ] | 52 | ] |
41 | }, | 53 | }, |
42 | "lib": [ | 54 | "lib": [ |