33 changed files with 1569 additions and 178 deletions
@ -0,0 +1,35 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Dashboard, DashboardLayoutId } from '@app/shared/models/dashboard.models'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class ItemBufferService { |
||||
|
constructor() {} |
||||
|
|
||||
|
public hasWidget(): boolean { |
||||
|
// TODO:
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public canPasteWidgetReference(dashboard: Dashboard, state: string, layout: DashboardLayoutId): boolean { |
||||
|
// TODO:
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<mat-tab-group [ngClass]="{'tb-headless': (widgetType === widgetTypes.static && !displayAdvanced())}" |
||||
|
fxFlex class="tb-widget-config tb-absolute-fill" [selectedIndex]="selectedTab"> |
||||
|
<mat-tab label="{{ 'widget-config.data' | translate }}" [fxShow]="widgetType !== widgetTypes.static"> |
||||
|
<div class="mat-content mat-padding" fxLayout="column"> |
||||
|
<div [fxShow]="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm" |
||||
|
fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"> |
||||
|
<div fxLayout="column" fxFlex> |
||||
|
<mat-checkbox fxFlex [(ngModel)]="useDashboardTimewindow" (ngModelChange)="updateModel()"> |
||||
|
{{ 'widget-config.use-dashboard-timewindow' | translate }} |
||||
|
</mat-checkbox> |
||||
|
<mat-checkbox [disabled]="useDashboardTimewindow" fxFlex [(ngModel)]="displayTimewindow" (ngModelChange)="updateModel()"> |
||||
|
{{ 'widget-config.display-timewindow' | translate }} |
||||
|
</mat-checkbox> |
||||
|
</div> |
||||
|
<section fxFlex fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;"> |
||||
|
<span [ngClass]="{'tb-disabled-label': useDashboardTimewindow}" translate style="padding-right: 8px;">widget-config.timewindow</span> |
||||
|
<tb-timewindow [disabled]="useDashboardTimewindow" asButton="true" |
||||
|
aggregation="{{ widgetType === widgetTypes.timeseries }}" |
||||
|
fxFlex [(ngModel)]="timewindow" (ngModelChange)="updateModel()"></tb-timewindow> |
||||
|
</section> |
||||
|
</div> |
||||
|
</div> |
||||
|
</mat-tab> |
||||
|
<mat-tab label="{{ 'widget-config.settings' | translate }}"> |
||||
|
</mat-tab> |
||||
|
</mat-tab-group> |
||||
@ -0,0 +1,32 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
:host { |
||||
|
.tb-widget-config { |
||||
|
.tb-advanced-widget-config { |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:host ::ng-deep { |
||||
|
.tb-widget-config { |
||||
|
.mat-tab-body.mat-tab-body-active { |
||||
|
.mat-tab-body-content > div { |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,282 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Component, forwardRef, Input, OnInit } from '@angular/core'; |
||||
|
import { PageComponent } from '@shared/components/page.component'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { |
||||
|
Datasource, |
||||
|
LegendConfig, |
||||
|
WidgetActionDescriptor, |
||||
|
WidgetActionSource, WidgetConfigSettings, |
||||
|
widgetType, |
||||
|
WidgetTypeParameters |
||||
|
} from '@shared/models/widget.models'; |
||||
|
import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; |
||||
|
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; |
||||
|
import { deepClone, isDefined } from '@app/core/utils'; |
||||
|
import { Timewindow } from '@shared/models/time/time.models'; |
||||
|
import { AlarmSearchStatus } from '@shared/models/alarm.models'; |
||||
|
import { IAliasController } from '@core/api/widget-api.models'; |
||||
|
import { EntityAlias } from '@shared/models/alias.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-widget-config', |
||||
|
templateUrl: './widget-config.component.html', |
||||
|
styleUrls: ['./widget-config.component.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => WidgetConfigComponent), |
||||
|
multi: true |
||||
|
}, |
||||
|
{ |
||||
|
provide: NG_VALIDATORS, |
||||
|
useExisting: forwardRef(() => WidgetConfigComponent), |
||||
|
multi: true, |
||||
|
} |
||||
|
] |
||||
|
}) |
||||
|
export class WidgetConfigComponent extends PageComponent implements OnInit, ControlValueAccessor, Validator { |
||||
|
|
||||
|
widgetTypes = widgetType; |
||||
|
|
||||
|
@Input() |
||||
|
forceExpandDatasources: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
isDataEnabled: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
widgetType: widgetType; |
||||
|
|
||||
|
@Input() |
||||
|
typeParameters: WidgetTypeParameters; |
||||
|
|
||||
|
@Input() |
||||
|
actionSources: {[key: string]: WidgetActionSource}; |
||||
|
|
||||
|
@Input() |
||||
|
aliasController: IAliasController; |
||||
|
|
||||
|
@Input() |
||||
|
widgetSettingsSchema: any; |
||||
|
|
||||
|
@Input() |
||||
|
dataKeySettingsSchema: any; |
||||
|
|
||||
|
@Input() |
||||
|
functionsOnly: boolean; |
||||
|
|
||||
|
@Input() disabled: boolean; |
||||
|
|
||||
|
selectedTab: number; |
||||
|
title: string; |
||||
|
showTitleIcon: boolean; |
||||
|
titleIcon: string; |
||||
|
iconColor: string; |
||||
|
iconSize: string; |
||||
|
showTitle: boolean; |
||||
|
dropShadow: boolean; |
||||
|
enableFullscreen: boolean; |
||||
|
backgroundColor: string; |
||||
|
color: string; |
||||
|
padding: string; |
||||
|
margin: string; |
||||
|
widgetStyle: string; |
||||
|
titleStyle: string; |
||||
|
units: string; |
||||
|
decimals: number; |
||||
|
useDashboardTimewindow: boolean; |
||||
|
displayTimewindow: boolean; |
||||
|
timewindow: Timewindow; |
||||
|
showLegend: boolean; |
||||
|
legendConfig: LegendConfig; |
||||
|
actions: {[actionSourceId: string]: Array<WidgetActionDescriptor>}; |
||||
|
datasources: Array<Datasource>; |
||||
|
targetDeviceAlias: EntityAlias; |
||||
|
alarmSource: Datasource; |
||||
|
alarmSearchStatus: AlarmSearchStatus; |
||||
|
alarmsPollingInterval: number; |
||||
|
settings: WidgetConfigSettings; |
||||
|
mobileOrder: number; |
||||
|
mobileHeight: number; |
||||
|
|
||||
|
emptySettingsSchema = { |
||||
|
type: 'object', |
||||
|
properties: {} |
||||
|
}; |
||||
|
|
||||
|
emptySettingsGroupInfoes = []; |
||||
|
|
||||
|
defaultSettingsForm = [ |
||||
|
'*' |
||||
|
]; |
||||
|
|
||||
|
currentSettingsSchema = deepClone(this.emptySettingsSchema); |
||||
|
|
||||
|
currentSettings: WidgetConfigSettings = {}; |
||||
|
currentSettingsGroupInfoes = deepClone(this.emptySettingsGroupInfoes); |
||||
|
|
||||
|
currentSettingsForm: any; |
||||
|
|
||||
|
private modelValue: WidgetConfigComponentData; |
||||
|
|
||||
|
private propagateChange = null; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>) { |
||||
|
super(store); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
} |
||||
|
|
||||
|
writeValue(value: WidgetConfigComponentData): void { |
||||
|
this.modelValue = value; |
||||
|
if (this.modelValue) { |
||||
|
const config = this.modelValue.config; |
||||
|
const layout = this.modelValue.layout; |
||||
|
if (config) { |
||||
|
this.selectedTab = 0; |
||||
|
this.title = config.title; |
||||
|
this.showTitleIcon = isDefined(config.showTitleIcon) ? config.showTitleIcon : false; |
||||
|
this.titleIcon = isDefined(config.titleIcon) ? config.titleIcon : ''; |
||||
|
this.iconColor = isDefined(config.iconColor) ? config.iconColor : 'rgba(0, 0, 0, 0.87)'; |
||||
|
this.iconSize = isDefined(config.iconSize) ? config.iconSize : '24px'; |
||||
|
this.showTitle = config.showTitle; |
||||
|
this.dropShadow = isDefined(config.dropShadow) ? config.dropShadow : true; |
||||
|
this.enableFullscreen = isDefined(config.enableFullscreen) ? config.enableFullscreen : true; |
||||
|
this.backgroundColor = config.backgroundColor; |
||||
|
this.color = config.color; |
||||
|
this.padding = config.padding; |
||||
|
this.margin = config.margin; |
||||
|
this.widgetStyle = |
||||
|
JSON.stringify(isDefined(config.widgetStyle) ? config.widgetStyle : {}, null, 2); |
||||
|
this.titleStyle = |
||||
|
JSON.stringify(isDefined(config.titleStyle) ? config.titleStyle : { |
||||
|
fontSize: '16px', |
||||
|
fontWeight: 400 |
||||
|
}, null, 2); |
||||
|
this.units = config.units; |
||||
|
this.decimals = config.decimals; |
||||
|
this.useDashboardTimewindow = isDefined(config.useDashboardTimewindow) ? |
||||
|
config.useDashboardTimewindow : true; |
||||
|
this.displayTimewindow = isDefined(config.displayTimewindow) ? |
||||
|
config.displayTimewindow : true; |
||||
|
this.timewindow = config.timewindow; |
||||
|
this.actions = config.actions; |
||||
|
if (!this.actions) { |
||||
|
this.actions = {}; |
||||
|
} |
||||
|
if (this.isDataEnabled) { |
||||
|
if (this.widgetType !== widgetType.rpc && |
||||
|
this.widgetType !== widgetType.alarm && |
||||
|
this.widgetType !== widgetType.static) { |
||||
|
if (config.datasources) { |
||||
|
this.datasources = config.datasources; |
||||
|
} else { |
||||
|
this.datasources = []; |
||||
|
} |
||||
|
} else if (this.widgetType === widgetType.rpc) { |
||||
|
if (config.targetDeviceAliasIds && config.targetDeviceAliasIds.length > 0) { |
||||
|
const aliasId = config.targetDeviceAliasIds[0]; |
||||
|
const entityAliases = this.aliasController.getEntityAliases(); |
||||
|
if (entityAliases[aliasId]) { |
||||
|
this.targetDeviceAlias = entityAliases[aliasId]; |
||||
|
} else { |
||||
|
this.targetDeviceAlias = null; |
||||
|
} |
||||
|
} else { |
||||
|
this.targetDeviceAlias = null; |
||||
|
} |
||||
|
} else if (this.widgetType === widgetType.alarm) { |
||||
|
this.alarmSearchStatus = isDefined(config.alarmSearchStatus) ? |
||||
|
config.alarmSearchStatus : AlarmSearchStatus.ANY; |
||||
|
this.alarmsPollingInterval = isDefined(config.alarmsPollingInterval) ? |
||||
|
config.alarmsPollingInterval : 5; |
||||
|
if (config.alarmSource) { |
||||
|
this.alarmSource = config.alarmSource; |
||||
|
} else { |
||||
|
this.alarmSource = null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
this.settings = config.settings; |
||||
|
|
||||
|
this.updateSchemaForm(); |
||||
|
|
||||
|
if (layout) { |
||||
|
this.mobileOrder = layout.mobileOrder; |
||||
|
this.mobileHeight = layout.mobileHeight; |
||||
|
} else { |
||||
|
this.mobileOrder = undefined; |
||||
|
this.mobileHeight = undefined; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private updateSchemaForm() { |
||||
|
if (this.widgetSettingsSchema && this.widgetSettingsSchema.schema) { |
||||
|
this.currentSettingsSchema = this.widgetSettingsSchema.schema; |
||||
|
this.currentSettingsForm = this.widgetSettingsSchema.form || deepClone(this.defaultSettingsForm); |
||||
|
this.currentSettingsGroupInfoes = this.widgetSettingsSchema.groupInfoes; |
||||
|
this.currentSettings = this.settings; |
||||
|
} else { |
||||
|
this.currentSettingsForm = deepClone(this.defaultSettingsForm); |
||||
|
this.currentSettingsSchema = deepClone(this.emptySettingsSchema); |
||||
|
this.currentSettingsGroupInfoes = deepClone(this.emptySettingsGroupInfoes); |
||||
|
this.currentSettings = {}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public updateModel() { |
||||
|
if (this.modelValue) { |
||||
|
if (this.modelValue.config) { |
||||
|
const config = this.modelValue.config; |
||||
|
config.useDashboardTimewindow = this.useDashboardTimewindow; |
||||
|
config.displayTimewindow = this.displayTimewindow; |
||||
|
config.timewindow = this.timewindow; |
||||
|
} |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public displayAdvanced(): boolean { |
||||
|
return this.widgetSettingsSchema && this.widgetSettingsSchema.schema; |
||||
|
} |
||||
|
|
||||
|
public validate(c: FormControl) { |
||||
|
return null; /*{ |
||||
|
targetDeviceAliasIds: { |
||||
|
valid: false, |
||||
|
}, |
||||
|
};*/ |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<form [formGroup]="widgetFormGroup"> |
||||
|
<fieldset [disabled]="isLoading$ | async"> |
||||
|
<tb-widget-config |
||||
|
[widgetType]="widget.type" |
||||
|
[typeParameters]="typeParameters" |
||||
|
[actionSources]="actionSources" |
||||
|
[isDataEnabled]="isDataEnabled" |
||||
|
[widgetSettingsSchema]="settingsSchema" |
||||
|
[dataKeySettingsSchema]="dataKeySettingsSchema" |
||||
|
[aliasController]="aliasController" |
||||
|
[functionsOnly]="widgetEditMode" |
||||
|
formControlName="widgetConfig"> |
||||
|
</tb-widget-config> |
||||
|
</fieldset> |
||||
|
</form> |
||||
@ -0,0 +1,115 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core'; |
||||
|
import { PageComponent } from '@shared/components/page.component'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { ActivatedRoute, Router } from '@angular/router'; |
||||
|
import { WidgetService } from '@core/http/widget.service'; |
||||
|
import { DialogService } from '@core/services/dialog.service'; |
||||
|
import { MatDialog } from '@angular/material/dialog'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { Dashboard, WidgetLayout } from '@shared/models/dashboard.models'; |
||||
|
import { IAliasController } from '@core/api/widget-api.models'; |
||||
|
import { Widget, WidgetActionSource, WidgetTypeParameters } from '@shared/models/widget.models'; |
||||
|
import { WidgetComponentService } from '@home/components/widget/widget-component.service'; |
||||
|
import { WidgetConfigComponentData } from '../../models/widget-component.models'; |
||||
|
import { isString } from '@core/utils'; |
||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-edit-widget', |
||||
|
templateUrl: './edit-widget.component.html', |
||||
|
styleUrls: [] |
||||
|
}) |
||||
|
export class EditWidgetComponent extends PageComponent implements OnInit, OnChanges { |
||||
|
|
||||
|
@Input() |
||||
|
dashboard: Dashboard; |
||||
|
|
||||
|
@Input() |
||||
|
aliasController: IAliasController; |
||||
|
|
||||
|
@Input() |
||||
|
widgetEditMode: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
widget: Widget; |
||||
|
|
||||
|
@Input() |
||||
|
widgetLayout: WidgetLayout; |
||||
|
|
||||
|
@Input() |
||||
|
widgetFormGroup: FormGroup; |
||||
|
|
||||
|
widgetConfig: WidgetConfigComponentData; |
||||
|
typeParameters: WidgetTypeParameters; |
||||
|
actionSources: {[key: string]: WidgetActionSource}; |
||||
|
isDataEnabled: boolean; |
||||
|
settingsSchema: any; |
||||
|
dataKeySettingsSchema: any; |
||||
|
functionsOnly: boolean; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
private widgetComponentService: WidgetComponentService) { |
||||
|
super(store); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.loadWidgetConfig(); |
||||
|
} |
||||
|
|
||||
|
ngOnChanges(changes: SimpleChanges): void { |
||||
|
let reloadConfig = false; |
||||
|
for (const propName of Object.keys(changes)) { |
||||
|
const change = changes[propName]; |
||||
|
if (!change.firstChange && change.currentValue !== change.previousValue) { |
||||
|
if (['widget', 'widgetLayout'].includes(propName)) { |
||||
|
reloadConfig = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (reloadConfig) { |
||||
|
this.loadWidgetConfig(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private loadWidgetConfig() { |
||||
|
const widgetInfo = this.widgetComponentService.getInstantWidgetInfo(this.widget); |
||||
|
this.widgetConfig = { |
||||
|
config: this.widget.config, |
||||
|
layout: this.widgetLayout |
||||
|
}; |
||||
|
const settingsSchema = widgetInfo.typeSettingsSchema || widgetInfo.settingsSchema; |
||||
|
const dataKeySettingsSchema = widgetInfo.typeDataKeySettingsSchema || widgetInfo.dataKeySettingsSchema; |
||||
|
this.typeParameters = widgetInfo.typeParameters; |
||||
|
this.actionSources = widgetInfo.actionSources; |
||||
|
this.isDataEnabled = widgetInfo.typeParameters && !widgetInfo.typeParameters.useCustomDatasources; |
||||
|
if (!settingsSchema || settingsSchema === '') { |
||||
|
this.settingsSchema = {}; |
||||
|
} else { |
||||
|
this.settingsSchema = isString(settingsSchema) ? JSON.parse(settingsSchema) : settingsSchema; |
||||
|
} |
||||
|
if (!dataKeySettingsSchema || dataKeySettingsSchema === '') { |
||||
|
this.dataKeySettingsSchema = {}; |
||||
|
} else { |
||||
|
this.dataKeySettingsSchema = isString(dataKeySettingsSchema) ? JSON.parse(dataKeySettingsSchema) : dataKeySettingsSchema; |
||||
|
} |
||||
|
this.functionsOnly = this.dashboard ? false : true; |
||||
|
this.widgetFormGroup.reset({widgetConfig: this.widgetConfig}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Inject, Pipe, PipeTransform } from '@angular/core'; |
||||
|
import { WINDOW } from '@core/services/window.service'; |
||||
|
|
||||
|
@Pipe({ |
||||
|
name: 'keyboardShortcut' |
||||
|
}) |
||||
|
export class KeyboardShortcutPipe implements PipeTransform { |
||||
|
|
||||
|
constructor(@Inject(WINDOW) private window: Window) {} |
||||
|
|
||||
|
transform(value: string): string { |
||||
|
if (!value) { |
||||
|
return; |
||||
|
} |
||||
|
const keys = value.split('-'); |
||||
|
const isOSX = /Mac OS X/.test(this.window.navigator.userAgent); |
||||
|
|
||||
|
const seperator = (!isOSX || keys.length > 2) ? '+' : ''; |
||||
|
|
||||
|
const abbreviations = { |
||||
|
M: isOSX ? '⌘' : 'Ctrl', |
||||
|
A: isOSX ? 'Option' : 'Alt', |
||||
|
S: 'Shift' |
||||
|
}; |
||||
|
|
||||
|
return keys.map((key, index) => { |
||||
|
const last = index === keys.length - 1; |
||||
|
return last ? key : abbreviations[key]; |
||||
|
}).join(seperator); |
||||
|
return (!value) ? '' : value.replace(/ /g, ''); |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue