Merge branch 'refs/heads/master' into feature/lwm2m/obj-19-ota-update
This commit is contained in:
		
						commit
						6acfcab34d
					
				@ -250,5 +250,5 @@
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}]]></tb:metadata>
 | 
			
		||||
<path d="M200 101H131C113.879 101 100 114.879 100 132V201" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
 | 
			
		||||
<path d="M200 100H132C115 100 100 115 100 132V200" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB  | 
@ -32,7 +32,7 @@ public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSetti
 | 
			
		||||
 | 
			
		||||
    // This list should include all versions which are compatible for the upgrade.
 | 
			
		||||
    // The compatibility cycle usually breaks when we have some scripts written in Java that may not work after new release.
 | 
			
		||||
    private static final List<String> SUPPORTED_VERSIONS_FOR_UPGRADE = List.of("4.0.0");
 | 
			
		||||
    private static final List<String> SUPPORTED_VERSIONS_FOR_UPGRADE = List.of("4.0.0", "4.0.1");
 | 
			
		||||
 | 
			
		||||
    private final ProjectInfo projectInfo;
 | 
			
		||||
    private final JdbcTemplate jdbcTemplate;
 | 
			
		||||
 | 
			
		||||
@ -259,9 +259,9 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
 | 
			
		||||
            int sent = stats.getTotalSent().get();
 | 
			
		||||
            int errors = stats.getTotalErrors().get();
 | 
			
		||||
            if (errors > 0) {
 | 
			
		||||
                log.info("[{}][{}] Notification request processing finished in {} ms (sent: {}, errors: {})", ctx.getTenantId(), requestId, time, sent, errors);
 | 
			
		||||
                log.debug("[{}][{}] Notification request processing finished in {} ms (sent: {}, errors: {})", ctx.getTenantId(), requestId, time, sent, errors);
 | 
			
		||||
            } else {
 | 
			
		||||
                log.info("[{}][{}] Notification request processing finished in {} ms (sent: {})", ctx.getTenantId(), requestId, time, sent);
 | 
			
		||||
                log.debug("[{}][{}] Notification request processing finished in {} ms (sent: {})", ctx.getTenantId(), requestId, time, sent);
 | 
			
		||||
            }
 | 
			
		||||
            updateRequestStats(ctx, requestId, stats);
 | 
			
		||||
            if (callback != null) {
 | 
			
		||||
 | 
			
		||||
@ -1600,13 +1600,13 @@ queue:
 | 
			
		||||
        # These notifications include RPC calls, lifecycle events, and new queue messages,
 | 
			
		||||
        # requiring minimal latency and swift processing.
 | 
			
		||||
        - key: max.poll.records
 | 
			
		||||
          # Define the maximum number of records that can be polled from tb_edge.notifications.<SERVICE_ID> topics.
 | 
			
		||||
          # Define the maximum number of records that can be polled from tb_edge.notifications.SERVICE_ID topics.
 | 
			
		||||
          value: "${TB_QUEUE_KAFKA_EDGE_HP_EVENTS_MAX_POLL_RECORDS:10}"
 | 
			
		||||
      tb_edge_event.notifications:
 | 
			
		||||
        # Properties for consumers targeting downlinks meant for specific edge topics.
 | 
			
		||||
        # Topic names are dynamically constructed using tenant and edge identifiers.
 | 
			
		||||
        - key: max.poll.records
 | 
			
		||||
          # Define the maximum number of records that can be polled from tb_edge_event.notifications.<TENANT_ID>.<EDGE_ID> topics.
 | 
			
		||||
          # Define the maximum number of records that can be polled from tb_edge_event.notifications.TENANT_ID.EDGE_ID topics.
 | 
			
		||||
          value: "${TB_QUEUE_KAFKA_EDGE_NOTIFICATIONS_MAX_POLL_RECORDS:10}"
 | 
			
		||||
      tb_housekeeper:
 | 
			
		||||
        # Consumer properties for Housekeeper tasks topic
 | 
			
		||||
@ -1861,10 +1861,10 @@ queue:
 | 
			
		||||
    # Topic name to notify edge service on entity updates, assignment, etc.
 | 
			
		||||
    topic: "${TB_QUEUE_EDGE_TOPIC:tb_edge}"
 | 
			
		||||
    # Topic prefix for high-priority edge notifications (rpc, lifecycle, new messages in queue) that require minimum latency and processing time.
 | 
			
		||||
    # Each tb-core has its own topic: <PREFIX>.<SERVICE_ID>
 | 
			
		||||
    # Each tb-core has its own topic: PREFIX.SERVICE_ID
 | 
			
		||||
    notifications_topic: "${TB_QUEUE_EDGE_NOTIFICATIONS_TOPIC:tb_edge.notifications}"
 | 
			
		||||
    # Topic prefix for downlinks to be pushed to specific edge.
 | 
			
		||||
    # Every edge has its own unique topic: <PREFIX>.<TENANT_ID>.<EDGE_ID>
 | 
			
		||||
    # Every edge has its own unique topic: PREFIX.TENANT_ID.EDGE_ID
 | 
			
		||||
    event_notifications_topic: "${TB_QUEUE_EDGE_EVENT_NOTIFICATIONS_TOPIC:tb_edge_event.notifications}"
 | 
			
		||||
    # Amount of partitions used by Edge services
 | 
			
		||||
    partitions: "${TB_QUEUE_EDGE_PARTITIONS:10}"
 | 
			
		||||
 | 
			
		||||
@ -137,6 +137,14 @@ export function isLiteralObject(value: any) {
 | 
			
		||||
  return (!!value) && (value.constructor === Object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const isDate = (obj: any): boolean => {
 | 
			
		||||
  return Object.prototype.toString.call(obj) === "[object Date]";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const isFile = (obj: any): boolean => {
 | 
			
		||||
  return Object.prototype.toString.call(obj) === "[object File]";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const formatValue = (value: any, dec?: number, units?: string, showZeroDecimals?: boolean): string | undefined => {
 | 
			
		||||
  if (isDefinedAndNotNull(value) && isNumeric(value) &&
 | 
			
		||||
    (isDefinedAndNotNull(dec) || isNotEmptyStr(units) || Number(value).toString() === value)) {
 | 
			
		||||
@ -180,7 +188,7 @@ export function deleteNullProperties(obj: any) {
 | 
			
		||||
      delete obj[propName];
 | 
			
		||||
    } else if (isObject(obj[propName])) {
 | 
			
		||||
      deleteNullProperties(obj[propName]);
 | 
			
		||||
    } else if (obj[propName] instanceof Array) {
 | 
			
		||||
    } else if (Array.isArray(obj[propName])) {
 | 
			
		||||
      (obj[propName] as any[]).forEach((elem) => {
 | 
			
		||||
        deleteNullProperties(elem);
 | 
			
		||||
      });
 | 
			
		||||
@ -335,13 +343,11 @@ export function deepClone<T>(target: T, ignoreFields?: string[]): T {
 | 
			
		||||
  if (isObservable(target)) {
 | 
			
		||||
    return target;
 | 
			
		||||
  }
 | 
			
		||||
  if (target instanceof Date) {
 | 
			
		||||
    return new Date(target.getTime()) as any;
 | 
			
		||||
  if (isDate(target)) {
 | 
			
		||||
    return new Date((target as Date).getTime()) as T;
 | 
			
		||||
  }
 | 
			
		||||
  if (target instanceof Array) {
 | 
			
		||||
    const cp = [] as any[];
 | 
			
		||||
    (target as any[]).forEach((v) => { cp.push(v); });
 | 
			
		||||
    return cp.map((n: any) => deepClone<any>(n)) as any;
 | 
			
		||||
  if (Array.isArray(target)) {
 | 
			
		||||
    return (target as any[]).map((item) => deepClone(item)) as any;
 | 
			
		||||
  }
 | 
			
		||||
  if (typeof target === 'object') {
 | 
			
		||||
    const cp = {...(target as { [key: string]: any })} as { [key: string]: any };
 | 
			
		||||
@ -752,7 +758,7 @@ export function sortObjectKeys<T>(obj: T): T {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function deepTrim<T>(obj: T): T {
 | 
			
		||||
  if (isNumber(obj) || isUndefined(obj) || isString(obj) || obj === null || obj instanceof File) {
 | 
			
		||||
  if (isNumber(obj) || isUndefined(obj) || isString(obj) || obj === null || isFile(obj)) {
 | 
			
		||||
    return obj;
 | 
			
		||||
  }
 | 
			
		||||
  return Object.keys(obj).reduce((acc, curr) => {
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ export class AlarmCountWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...countDefaultSettings(true)};
 | 
			
		||||
    return countDefaultSettings(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ export class ActionButtonWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...actionButtonDefaultSettings};
 | 
			
		||||
    return actionButtonDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ export class CommandButtonWidgetSettingsComponent extends WidgetSettingsComponen
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...commandButtonDefaultSettings};
 | 
			
		||||
    return commandButtonDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -61,7 +61,7 @@ export class PowerButtonWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...powerButtonDefaultSettings};
 | 
			
		||||
    return powerButtonDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ export class SegmentedButtonWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...segmentedButtonDefaultSettings};
 | 
			
		||||
    return segmentedButtonDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ export class ToggleButtonWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...toggleButtonDefaultSettings};
 | 
			
		||||
    return toggleButtonDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,6 @@ import {
 | 
			
		||||
  AggregatedValueCardKeyPosition,
 | 
			
		||||
  aggregatedValueCardKeyPositionTranslations
 | 
			
		||||
} from '@home/components/widget/lib/cards/aggregated-value-card.models';
 | 
			
		||||
import { constantColor } from '@shared/models/widget-settings.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-aggregated-value-card-key-settings',
 | 
			
		||||
@ -50,7 +49,7 @@ export class AggregatedValueCardKeySettingsComponent extends WidgetSettingsCompo
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...aggregatedValueCardDefaultKeySettings};
 | 
			
		||||
    return aggregatedValueCardDefaultKeySettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ export class AggregatedValueCardWidgetSettingsComponent extends WidgetSettingsCo
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...aggregatedValueCardDefaultSettings};
 | 
			
		||||
    return aggregatedValueCardDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ export class LabelCardWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...labelCardWidgetDefaultSettings};
 | 
			
		||||
    return labelCardWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ export class LabelValueCardWidgetSettingsComponent extends WidgetSettingsCompone
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...labelValueCardWidgetDefaultSettings};
 | 
			
		||||
    return labelValueCardWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component } from "@angular/core";
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from "@angular/forms";
 | 
			
		||||
import { WidgetSettings, WidgetSettingsComponent } from "@shared/models/widget.models";
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { Store } from "@ngrx/store";
 | 
			
		||||
@ -43,7 +43,7 @@ export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...mobileAppQrCodeWidgetDefaultSettings};
 | 
			
		||||
    return mobileAppQrCodeWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ export class ProgressBarWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...progressBarDefaultSettings};
 | 
			
		||||
    return progressBarDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ export class UnreadNotificationWidgetSettingsComponent extends WidgetSettingsCom
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...unreadNotificationDefaultSettings};
 | 
			
		||||
    return unreadNotificationDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ export class ValueChartCardWidgetSettingsComponent extends WidgetSettingsCompone
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...valueChartCardDefaultSettings};
 | 
			
		||||
    return valueChartCardDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -25,10 +25,10 @@ import {
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { formatValue, mergeDeep } from '@core/utils';
 | 
			
		||||
import { formatValue } from '@core/utils';
 | 
			
		||||
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
 | 
			
		||||
import {
 | 
			
		||||
  barChartWithLabelsDefaultSettings, BarChartWithLabelsWidgetSettings
 | 
			
		||||
  barChartWithLabelsDefaultSettings
 | 
			
		||||
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -68,7 +68,7 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeep<BarChartWithLabelsWidgetSettings>({} as BarChartWithLabelsWidgetSettings, barChartWithLabelsDefaultSettings);
 | 
			
		||||
    return barChartWithLabelsDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -29,9 +29,11 @@ import {
 | 
			
		||||
} from '@shared/models/widget.models';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import {
 | 
			
		||||
  DoughnutLayout, doughnutLayoutImages,
 | 
			
		||||
  DoughnutLayout,
 | 
			
		||||
  doughnutLayoutImages,
 | 
			
		||||
  doughnutLayouts,
 | 
			
		||||
  doughnutLayoutTranslations, horizontalDoughnutLayoutImages
 | 
			
		||||
  doughnutLayoutTranslations,
 | 
			
		||||
  horizontalDoughnutLayoutImages
 | 
			
		||||
} from '@home/components/widget/lib/chart/doughnut-widget.models';
 | 
			
		||||
import {
 | 
			
		||||
  chartLabelPositions,
 | 
			
		||||
@ -44,7 +46,7 @@ import {
 | 
			
		||||
  pieChartLabelPositionTranslations
 | 
			
		||||
} from '@home/components/widget/lib/chart/chart.models';
 | 
			
		||||
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
 | 
			
		||||
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
 | 
			
		||||
import { formatValue, isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
@ -116,7 +118,7 @@ export abstract class LatestChartWidgetSettingsComponent<S extends LatestChartWi
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeep<S>({} as S, this.defaultLatestChartSettings());
 | 
			
		||||
    return this.defaultLatestChartSettings();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -25,11 +25,8 @@ import {
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { formatValue, mergeDeepIgnoreArray } from '@core/utils';
 | 
			
		||||
import {
 | 
			
		||||
  rangeChartDefaultSettings,
 | 
			
		||||
  RangeChartWidgetSettings
 | 
			
		||||
} from '@home/components/widget/lib/chart/range-chart-widget.models';
 | 
			
		||||
import { formatValue } from '@core/utils';
 | 
			
		||||
import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/range-chart-widget.models';
 | 
			
		||||
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
 | 
			
		||||
import {
 | 
			
		||||
  lineSeriesStepTypes,
 | 
			
		||||
@ -99,7 +96,7 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeepIgnoreArray<RangeChartWidgetSettings>({} as RangeChartWidgetSettings, rangeChartDefaultSettings);
 | 
			
		||||
    return rangeChartDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -19,13 +19,16 @@ import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.m
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { isDefinedAndNotNull, mergeDeep } from '@core/utils';
 | 
			
		||||
import { isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
import {
 | 
			
		||||
  timeSeriesChartKeyDefaultSettings,
 | 
			
		||||
  TimeSeriesChartKeySettings,
 | 
			
		||||
  TimeSeriesChartSeriesType,
 | 
			
		||||
  timeSeriesChartSeriesTypes,
 | 
			
		||||
  timeSeriesChartSeriesTypeTranslations, TimeSeriesChartType, timeSeriesChartTypeTranslations, TimeSeriesChartYAxisId
 | 
			
		||||
  timeSeriesChartSeriesTypeTranslations,
 | 
			
		||||
  TimeSeriesChartType,
 | 
			
		||||
  timeSeriesChartTypeTranslations,
 | 
			
		||||
  TimeSeriesChartYAxisId
 | 
			
		||||
} from '@home/components/widget/lib/chart/time-series-chart.models';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
import { TimeSeriesChartWidgetSettings } from '@home/components/widget/lib/chart/time-series-chart-widget.models';
 | 
			
		||||
@ -79,8 +82,7 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeep<TimeSeriesChartKeySettings>({} as TimeSeriesChartKeySettings,
 | 
			
		||||
      timeSeriesChartKeyDefaultSettings);
 | 
			
		||||
    return timeSeriesChartKeyDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -26,11 +26,10 @@ import {
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
 | 
			
		||||
import { formatValue, isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
 | 
			
		||||
import {
 | 
			
		||||
  timeSeriesChartWidgetDefaultSettings,
 | 
			
		||||
  TimeSeriesChartWidgetSettings
 | 
			
		||||
  timeSeriesChartWidgetDefaultSettings
 | 
			
		||||
} from '@home/components/widget/lib/chart/time-series-chart-widget.models';
 | 
			
		||||
import {
 | 
			
		||||
  TimeSeriesChartKeySettings,
 | 
			
		||||
@ -120,7 +119,7 @@ export class TimeSeriesChartWidgetSettingsComponent extends WidgetSettingsCompon
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeep<TimeSeriesChartWidgetSettings>({} as TimeSeriesChartWidgetSettings, timeSeriesChartWidgetDefaultSettings);
 | 
			
		||||
    return timeSeriesChartWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -61,7 +61,7 @@ export class SingleSwitchWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...singleSwitchDefaultSettings};
 | 
			
		||||
    return singleSwitchDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ export class SliderWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...sliderWidgetDefaultSettings};
 | 
			
		||||
    return sliderWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ export class ValueStepperWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...valueStepperDefaultSettings};
 | 
			
		||||
    return valueStepperDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ export class EntityCountWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...countDefaultSettings(false)};
 | 
			
		||||
    return countDefaultSettings(false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,8 @@ import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { formatValue } from '@core/utils';
 | 
			
		||||
import {
 | 
			
		||||
  batteryLevelDefaultSettings, BatteryLevelLayout,
 | 
			
		||||
  batteryLevelDefaultSettings,
 | 
			
		||||
  BatteryLevelLayout,
 | 
			
		||||
  batteryLevelLayoutImages,
 | 
			
		||||
  batteryLevelLayouts,
 | 
			
		||||
  batteryLevelLayoutTranslations
 | 
			
		||||
@ -68,7 +69,7 @@ export class BatteryLevelWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...batteryLevelDefaultSettings};
 | 
			
		||||
    return batteryLevelDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ export class SignalStrengthWidgetSettingsComponent extends WidgetSettingsCompone
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...signalStrengthDefaultSettings};
 | 
			
		||||
    return signalStrengthDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ export class StatusWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...statusWidgetDefaultSettings};
 | 
			
		||||
    return statusWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -40,9 +40,7 @@ export class MapWidgetSettingsLegacyComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {
 | 
			
		||||
      ...defaultMapSettings
 | 
			
		||||
    };
 | 
			
		||||
    return defaultMapSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -40,9 +40,7 @@ export class RouteMapWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {
 | 
			
		||||
      ...defaultMapSettings
 | 
			
		||||
    };
 | 
			
		||||
    return defaultMapSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -57,9 +57,7 @@ export class TripAnimationWidgetSettingsComponent extends WidgetSettingsComponen
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {
 | 
			
		||||
      ...defaultTripAnimationSettings
 | 
			
		||||
    };
 | 
			
		||||
    return defaultTripAnimationSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,8 @@ import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.m
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { isDefinedAndNotNull, mergeDeepIgnoreArray } from '@core/utils';
 | 
			
		||||
import { mapWidgetDefaultSettings, MapWidgetSettings } from '@home/components/widget/lib/maps/map-widget.models';
 | 
			
		||||
import { isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
import { mapWidgetDefaultSettings } from '@home/components/widget/lib/maps/map-widget.models';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -53,7 +53,7 @@ export class MapWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return mergeDeepIgnoreArray<MapWidgetSettings>({} as MapWidgetSettings, mapWidgetDefaultSettings);
 | 
			
		||||
    return mapWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@ export class ScadaSymbolWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...scadaSymbolWidgetDefaultSettings};
 | 
			
		||||
    return scadaSymbolWidgetDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ export class WindSpeedDirectionWidgetSettingsComponent extends WidgetSettingsCom
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...windSpeedDirectionDefaultSettings};
 | 
			
		||||
    return windSpeedDirectionDefaultSettings;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
 | 
			
		||||
@ -472,7 +472,9 @@ export class TbPopoverComponent<T = any> implements OnDestroy, OnInit {
 | 
			
		||||
 | 
			
		||||
  set tbOverlayStyle(value: { [klass: string]: any }) {
 | 
			
		||||
    this._tbOverlayStyle = value;
 | 
			
		||||
    this.cdr.detectChanges();
 | 
			
		||||
    if (this.popover) {
 | 
			
		||||
      this.cdr.detectChanges();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get tbOverlayStyle(): { [klass: string]: any } {
 | 
			
		||||
 | 
			
		||||
@ -113,6 +113,7 @@ export const HelpLinks = {
 | 
			
		||||
    ruleNodeOriginatorTelemetry: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#originator-telemetry`,
 | 
			
		||||
    ruleNodeCustomerAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#customer-attributes`,
 | 
			
		||||
    ruleNodeCustomerDetails: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#customer-details`,
 | 
			
		||||
    ruleNodeFetchDeviceCredentials: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#fetch-device-credentials`,
 | 
			
		||||
    ruleNodeDeviceAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#device-attributes`,
 | 
			
		||||
    ruleNodeRelatedAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#related-attributes`,
 | 
			
		||||
    ruleNodeTenantAttributes: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/enrichment-nodes/#tenant-attributes`,
 | 
			
		||||
@ -120,13 +121,14 @@ export const HelpLinks = {
 | 
			
		||||
    ruleNodeChangeOriginator: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#change-originator`,
 | 
			
		||||
    ruleNodeTransformMsg: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#script-transformation-node`,
 | 
			
		||||
    ruleNodeMsgToEmail: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#to-email-node`,
 | 
			
		||||
    ruleNodeAssignToCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#assign-to-customer-node`,
 | 
			
		||||
    ruleNodeUnassignFromCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/transformation-nodes/#unassign-from-customer-node`,
 | 
			
		||||
    ruleNodeAssignToCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#assign-to-customer-node`,
 | 
			
		||||
    ruleNodeUnassignFromCustomer: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#unassign-from-customer-node`,
 | 
			
		||||
    ruleNodeCalculatedFields: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#calculated-fields-node`,
 | 
			
		||||
    ruleNodeClearAlarm: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#clear-alarm-node`,
 | 
			
		||||
    ruleNodeCreateAlarm: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#create-alarm-node`,
 | 
			
		||||
    ruleNodeCreateRelation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#create-relation-node`,
 | 
			
		||||
    ruleNodeDeleteRelation: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delete-relation-node`,
 | 
			
		||||
    ruleNodeMsgDelay: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delay-node`,
 | 
			
		||||
    ruleNodeMsgDelay: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#delay-node-deprecated`,
 | 
			
		||||
    ruleNodeMsgGenerator: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#generator-node`,
 | 
			
		||||
    ruleNodeGpsGeofencingEvents: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#gps-geofencing-events-node`,
 | 
			
		||||
    ruleNodeLog: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/action-nodes/#log-node`,
 | 
			
		||||
 | 
			
		||||
@ -181,15 +181,15 @@ export const cleanupFormProperty = (property: FormProperty): FormProperty => {
 | 
			
		||||
  if (property.type !== FormPropertyType.textarea) {
 | 
			
		||||
    delete property.rows;
 | 
			
		||||
  }
 | 
			
		||||
  if (property.type !== FormPropertyType.fieldset) {
 | 
			
		||||
    delete property.properties;
 | 
			
		||||
  } else if (property.properties?.length) {
 | 
			
		||||
    property.properties = cleanupFormProperties(property.properties);
 | 
			
		||||
  }
 | 
			
		||||
  if (property.type !== FormPropertyType.array) {
 | 
			
		||||
    delete property.arrayItemName;
 | 
			
		||||
    delete property.arrayItemType;
 | 
			
		||||
  }
 | 
			
		||||
  if (property.type !== FormPropertyType.fieldset && property.arrayItemType !== FormPropertyType.fieldset) {
 | 
			
		||||
    delete property.properties;
 | 
			
		||||
  } else if (property.properties?.length) {
 | 
			
		||||
    property.properties = cleanupFormProperties(property.properties);
 | 
			
		||||
  }
 | 
			
		||||
  if (property.type !== FormPropertyType.select) {
 | 
			
		||||
    delete property.multiple;
 | 
			
		||||
    delete property.allowEmptyOption;
 | 
			
		||||
 | 
			
		||||
@ -469,6 +469,7 @@ const ruleNodeClazzHelpLinkMap = {
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetTelemetryNode': 'ruleNodeOriginatorTelemetry',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetCustomerAttributeNode': 'ruleNodeCustomerAttributes',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetCustomerDetailsNode': 'ruleNodeCustomerDetails',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbFetchDeviceCredentialsNode': 'ruleNodeFetchDeviceCredentials',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetDeviceAttrNode': 'ruleNodeDeviceAttributes',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode': 'ruleNodeRelatedAttributes',
 | 
			
		||||
  'org.thingsboard.rule.engine.metadata.TbGetTenantAttributeNode': 'ruleNodeTenantAttributes',
 | 
			
		||||
@ -479,6 +480,7 @@ const ruleNodeClazzHelpLinkMap = {
 | 
			
		||||
  'org.thingsboard.rule.engine.mail.TbMsgToEmailNode': 'ruleNodeMsgToEmail',
 | 
			
		||||
  'org.thingsboard.rule.engine.action.TbAssignToCustomerNode': 'ruleNodeAssignToCustomer',
 | 
			
		||||
  'org.thingsboard.rule.engine.action.TbUnassignFromCustomerNode': 'ruleNodeUnassignFromCustomer',
 | 
			
		||||
  'org.thingsboard.rule.engine.telemetry.TbCalculatedFieldsNode': 'ruleNodeCalculatedFields',
 | 
			
		||||
  'org.thingsboard.rule.engine.action.TbClearAlarmNode': 'ruleNodeClearAlarm',
 | 
			
		||||
  'org.thingsboard.rule.engine.action.TbCreateAlarmNode': 'ruleNodeCreateAlarm',
 | 
			
		||||
  'org.thingsboard.rule.engine.action.TbCreateRelationNode': 'ruleNodeCreateRelation',
 | 
			
		||||
 | 
			
		||||
@ -37,17 +37,19 @@ import { AbstractControl, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { Dashboard } from '@shared/models/dashboard.models';
 | 
			
		||||
import { IAliasController } from '@core/api/widget-api.models';
 | 
			
		||||
import { isNotEmptyStr, mergeDeepIgnoreArray } from '@core/utils';
 | 
			
		||||
import { isNotEmptyStr, mergeDeep, mergeDeepIgnoreArray } from '@core/utils';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
import { ComponentStyle, Font, TimewindowStyle } from '@shared/models/widget-settings.models';
 | 
			
		||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
 | 
			
		||||
import { EntityInfoData, HasTenantId, HasVersion } from '@shared/models/entity.models';
 | 
			
		||||
import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/lib/settings/common/key/data-keys.component.models';
 | 
			
		||||
import {
 | 
			
		||||
  DataKeysCallbacks,
 | 
			
		||||
  DataKeySettingsFunction
 | 
			
		||||
} from '@home/components/widget/lib/settings/common/key/data-keys.component.models';
 | 
			
		||||
import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models';
 | 
			
		||||
import { TbFunction } from '@shared/models/js-function.models';
 | 
			
		||||
import { FormProperty, jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models';
 | 
			
		||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
 | 
			
		||||
import { Device } from '@shared/models/device.models';
 | 
			
		||||
 | 
			
		||||
export enum widgetType {
 | 
			
		||||
  timeseries = 'timeseries',
 | 
			
		||||
@ -1000,9 +1002,9 @@ export abstract class WidgetSettingsComponent extends PageComponent implements
 | 
			
		||||
 | 
			
		||||
  set settings(value: WidgetSettings) {
 | 
			
		||||
    if (!value) {
 | 
			
		||||
      this.settingsValue = this.defaultSettings();
 | 
			
		||||
      this.settingsValue = mergeDeep({}, this.defaultSettings());
 | 
			
		||||
    } else {
 | 
			
		||||
      this.settingsValue = mergeDeepIgnoreArray(this.defaultSettings(), value);
 | 
			
		||||
      this.settingsValue = mergeDeepIgnoreArray({}, this.defaultSettings(), value);
 | 
			
		||||
    }
 | 
			
		||||
    if (!this.settingsSet) {
 | 
			
		||||
      this.settingsSet = true;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user