Commit 86a991162f31ea9ae66f726235d673398271a2f4
1 parent
8e3c3990
Improvment encode-state params for dashboard
Showing
8 changed files
with
26 additions
and
160 deletions
... | ... | @@ -35,13 +35,11 @@ |
35 | 35 | "@ngrx/effects": "^10.0.0", |
36 | 36 | "@ngrx/store": "^10.0.0", |
37 | 37 | "@ngrx/store-devtools": "^10.0.0", |
38 | - "ngx-sharebuttons": "^8.0.1", | |
39 | 38 | "@ngx-translate/core": "^13.0.0", |
40 | 39 | "@ngx-translate/http-loader": "^6.0.0", |
41 | 40 | "ace-builds": "^1.4.12", |
42 | 41 | "angular-gridster2": "^10.1.3", |
43 | 42 | "angular2-hotkeys": "^2.2.0", |
44 | - "base64-js": "^1.3.1", | |
45 | 43 | "canvas-gauges": "^2.1.7", |
46 | 44 | "compass-sass-mixins": "^0.12.7", |
47 | 45 | "core-js": "^3.6.5", |
... | ... | @@ -70,6 +68,7 @@ |
70 | 68 | "ngx-daterangepicker-material": "^3.0.4", |
71 | 69 | "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master", |
72 | 70 | "ngx-hm-carousel": "^2.0.0-rc.1", |
71 | + "ngx-sharebuttons": "^8.0.1", | |
73 | 72 | "ngx-translate-messageformat-compiler": "^4.8.0", |
74 | 73 | "objectpath": "^2.0.0", |
75 | 74 | "prettier": "^2.0.5", | ... | ... |
... | ... | @@ -26,7 +26,6 @@ import { |
26 | 26 | import { DOCUMENT } from '@angular/common'; |
27 | 27 | import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs'; |
28 | 28 | import { HttpClient } from '@angular/common/http'; |
29 | -import { objToBase64 } from '@core/utils'; | |
30 | 29 | |
31 | 30 | declare const SystemJS; |
32 | 31 | ... | ... |
... | ... | @@ -17,7 +17,6 @@ |
17 | 17 | import _ from 'lodash'; |
18 | 18 | import { Observable, Subject } from 'rxjs'; |
19 | 19 | import { finalize, share } from 'rxjs/operators'; |
20 | -import base64js from 'base64-js'; | |
21 | 20 | import { Datasource } from '@app/shared/models/widget.models'; |
22 | 21 | |
23 | 22 | const varsRegex = /\${([^}]*)}/g; |
... | ... | @@ -123,7 +122,8 @@ export function isEmpty(obj: any): boolean { |
123 | 122 | } |
124 | 123 | |
125 | 124 | export function formatValue(value: any, dec?: number, units?: string, showZeroDecimals?: boolean): string | undefined { |
126 | - if (isDefinedAndNotNull(value) && isNumeric(value) && (isDefinedAndNotNull(dec) || isDefinedAndNotNull(units) || Number(value).toString() === value)) { | |
125 | + if (isDefinedAndNotNull(value) && isNumeric(value) && | |
126 | + (isDefinedAndNotNull(dec) || isDefinedAndNotNull(units) || Number(value).toString() === value)) { | |
127 | 127 | let formatted: string | number = Number(value); |
128 | 128 | if (isDefinedAndNotNull(dec)) { |
129 | 129 | formatted = formatted.toFixed(dec); |
... | ... | @@ -164,28 +164,21 @@ export function deleteNullProperties(obj: any) { |
164 | 164 | |
165 | 165 | export function objToBase64(obj: any): string { |
166 | 166 | const json = JSON.stringify(obj); |
167 | - const encoded = utf8Encode(json); | |
168 | - return base64js.fromByteArray(encoded); | |
167 | + return btoa(encodeURIComponent(json).replace(/%([0-9A-F]{2})/g, | |
168 | + function toSolidBytes(match, p1) { | |
169 | + return String.fromCharCode(Number('0x' + p1)); | |
170 | + })); | |
169 | 171 | } |
170 | 172 | |
171 | -export function base64toObj(b64Encoded: string): any { | |
172 | - const encoded: Uint8Array | number[] = base64js.toByteArray(b64Encoded); | |
173 | - const json = utf8Decode(encoded); | |
174 | - return JSON.parse(json); | |
175 | -} | |
176 | - | |
177 | -function utf8Encode(str: string): Uint8Array | number[] { | |
178 | - let result: Uint8Array | number[]; | |
179 | - if (isUndefined(Uint8Array)) { | |
180 | - result = utf8ToBytes(str); | |
181 | - } else { | |
182 | - result = new Uint8Array(utf8ToBytes(str)); | |
183 | - } | |
184 | - return result; | |
173 | +export function objToBase64URI(obj: any): string { | |
174 | + return encodeURIComponent(objToBase64(obj)); | |
185 | 175 | } |
186 | 176 | |
187 | -function utf8Decode(bytes: Uint8Array | number[]): string { | |
188 | - return utf8Slice(bytes, 0, bytes.length); | |
177 | +export function base64toObj(b64Encoded: string): any { | |
178 | + const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => { | |
179 | + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); | |
180 | + }).join('')); | |
181 | + return JSON.parse(json); | |
189 | 182 | } |
190 | 183 | |
191 | 184 | const scrollRegex = /(auto|scroll)/; |
... | ... | @@ -275,129 +268,6 @@ function easeInOut( |
275 | 268 | ); |
276 | 269 | } |
277 | 270 | |
278 | -function utf8Slice(buf: Uint8Array | number[], start: number, end: number): string { | |
279 | - let res = ''; | |
280 | - let tmp = ''; | |
281 | - end = Math.min(buf.length, end || Infinity); | |
282 | - start = start || 0; | |
283 | - | |
284 | - for (let i = start; i < end; i++) { | |
285 | - if (buf[i] <= 0x7F) { | |
286 | - res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]); | |
287 | - tmp = ''; | |
288 | - } else { | |
289 | - tmp += '%' + buf[i].toString(16); | |
290 | - } | |
291 | - } | |
292 | - return res + decodeUtf8Char(tmp); | |
293 | -} | |
294 | - | |
295 | -function decodeUtf8Char(str: string): string { | |
296 | - try { | |
297 | - return decodeURIComponent(str); | |
298 | - } catch (err) { | |
299 | - return String.fromCharCode(0xFFFD); // UTF 8 invalid char | |
300 | - } | |
301 | -} | |
302 | - | |
303 | -function utf8ToBytes(input: string, units?: number): number[] { | |
304 | - units = units || Infinity; | |
305 | - let codePoint: number; | |
306 | - const length = input.length; | |
307 | - let leadSurrogate: number = null; | |
308 | - const bytes: number[] = []; | |
309 | - let i = 0; | |
310 | - | |
311 | - for (; i < length; i++) { | |
312 | - codePoint = input.charCodeAt(i); | |
313 | - | |
314 | - // is surrogate component | |
315 | - if (codePoint > 0xD7FF && codePoint < 0xE000) { | |
316 | - // last char was a lead | |
317 | - if (leadSurrogate) { | |
318 | - // 2 leads in a row | |
319 | - if (codePoint < 0xDC00) { | |
320 | - units -= 3; | |
321 | - if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); } | |
322 | - leadSurrogate = codePoint; | |
323 | - continue; | |
324 | - } else { | |
325 | - // valid surrogate pair | |
326 | - // tslint:disable-next-line:no-bitwise | |
327 | - codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000; | |
328 | - leadSurrogate = null; | |
329 | - } | |
330 | - } else { | |
331 | - // no lead yet | |
332 | - | |
333 | - if (codePoint > 0xDBFF) { | |
334 | - // unexpected trail | |
335 | - units -= 3; | |
336 | - if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); } | |
337 | - continue; | |
338 | - } else if (i + 1 === length) { | |
339 | - // unpaired lead | |
340 | - units -= 3; | |
341 | - if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); } | |
342 | - continue; | |
343 | - } else { | |
344 | - // valid lead | |
345 | - leadSurrogate = codePoint; | |
346 | - continue; | |
347 | - } | |
348 | - } | |
349 | - } else if (leadSurrogate) { | |
350 | - // valid bmp char, but last char was a lead | |
351 | - units -= 3; | |
352 | - if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); } | |
353 | - leadSurrogate = null; | |
354 | - } | |
355 | - | |
356 | - // encode utf8 | |
357 | - if (codePoint < 0x80) { | |
358 | - units -= 1; | |
359 | - if (units < 0) { break; } | |
360 | - bytes.push(codePoint); | |
361 | - } else if (codePoint < 0x800) { | |
362 | - units -= 2; | |
363 | - if (units < 0) { break; } | |
364 | - bytes.push( | |
365 | - // tslint:disable-next-line:no-bitwise | |
366 | - codePoint >> 0x6 | 0xC0, | |
367 | - // tslint:disable-next-line:no-bitwise | |
368 | - codePoint & 0x3F | 0x80 | |
369 | - ); | |
370 | - } else if (codePoint < 0x10000) { | |
371 | - units -= 3; | |
372 | - if (units < 0) { break; } | |
373 | - bytes.push( | |
374 | - // tslint:disable-next-line:no-bitwise | |
375 | - codePoint >> 0xC | 0xE0, | |
376 | - // tslint:disable-next-line:no-bitwise | |
377 | - codePoint >> 0x6 & 0x3F | 0x80, | |
378 | - // tslint:disable-next-line:no-bitwise | |
379 | - codePoint & 0x3F | 0x80 | |
380 | - ); | |
381 | - } else if (codePoint < 0x200000) { | |
382 | - units -= 4; | |
383 | - if (units < 0) { break; } | |
384 | - bytes.push( | |
385 | - // tslint:disable-next-line:no-bitwise | |
386 | - codePoint >> 0x12 | 0xF0, | |
387 | - // tslint:disable-next-line:no-bitwise | |
388 | - codePoint >> 0xC & 0x3F | 0x80, | |
389 | - // tslint:disable-next-line:no-bitwise | |
390 | - codePoint >> 0x6 & 0x3F | 0x80, | |
391 | - // tslint:disable-next-line:no-bitwise | |
392 | - codePoint & 0x3F | 0x80 | |
393 | - ); | |
394 | - } else { | |
395 | - throw new Error('Invalid code point'); | |
396 | - } | |
397 | - } | |
398 | - return bytes; | |
399 | -} | |
400 | - | |
401 | 271 | export function deepClone<T>(target: T, ignoreFields?: string[]): T { |
402 | 272 | if (target === null) { |
403 | 273 | return target; | ... | ... |
... | ... | @@ -24,7 +24,7 @@ import { Router } from '@angular/router'; |
24 | 24 | import { DialogComponent } from '@app/shared/components/dialog.component'; |
25 | 25 | import { UtilsService } from '@core/services/utils.service'; |
26 | 26 | import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models'; |
27 | -import { objToBase64 } from '@core/utils'; | |
27 | +import { objToBase64URI } from '@core/utils'; | |
28 | 28 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
29 | 29 | import { EntityId } from '@app/shared/models/id/entity-id'; |
30 | 30 | import { Widget } from '@app/shared/models/widget.models'; |
... | ... | @@ -205,7 +205,7 @@ export class AddWidgetToDashboardDialogComponent extends |
205 | 205 | id: targetState, |
206 | 206 | params: {} |
207 | 207 | }; |
208 | - const state = objToBase64([ stateObject ]); | |
208 | + const state = objToBase64URI([ stateObject ]); | |
209 | 209 | url = `/dashboards/${theDashboard.id.id}?state=${state}`; |
210 | 210 | } else { |
211 | 211 | url = `/dashboards/${theDashboard.id.id}`; | ... | ... |
... | ... | @@ -35,7 +35,6 @@ import { |
35 | 35 | } from '@angular/core'; |
36 | 36 | import { DashboardWidget } from '@home/models/dashboard-component.models'; |
37 | 37 | import { |
38 | - Datasource, | |
39 | 38 | defaultLegendConfig, |
40 | 39 | LegendConfig, |
41 | 40 | LegendData, |
... | ... | @@ -55,7 +54,7 @@ import { AppState } from '@core/core.state'; |
55 | 54 | import { WidgetService } from '@core/http/widget.service'; |
56 | 55 | import { UtilsService } from '@core/services/utils.service'; |
57 | 56 | import { forkJoin, Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs'; |
58 | -import { deepClone, isDefined, objToBase64 } from '@core/utils'; | |
57 | +import { deepClone, isDefined, objToBase64URI } from '@core/utils'; | |
59 | 58 | import { |
60 | 59 | IDynamicWidgetComponent, |
61 | 60 | WidgetContext, |
... | ... | @@ -68,7 +67,8 @@ import { |
68 | 67 | StateObject, |
69 | 68 | StateParams, |
70 | 69 | SubscriptionEntityInfo, |
71 | - SubscriptionInfo, SubscriptionMessage, | |
70 | + SubscriptionInfo, | |
71 | + SubscriptionMessage, | |
72 | 72 | WidgetSubscriptionContext, |
73 | 73 | WidgetSubscriptionOptions |
74 | 74 | } from '@core/api/widget-api.models'; |
... | ... | @@ -80,11 +80,9 @@ import { catchError, switchMap } from 'rxjs/operators'; |
80 | 80 | import { ActionNotificationShow } from '@core/notification/notification.actions'; |
81 | 81 | import { TimeService } from '@core/services/time.service'; |
82 | 82 | import { DeviceService } from '@app/core/http/device.service'; |
83 | -import { AlarmService } from '@app/core/http/alarm.service'; | |
84 | 83 | import { ExceptionData } from '@shared/models/error.models'; |
85 | 84 | import { WidgetComponentService } from './widget-component.service'; |
86 | 85 | import { Timewindow } from '@shared/models/time/time.models'; |
87 | -import { AlarmSearchStatus } from '@shared/models/alarm.models'; | |
88 | 86 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
89 | 87 | import { DashboardService } from '@core/http/dashboard.service'; |
90 | 88 | import { WidgetSubscription } from '@core/api/widget-subscription'; |
... | ... | @@ -688,7 +686,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI |
688 | 686 | |
689 | 687 | private destroyDynamicWidgetComponent() { |
690 | 688 | if (this.widgetContext.$containerParent && this.widgetResize$) { |
691 | - this.widgetResize$.disconnect() | |
689 | + this.widgetResize$.disconnect(); | |
692 | 690 | } |
693 | 691 | if (this.dynamicWidgetComponentRef) { |
694 | 692 | this.dynamicWidgetComponentRef.destroy(); |
... | ... | @@ -1023,7 +1021,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI |
1023 | 1021 | if (targetDashboardStateId) { |
1024 | 1022 | stateObject.id = targetDashboardStateId; |
1025 | 1023 | } |
1026 | - const state = objToBase64([ stateObject ]); | |
1024 | + const state = objToBase64URI([ stateObject ]); | |
1027 | 1025 | const isSinglePage = this.route.snapshot.data.singlePageMode; |
1028 | 1026 | let url; |
1029 | 1027 | if (isSinglePage) { | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; |
23 | 23 | import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
24 | 24 | import { EntityId } from '@app/shared/models/id/entity-id'; |
25 | 25 | import { UtilsService } from '@core/services/utils.service'; |
26 | -import { base64toObj, objToBase64 } from '@app/core/utils'; | |
26 | +import { base64toObj, objToBase64URI } from '@app/core/utils'; | |
27 | 27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
28 | 28 | import { EntityService } from '@core/http/entity.service'; |
29 | 29 | |
... | ... | @@ -237,7 +237,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im |
237 | 237 | |
238 | 238 | private updateLocation() { |
239 | 239 | if (this.stateObject[0].id) { |
240 | - const newState = objToBase64(this.stateObject); | |
240 | + const newState = objToBase64URI(this.stateObject); | |
241 | 241 | this.updateStateParam(newState); |
242 | 242 | } |
243 | 243 | } | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; |
23 | 23 | import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service'; |
24 | 24 | import { EntityId } from '@app/shared/models/id/entity-id'; |
25 | 25 | import { UtilsService } from '@core/services/utils.service'; |
26 | -import { base64toObj, insertVariable, isEmpty, objToBase64 } from '@app/core/utils'; | |
26 | +import { base64toObj, insertVariable, isEmpty, objToBase64URI } from '@app/core/utils'; | |
27 | 27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
28 | 28 | import { EntityService } from '@core/http/entity.service'; |
29 | 29 | import { EntityType } from '@shared/models/entity-type.models'; |
... | ... | @@ -281,7 +281,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp |
281 | 281 | if (this.isDefaultState()) { |
282 | 282 | newState = null; |
283 | 283 | } else { |
284 | - newState = objToBase64(this.stateObject); | |
284 | + newState = objToBase64URI(this.stateObject); | |
285 | 285 | } |
286 | 286 | this.updateStateParam(newState); |
287 | 287 | } | ... | ... |
... | ... | @@ -2138,7 +2138,7 @@ base64-arraybuffer@0.1.5: |
2138 | 2138 | resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" |
2139 | 2139 | integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= |
2140 | 2140 | |
2141 | -base64-js@^1.0.2, base64-js@^1.3.1: | |
2141 | +base64-js@^1.0.2: | |
2142 | 2142 | version "1.3.1" |
2143 | 2143 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" |
2144 | 2144 | integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== | ... | ... |