Merge pull request #3353 from vvlladd28/feature/encode-state-params
Improvment encode-state params for dashboard
This commit is contained in:
		
						commit
						e3dcc96913
					
				@ -35,13 +35,11 @@
 | 
			
		||||
    "@ngrx/effects": "^10.0.0",
 | 
			
		||||
    "@ngrx/store": "^10.0.0",
 | 
			
		||||
    "@ngrx/store-devtools": "^10.0.0",
 | 
			
		||||
    "ngx-sharebuttons": "^8.0.1",
 | 
			
		||||
    "@ngx-translate/core": "^13.0.0",
 | 
			
		||||
    "@ngx-translate/http-loader": "^6.0.0",
 | 
			
		||||
    "ace-builds": "^1.4.12",
 | 
			
		||||
    "angular-gridster2": "^10.1.3",
 | 
			
		||||
    "angular2-hotkeys": "^2.2.0",
 | 
			
		||||
    "base64-js": "^1.3.1",
 | 
			
		||||
    "canvas-gauges": "^2.1.7",
 | 
			
		||||
    "compass-sass-mixins": "^0.12.7",
 | 
			
		||||
    "core-js": "^3.6.5",
 | 
			
		||||
@ -70,6 +68,7 @@
 | 
			
		||||
    "ngx-daterangepicker-material": "^3.0.4",
 | 
			
		||||
    "ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master",
 | 
			
		||||
    "ngx-hm-carousel": "^2.0.0-rc.1",
 | 
			
		||||
    "ngx-sharebuttons": "^8.0.1",
 | 
			
		||||
    "ngx-translate-messageformat-compiler": "^4.8.0",
 | 
			
		||||
    "objectpath": "^2.0.0",
 | 
			
		||||
    "prettier": "^2.0.5",
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,6 @@ import {
 | 
			
		||||
import { DOCUMENT } from '@angular/common';
 | 
			
		||||
import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs';
 | 
			
		||||
import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import { objToBase64 } from '@core/utils';
 | 
			
		||||
 | 
			
		||||
declare const SystemJS;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,6 @@
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
import { Observable, Subject } from 'rxjs';
 | 
			
		||||
import { finalize, share } from 'rxjs/operators';
 | 
			
		||||
import base64js from 'base64-js';
 | 
			
		||||
import { Datasource } from '@app/shared/models/widget.models';
 | 
			
		||||
 | 
			
		||||
const varsRegex = /\${([^}]*)}/g;
 | 
			
		||||
@ -123,7 +122,8 @@ export function isEmpty(obj: any): boolean {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function formatValue(value: any, dec?: number, units?: string, showZeroDecimals?: boolean): string | undefined {
 | 
			
		||||
  if (isDefinedAndNotNull(value) && isNumeric(value) && (isDefinedAndNotNull(dec) || isDefinedAndNotNull(units) || Number(value).toString() === value)) {
 | 
			
		||||
  if (isDefinedAndNotNull(value) && isNumeric(value) &&
 | 
			
		||||
    (isDefinedAndNotNull(dec) || isDefinedAndNotNull(units) || Number(value).toString() === value)) {
 | 
			
		||||
    let formatted: string | number = Number(value);
 | 
			
		||||
    if (isDefinedAndNotNull(dec)) {
 | 
			
		||||
      formatted = formatted.toFixed(dec);
 | 
			
		||||
@ -164,30 +164,23 @@ export function deleteNullProperties(obj: any) {
 | 
			
		||||
 | 
			
		||||
export function objToBase64(obj: any): string {
 | 
			
		||||
  const json = JSON.stringify(obj);
 | 
			
		||||
  const encoded = utf8Encode(json);
 | 
			
		||||
  return base64js.fromByteArray(encoded);
 | 
			
		||||
  return btoa(encodeURIComponent(json).replace(/%([0-9A-F]{2})/g,
 | 
			
		||||
    function toSolidBytes(match, p1) {
 | 
			
		||||
      return String.fromCharCode(Number('0x' + p1));
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function objToBase64URI(obj: any): string {
 | 
			
		||||
  return encodeURIComponent(objToBase64(obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function base64toObj(b64Encoded: string): any {
 | 
			
		||||
  const encoded: Uint8Array | number[] = base64js.toByteArray(b64Encoded);
 | 
			
		||||
  const json = utf8Decode(encoded);
 | 
			
		||||
  const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => {
 | 
			
		||||
    return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
 | 
			
		||||
  }).join(''));
 | 
			
		||||
  return JSON.parse(json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function utf8Encode(str: string): Uint8Array | number[] {
 | 
			
		||||
  let result: Uint8Array | number[];
 | 
			
		||||
  if (isUndefined(Uint8Array)) {
 | 
			
		||||
    result = utf8ToBytes(str);
 | 
			
		||||
  } else {
 | 
			
		||||
    result = new Uint8Array(utf8ToBytes(str));
 | 
			
		||||
  }
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function utf8Decode(bytes: Uint8Array | number[]): string {
 | 
			
		||||
  return utf8Slice(bytes, 0, bytes.length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const scrollRegex = /(auto|scroll)/;
 | 
			
		||||
 | 
			
		||||
function parentNodes(node: Node, nodes: Node[]): Node[] {
 | 
			
		||||
@ -275,129 +268,6 @@ function easeInOut(
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function utf8Slice(buf: Uint8Array | number[], start: number, end: number): string {
 | 
			
		||||
  let res = '';
 | 
			
		||||
  let tmp = '';
 | 
			
		||||
  end = Math.min(buf.length, end || Infinity);
 | 
			
		||||
  start = start || 0;
 | 
			
		||||
 | 
			
		||||
  for (let i = start; i < end; i++) {
 | 
			
		||||
    if (buf[i] <= 0x7F) {
 | 
			
		||||
      res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]);
 | 
			
		||||
      tmp = '';
 | 
			
		||||
    } else {
 | 
			
		||||
      tmp += '%' + buf[i].toString(16);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return res + decodeUtf8Char(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function decodeUtf8Char(str: string): string {
 | 
			
		||||
  try {
 | 
			
		||||
    return decodeURIComponent(str);
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    return String.fromCharCode(0xFFFD); // UTF 8 invalid char
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function utf8ToBytes(input: string, units?: number): number[] {
 | 
			
		||||
  units = units || Infinity;
 | 
			
		||||
  let codePoint: number;
 | 
			
		||||
  const length = input.length;
 | 
			
		||||
  let leadSurrogate: number = null;
 | 
			
		||||
  const bytes: number[] = [];
 | 
			
		||||
  let i = 0;
 | 
			
		||||
 | 
			
		||||
  for (; i < length; i++) {
 | 
			
		||||
    codePoint = input.charCodeAt(i);
 | 
			
		||||
 | 
			
		||||
    // is surrogate component
 | 
			
		||||
    if (codePoint > 0xD7FF && codePoint < 0xE000) {
 | 
			
		||||
      // last char was a lead
 | 
			
		||||
      if (leadSurrogate) {
 | 
			
		||||
        // 2 leads in a row
 | 
			
		||||
        if (codePoint < 0xDC00) {
 | 
			
		||||
          units -= 3;
 | 
			
		||||
          if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); }
 | 
			
		||||
          leadSurrogate = codePoint;
 | 
			
		||||
          continue;
 | 
			
		||||
        } else {
 | 
			
		||||
          // valid surrogate pair
 | 
			
		||||
          // tslint:disable-next-line:no-bitwise
 | 
			
		||||
          codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000;
 | 
			
		||||
          leadSurrogate = null;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        // no lead yet
 | 
			
		||||
 | 
			
		||||
        if (codePoint > 0xDBFF) {
 | 
			
		||||
          // unexpected trail
 | 
			
		||||
          units -= 3;
 | 
			
		||||
          if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); }
 | 
			
		||||
          continue;
 | 
			
		||||
        } else if (i + 1 === length) {
 | 
			
		||||
          // unpaired lead
 | 
			
		||||
          units -= 3;
 | 
			
		||||
          if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); }
 | 
			
		||||
          continue;
 | 
			
		||||
        } else {
 | 
			
		||||
          // valid lead
 | 
			
		||||
          leadSurrogate = codePoint;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else if (leadSurrogate) {
 | 
			
		||||
      // valid bmp char, but last char was a lead
 | 
			
		||||
      units -= 3;
 | 
			
		||||
      if (units > -1) { bytes.push(0xEF, 0xBF, 0xBD); }
 | 
			
		||||
      leadSurrogate = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // encode utf8
 | 
			
		||||
    if (codePoint < 0x80) {
 | 
			
		||||
      units -= 1;
 | 
			
		||||
      if (units < 0) { break; }
 | 
			
		||||
      bytes.push(codePoint);
 | 
			
		||||
    } else if (codePoint < 0x800) {
 | 
			
		||||
      units -= 2;
 | 
			
		||||
      if (units < 0) { break; }
 | 
			
		||||
      bytes.push(
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0x6 | 0xC0,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint & 0x3F | 0x80
 | 
			
		||||
      );
 | 
			
		||||
    } else if (codePoint < 0x10000) {
 | 
			
		||||
      units -= 3;
 | 
			
		||||
      if (units < 0) { break; }
 | 
			
		||||
      bytes.push(
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0xC | 0xE0,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0x6 & 0x3F | 0x80,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint & 0x3F | 0x80
 | 
			
		||||
      );
 | 
			
		||||
    } else if (codePoint < 0x200000) {
 | 
			
		||||
      units -= 4;
 | 
			
		||||
      if (units < 0) { break; }
 | 
			
		||||
      bytes.push(
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0x12 | 0xF0,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0xC & 0x3F | 0x80,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint >> 0x6 & 0x3F | 0x80,
 | 
			
		||||
        // tslint:disable-next-line:no-bitwise
 | 
			
		||||
        codePoint & 0x3F | 0x80
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error('Invalid code point');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function deepClone<T>(target: T, ignoreFields?: string[]): T {
 | 
			
		||||
  if (target === null) {
 | 
			
		||||
    return target;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ import { Router } from '@angular/router';
 | 
			
		||||
import { DialogComponent } from '@app/shared/components/dialog.component';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models';
 | 
			
		||||
import { objToBase64 } from '@core/utils';
 | 
			
		||||
import { objToBase64URI } from '@core/utils';
 | 
			
		||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
 | 
			
		||||
import { EntityId } from '@app/shared/models/id/entity-id';
 | 
			
		||||
import { Widget } from '@app/shared/models/widget.models';
 | 
			
		||||
@ -205,7 +205,7 @@ export class AddWidgetToDashboardDialogComponent extends
 | 
			
		||||
              id: targetState,
 | 
			
		||||
              params: {}
 | 
			
		||||
            };
 | 
			
		||||
            const state = objToBase64([ stateObject ]);
 | 
			
		||||
            const state = objToBase64URI([ stateObject ]);
 | 
			
		||||
            url = `/dashboards/${theDashboard.id.id}?state=${state}`;
 | 
			
		||||
          } else {
 | 
			
		||||
            url = `/dashboards/${theDashboard.id.id}`;
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,6 @@ import {
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { DashboardWidget } from '@home/models/dashboard-component.models';
 | 
			
		||||
import {
 | 
			
		||||
  Datasource,
 | 
			
		||||
  defaultLegendConfig,
 | 
			
		||||
  LegendConfig,
 | 
			
		||||
  LegendData,
 | 
			
		||||
@ -55,7 +54,7 @@ import { AppState } from '@core/core.state';
 | 
			
		||||
import { WidgetService } from '@core/http/widget.service';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { forkJoin, Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs';
 | 
			
		||||
import { deepClone, isDefined, objToBase64 } from '@core/utils';
 | 
			
		||||
import { deepClone, isDefined, objToBase64URI } from '@core/utils';
 | 
			
		||||
import {
 | 
			
		||||
  IDynamicWidgetComponent,
 | 
			
		||||
  WidgetContext,
 | 
			
		||||
@ -68,7 +67,8 @@ import {
 | 
			
		||||
  StateObject,
 | 
			
		||||
  StateParams,
 | 
			
		||||
  SubscriptionEntityInfo,
 | 
			
		||||
  SubscriptionInfo, SubscriptionMessage,
 | 
			
		||||
  SubscriptionInfo,
 | 
			
		||||
  SubscriptionMessage,
 | 
			
		||||
  WidgetSubscriptionContext,
 | 
			
		||||
  WidgetSubscriptionOptions
 | 
			
		||||
} from '@core/api/widget-api.models';
 | 
			
		||||
@ -80,11 +80,9 @@ import { catchError, switchMap } from 'rxjs/operators';
 | 
			
		||||
import { ActionNotificationShow } from '@core/notification/notification.actions';
 | 
			
		||||
import { TimeService } from '@core/services/time.service';
 | 
			
		||||
import { DeviceService } from '@app/core/http/device.service';
 | 
			
		||||
import { AlarmService } from '@app/core/http/alarm.service';
 | 
			
		||||
import { ExceptionData } from '@shared/models/error.models';
 | 
			
		||||
import { WidgetComponentService } from './widget-component.service';
 | 
			
		||||
import { Timewindow } from '@shared/models/time/time.models';
 | 
			
		||||
import { AlarmSearchStatus } from '@shared/models/alarm.models';
 | 
			
		||||
import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
 | 
			
		||||
import { DashboardService } from '@core/http/dashboard.service';
 | 
			
		||||
import { WidgetSubscription } from '@core/api/widget-subscription';
 | 
			
		||||
@ -688,7 +686,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
 | 
			
		||||
 | 
			
		||||
  private destroyDynamicWidgetComponent() {
 | 
			
		||||
    if (this.widgetContext.$containerParent && this.widgetResize$) {
 | 
			
		||||
      this.widgetResize$.disconnect()
 | 
			
		||||
      this.widgetResize$.disconnect();
 | 
			
		||||
    }
 | 
			
		||||
    if (this.dynamicWidgetComponentRef) {
 | 
			
		||||
      this.dynamicWidgetComponentRef.destroy();
 | 
			
		||||
@ -1023,7 +1021,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
 | 
			
		||||
        if (targetDashboardStateId) {
 | 
			
		||||
          stateObject.id = targetDashboardStateId;
 | 
			
		||||
        }
 | 
			
		||||
        const state = objToBase64([ stateObject ]);
 | 
			
		||||
        const state = objToBase64URI([ stateObject ]);
 | 
			
		||||
        const isSinglePage = this.route.snapshot.data.singlePageMode;
 | 
			
		||||
        let url;
 | 
			
		||||
        if (isSinglePage) {
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component';
 | 
			
		||||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
 | 
			
		||||
import { EntityId } from '@app/shared/models/id/entity-id';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { base64toObj, objToBase64 } from '@app/core/utils';
 | 
			
		||||
import { base64toObj, objToBase64URI } from '@app/core/utils';
 | 
			
		||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
 | 
			
		||||
import { EntityService } from '@core/http/entity.service';
 | 
			
		||||
 | 
			
		||||
@ -237,7 +237,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im
 | 
			
		||||
 | 
			
		||||
  private updateLocation() {
 | 
			
		||||
    if (this.stateObject[0].id) {
 | 
			
		||||
      const newState = objToBase64(this.stateObject);
 | 
			
		||||
      const newState = objToBase64URI(this.stateObject);
 | 
			
		||||
      this.updateStateParam(newState);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component';
 | 
			
		||||
import { StatesControllerService } from '@home/pages/dashboard/states/states-controller.service';
 | 
			
		||||
import { EntityId } from '@app/shared/models/id/entity-id';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { base64toObj, insertVariable, isEmpty, objToBase64 } from '@app/core/utils';
 | 
			
		||||
import { base64toObj, insertVariable, isEmpty, objToBase64URI } from '@app/core/utils';
 | 
			
		||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
 | 
			
		||||
import { EntityService } from '@core/http/entity.service';
 | 
			
		||||
import { EntityType } from '@shared/models/entity-type.models';
 | 
			
		||||
@ -281,7 +281,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
 | 
			
		||||
      if (this.isDefaultState()) {
 | 
			
		||||
        newState = null;
 | 
			
		||||
      } else {
 | 
			
		||||
        newState = objToBase64(this.stateObject);
 | 
			
		||||
        newState = objToBase64URI(this.stateObject);
 | 
			
		||||
      }
 | 
			
		||||
      this.updateStateParam(newState);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2138,7 +2138,7 @@ base64-arraybuffer@0.1.5:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
 | 
			
		||||
  integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
 | 
			
		||||
 | 
			
		||||
base64-js@^1.0.2, base64-js@^1.3.1:
 | 
			
		||||
base64-js@^1.0.2:
 | 
			
		||||
  version "1.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
 | 
			
		||||
  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user