UI: Ability to import form properties from JSON content. Update help resources according to new widget settings forms.
This commit is contained in:
parent
39abbacb20
commit
f6071177ae
@ -37,7 +37,12 @@ import {
|
||||
} from '@angular/forms';
|
||||
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FormProperty, FormPropertyType, propertyValid } from '@shared/models/dynamic-form.models';
|
||||
import {
|
||||
cleanupFormProperties,
|
||||
FormProperty,
|
||||
FormPropertyType,
|
||||
propertyValid
|
||||
} from '@shared/models/dynamic-form.models';
|
||||
import {
|
||||
DynamicFormPropertyRowComponent
|
||||
} from '@home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component';
|
||||
@ -134,7 +139,7 @@ export class DynamicFormPropertiesComponent implements ControlValueAccessor, OnI
|
||||
controls[i].patchValue(p, {emitEvent: false});
|
||||
}
|
||||
});
|
||||
this.propagateChange(properties);
|
||||
this.propagateChange(cleanupFormProperties(properties));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -54,8 +54,24 @@ const widgetEditorCompletions = (settingsCompletions?: TbEditorCompletions): TbE
|
||||
description: 'Called when widget element is destroyed. Should be used to cleanup all resources if necessary.',
|
||||
meta: 'function'
|
||||
},
|
||||
getSettingsForm: {
|
||||
description: 'Optional function returning widget settings form array as alternative to <b>Settings form</b> tab of settings section.',
|
||||
meta: 'function',
|
||||
return: {
|
||||
description: 'An array of widget settings form properties',
|
||||
type: 'Array<FormProperty>'
|
||||
}
|
||||
},
|
||||
getDataKeySettingsForm: {
|
||||
description: 'Optional function returning particular data key settings form array as alternative to <b>Data key settings form</b> tab of settings section.',
|
||||
meta: 'function',
|
||||
return: {
|
||||
description: 'An array of data key settings form properties',
|
||||
type: 'Array<FormProperty>'
|
||||
}
|
||||
},
|
||||
getSettingsSchema: {
|
||||
description: 'Optional function returning widget settings schema json as alternative to <b>Settings tab</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">Settings schema section</a>.',
|
||||
description: '<b>Deprecated</b>. Use getSettingsForm() function.',
|
||||
meta: 'function',
|
||||
return: {
|
||||
description: 'An widget settings schema json',
|
||||
@ -63,7 +79,7 @@ const widgetEditorCompletions = (settingsCompletions?: TbEditorCompletions): TbE
|
||||
}
|
||||
},
|
||||
getDataKeySettingsSchema: {
|
||||
description: 'Optional function returning particular data key settings schema json as alternative to <b>Data key settings schema</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">Settings schema section</a>.',
|
||||
description: '<b>Deprecated</b>. Use getDataKeySettingsForm() function.',
|
||||
meta: 'function',
|
||||
return: {
|
||||
description: 'A particular data key settings schema json',
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<form [formGroup]="importFormGroup" (ngSubmit)="importFromJson()">
|
||||
<form [formGroup]="importFormGroup" (ngSubmit)="importFromJson()" style="width: 500px;">
|
||||
<mat-toolbar color="primary">
|
||||
<h2 translate>{{ importTitle }}</h2>
|
||||
<span class="flex-1"></span>
|
||||
@ -30,15 +30,28 @@
|
||||
<div mat-dialog-content>
|
||||
<fieldset [disabled]="isLoading$ | async">
|
||||
<div class="flex flex-1 flex-col">
|
||||
<tb-file-input
|
||||
<tb-toggle-select *ngIf="enableImportFromContent"
|
||||
class="flex-1"
|
||||
formControlName="importType">
|
||||
<tb-toggle-option value="file">{{ importFileLabel | translate }}</tb-toggle-option>
|
||||
<tb-toggle-option value="content">{{ importContentLabel | translate }}</tb-toggle-option>
|
||||
</tb-toggle-select>
|
||||
<tb-file-input *ngIf="importFormGroup.get('importType').value === 'file'"
|
||||
[contentConvertFunction]="loadDataFromJsonContent"
|
||||
formControlName="jsonContent"
|
||||
[existingFileName]="currentFileName"
|
||||
(fileNameChanged)="currentFileName = $event"
|
||||
formControlName="fileContent"
|
||||
required
|
||||
label="{{importFileLabel | translate}}"
|
||||
dropLabel="{{ 'import.drop-json-file-or' | translate }}"
|
||||
accept=".json,application/json"
|
||||
allowedExtensions="json">
|
||||
</tb-file-input>
|
||||
<tb-json-object-edit *ngIf="importFormGroup.get('importType').value === 'content'"
|
||||
formControlName="jsonContent"
|
||||
jsonRequired
|
||||
label="{{ importContentLabel | translate }}">
|
||||
</tb-json-object-edit>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
|
||||
import { Component, DestroyRef, Inject, OnInit, SkipSelf } from '@angular/core';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
@ -23,10 +23,14 @@ import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDire
|
||||
import { Router } from '@angular/router';
|
||||
import { DialogComponent } from '@app/shared/components/dialog.component';
|
||||
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
||||
import { isDefinedAndNotNull } from '@core/utils';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
export interface ImportDialogData {
|
||||
importTitle: string;
|
||||
importFileLabel: string;
|
||||
enableImportFromContent?: boolean;
|
||||
importContentLabel?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -40,9 +44,13 @@ export class ImportDialogComponent extends DialogComponent<ImportDialogComponent
|
||||
|
||||
importTitle: string;
|
||||
importFileLabel: string;
|
||||
enableImportFromContent: boolean;
|
||||
importContentLabel: string;
|
||||
|
||||
importFormGroup: UntypedFormGroup;
|
||||
|
||||
currentFileName: string;
|
||||
|
||||
submitted = false;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
@ -50,17 +58,26 @@ export class ImportDialogComponent extends DialogComponent<ImportDialogComponent
|
||||
@Inject(MAT_DIALOG_DATA) public data: ImportDialogData,
|
||||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
||||
public dialogRef: MatDialogRef<ImportDialogComponent>,
|
||||
private destroyRef: DestroyRef,
|
||||
private fb: UntypedFormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
this.importTitle = data.importTitle;
|
||||
this.importFileLabel = data.importFileLabel;
|
||||
|
||||
this.importFormGroup = this.fb.group({
|
||||
jsonContent: [null, [Validators.required]]
|
||||
});
|
||||
this.enableImportFromContent = isDefinedAndNotNull(data.enableImportFromContent) ? data.enableImportFromContent : false;
|
||||
this.importContentLabel = data.importContentLabel;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.importFormGroup = this.fb.group({
|
||||
importType: ['file'],
|
||||
fileContent: [null, [Validators.required]],
|
||||
jsonContent: [null, [Validators.required]]
|
||||
});
|
||||
this.importFormGroup.get('importType').valueChanges.pipe(
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {
|
||||
this.importTypeChanged();
|
||||
});
|
||||
}
|
||||
|
||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
@ -85,7 +102,19 @@ export class ImportDialogComponent extends DialogComponent<ImportDialogComponent
|
||||
|
||||
importFromJson(): void {
|
||||
this.submitted = true;
|
||||
const importData = this.importFormGroup.get('jsonContent').value;
|
||||
const importType: 'file' | 'content' = this.importFormGroup.get('importType').value;
|
||||
const importData = this.importFormGroup.get(importType === 'file' ? 'fileContent' : 'jsonContent').value;
|
||||
this.dialogRef.close(importData);
|
||||
}
|
||||
|
||||
private importTypeChanged() {
|
||||
const importType: 'file' | 'content' = this.importFormGroup.get('importType').value;
|
||||
if (importType === 'file') {
|
||||
this.importFormGroup.get('fileContent').enable({emitEvent: false});
|
||||
this.importFormGroup.get('jsonContent').disable({emitEvent: false});
|
||||
} else {
|
||||
this.importFormGroup.get('fileContent').disable({emitEvent: false});
|
||||
this.importFormGroup.get('jsonContent').enable({emitEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ export class ImportExportService {
|
||||
}
|
||||
|
||||
public importFormProperties(): Observable<FormProperty[]> {
|
||||
return this.openImportDialog('dynamic-form.import-form', 'dynamic-form.form-json-file').pipe(
|
||||
return this.openImportDialog('dynamic-form.import-form',
|
||||
'dynamic-form.json-file', true, 'dynamic-form.json-content').pipe(
|
||||
map((properties: FormProperty[]) => {
|
||||
if (!this.validateImportedFormProperties(properties)) {
|
||||
this.store.dispatch(new ActionNotificationShow(
|
||||
@ -1134,14 +1135,17 @@ export class ImportExportService {
|
||||
};
|
||||
}
|
||||
|
||||
private openImportDialog(importTitle: string, importFileLabel: string): Observable<any> {
|
||||
private openImportDialog(importTitle: string, importFileLabel: string,
|
||||
enableImportFromContent = false, importContentLabel?: string): Observable<any> {
|
||||
return this.dialog.open<ImportDialogComponent, ImportDialogData,
|
||||
any>(ImportDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
importTitle,
|
||||
importFileLabel
|
||||
importFileLabel,
|
||||
enableImportFromContent,
|
||||
importContentLabel
|
||||
}
|
||||
}).afterClosed().pipe(
|
||||
map((importedData) => {
|
||||
|
||||
@ -325,7 +325,7 @@ export const widgetContextCompletionsWithSettings = (settingsCompletions?: TbEdi
|
||||
type: 'object'
|
||||
},
|
||||
settings: {
|
||||
description: 'Widget settings containing widget specific properties according to the defined <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">settings json schema</a>',
|
||||
description: 'Widget settings containing widget specific properties according to the defined settings form.',
|
||||
meta: 'property',
|
||||
type: 'object',
|
||||
children: settingsCompletions
|
||||
@ -363,7 +363,7 @@ export const widgetContextCompletionsWithSettings = (settingsCompletions?: TbEdi
|
||||
}
|
||||
},
|
||||
settings: {
|
||||
description: 'Widget settings containing widget specific properties according to the defined <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">settings json schema</a>',
|
||||
description: 'Widget settings containing widget specific properties according to the defined settings form.',
|
||||
meta: 'property',
|
||||
type: 'object',
|
||||
children: settingsCompletions
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
|
||||
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
|
||||
import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models';
|
||||
import { deepClone, isDefinedAndNotNull, isString } from '@core/utils';
|
||||
import { JsonSchema, JsonSettingsSchema, JsonFormData, KeyLabelItem } from '@shared/legacy/json-form.models';
|
||||
import { deepClone, isDefinedAndNotNull, isEmptyStr, isString, isUndefinedOrNull } from '@core/utils';
|
||||
import { JsonFormData, JsonSchema, JsonSettingsSchema, KeyLabelItem } from '@shared/legacy/json-form.models';
|
||||
import JsonFormUtils from '@shared/legacy/json-form-utils';
|
||||
import { constantColor, Font } from '@shared/models/widget-settings.models';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
@ -165,6 +165,63 @@ export interface FormHtmlSection extends FormPropertyBase {
|
||||
export type FormProperty = FormPropertyBase & FormTextareaProperty & FormNumberProperty & FormSelectProperty & FormRadiosProperty
|
||||
& FormDateTimeProperty & FormJavascriptProperty & FormMarkdownProperty & FormFieldSetProperty & FormArrayProperty & FormHtmlSection;
|
||||
|
||||
export const cleanupFormProperties = (properties: FormProperty[]): FormProperty[] => {
|
||||
for (const property of properties) {
|
||||
cleanupFormProperty(property);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
export const cleanupFormProperty = (property: FormProperty): FormProperty => {
|
||||
if (property.type !== FormPropertyType.number) {
|
||||
delete property.min;
|
||||
delete property.max;
|
||||
delete property.step;
|
||||
}
|
||||
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.select) {
|
||||
delete property.multiple;
|
||||
delete property.allowEmptyOption;
|
||||
delete property.minItems;
|
||||
delete property.maxItems;
|
||||
}
|
||||
if (property.type !== FormPropertyType.radios) {
|
||||
delete property.direction;
|
||||
}
|
||||
if (![FormPropertyType.select, FormPropertyType.radios].includes(property.type)) {
|
||||
delete property.items;
|
||||
}
|
||||
if (property.type !== FormPropertyType.datetime) {
|
||||
delete property.allowClear;
|
||||
delete property.dateTimeType;
|
||||
}
|
||||
if (![FormPropertyType.javascript, FormPropertyType.markdown].includes(property.type)) {
|
||||
delete property.helpId;
|
||||
}
|
||||
if (property.type !== FormPropertyType.htmlSection) {
|
||||
delete property.htmlClassList;
|
||||
delete property.htmlContent;
|
||||
}
|
||||
for (const key of Object.keys(property)) {
|
||||
const val = property[key];
|
||||
if (isUndefinedOrNull(val) || isEmptyStr(val)) {
|
||||
delete property[key];
|
||||
}
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
export enum FormPropertyContainerType {
|
||||
field = 'field',
|
||||
row = 'row',
|
||||
|
||||
@ -40,32 +40,25 @@ The **Widget Editor** will be opened, pre-populated with the content of the defa
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Put the following JSON content inside the "Settings schema" tab of **Settings schema section**:
|
||||
- Import the following JSON content inside the "Settings form" tab by clicking on 'Import form from JSON' button:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"title": "AlarmTableSettings",
|
||||
"properties": {
|
||||
"alarmSeverityColorFunction": {
|
||||
"title": "Alarm severity color function: f(severity)",
|
||||
"type": "string",
|
||||
"default": "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green'; "
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"form": [
|
||||
{
|
||||
"key": "alarmSeverityColorFunction",
|
||||
"type": "javascript"
|
||||
}
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"id": "alarmSeverityColorFunction",
|
||||
"name": "Alarm severity color function: f(severity)",
|
||||
"type": "javascript",
|
||||
"default": "if (severity == 'CRITICAL') {\n return 'red';\n} else if (severity == 'MAJOR') {\n return 'orange';\n} else return 'green';",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Clear all 'form selector' fields in the "Widget settings" tab.
|
||||
|
||||
- Turn off 'Has basic mode' switch in the "Widget settings" tab.
|
||||
|
||||
- Put the following JavaScript code inside the "JavaScript" section:
|
||||
|
||||
```javascript
|
||||
|
||||
@ -40,35 +40,28 @@ The **Widget Editor** will open, pre-populated with default **Control** template
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Put the following JSON content inside the "Settings schema" tab of **Settings schema section**:
|
||||
- Import the following JSON content inside the "Settings form" tab by clicking on 'Import form from JSON' button:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"title": "Settings",
|
||||
"properties": {
|
||||
"oneWayElseTwoWay": {
|
||||
"title": "Is One Way Command",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"requestTimeout": {
|
||||
"title": "RPC request timeout",
|
||||
"type": "number",
|
||||
"default": 500
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"form": [
|
||||
"oneWayElseTwoWay",
|
||||
"requestTimeout"
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"id": "oneWayElseTwoWay",
|
||||
"name": "Is One Way Command",
|
||||
"type": "switch",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "requestTimeout",
|
||||
"name": "RPC request timeout",
|
||||
"type": "number",
|
||||
"default": 500
|
||||
}
|
||||
]
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Clear value of 'Settings form selector' in the "Widget settings" tab.
|
||||
|
||||
- Put the following JavaScript code inside the "JavaScript" section:
|
||||
|
||||
```javascript
|
||||
|
||||
@ -17,28 +17,23 @@ The **Widget Editor** will be opened pre-populated with the content of default *
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Put the following JSON content inside the "Settings schema" tab of **Settings schema section**:
|
||||
- Import the following JSON content inside the "Settings form" tab by clicking on 'Import form from JSON' button:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"title": "Settings",
|
||||
"properties": {
|
||||
"alertContent": {
|
||||
"title": "Alert content",
|
||||
"type": "string",
|
||||
"default": "Content derived from alertContent property of widget settings."
|
||||
}
|
||||
}
|
||||
},
|
||||
"form": [
|
||||
"alertContent"
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"id": "alertContent",
|
||||
"name": "Alert content",
|
||||
"type": "text",
|
||||
"default": "Content derived from alertContent property of widget settings.",
|
||||
"fieldClass": "flex"
|
||||
}
|
||||
]
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
- Clear value of 'Settings form selector' in the "Widget settings" tab.
|
||||
|
||||
- Put the following JavaScript code inside the "JavaScript" section:
|
||||
|
||||
```javascript
|
||||
|
||||
@ -10,18 +10,20 @@ Each widget function should be defined as a property of the **self** variable.
|
||||
|
||||
In order to implement a new widget, the following JavaScript functions should be defined *(Note: each function is optional and can be implemented according to widget specific behaviour):*
|
||||
|
||||
|{:auto} **Function** | **Description** |
|
||||
|------------------------------------|----------------------------------------------------------------------------------------|
|
||||
| ``` onInit() ``` | The first function which is called when widget is ready for initialization. Should be used to prepare widget DOM, process widget settings and initial subscription information. |
|
||||
| ``` onDataUpdated() ``` | Called when the new data is available from the widget subscription. Latest data can be accessed from the <span trigger-style="fontSize: 16px;" trigger-text="<b>defaultSubscription</b>" tb-help-popup="widget/editor/widget_js_subscription_object"></span> object of widget context (**ctx**). |
|
||||
| ``` onResize() ``` | Called when widget container is resized. Latest width and height can be obtained from widget context (**ctx**). |
|
||||
| ``` onEditModeChanged() ``` | Called when dashboard editing mode is changed. Latest mode is handled by isEdit property of **ctx**. |
|
||||
| ``` onMobileModeChanged() ``` | Called when dashboard view width crosses mobile breakpoint. Latest state is handled by isMobile property of **ctx**. |
|
||||
| ``` onDestroy() ``` | Called when widget element is destroyed. Should be used to cleanup all resources if necessary. |
|
||||
| ``` getSettingsSchema() ``` | Optional function returning widget settings schema json as alternative to **Settings schema** of settings section. |
|
||||
| ``` getDataKeySettingsSchema() ``` | Optional function returning particular data key settings schema json as alternative to **Data key settings schema** tab of settings section. |
|
||||
| ``` typeParameters() ``` | Returns [WidgetTypeParameters{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L151) object describing widget datasource parameters. See <span trigger-style="fontSize: 16px;" trigger-text="<b>Type parameters object</b>" tb-help-popup="widget/editor/widget_js_type_parameters_object"></span> | |
|
||||
| ``` actionSources() ``` | Returns map describing available widget action sources ([WidgetActionSource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L121)) used to define user actions. See <span trigger-style="fontSize: 16px;" trigger-text="<b>Action sources object</b>" tb-help-popup="widget/editor/widget_js_action_sources_object"></span> |
|
||||
| {:auto} **Function** | **Description** |
|
||||
|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ``` onInit() ``` | The first function which is called when widget is ready for initialization. Should be used to prepare widget DOM, process widget settings and initial subscription information. |
|
||||
| ``` onDataUpdated() ``` | Called when the new data is available from the widget subscription. Latest data can be accessed from the <span trigger-style="fontSize: 16px;" trigger-text="<b>defaultSubscription</b>" tb-help-popup="widget/editor/widget_js_subscription_object"></span> object of widget context (**ctx**). |
|
||||
| ``` onResize() ``` | Called when widget container is resized. Latest width and height can be obtained from widget context (**ctx**). |
|
||||
| ``` onEditModeChanged() ``` | Called when dashboard editing mode is changed. Latest mode is handled by isEdit property of **ctx**. |
|
||||
| ``` onMobileModeChanged() ``` | Called when dashboard view width crosses mobile breakpoint. Latest state is handled by isMobile property of **ctx**. |
|
||||
| ``` onDestroy() ``` | Called when widget element is destroyed. Should be used to cleanup all resources if necessary. |
|
||||
| ``` getSettingsForm() ``` | Optional function returning widget settings form array as alternative to **Settings form** tab of settings section. |
|
||||
| ``` getDataKeySettingsForm() ``` | Optional function returning particular data key settings form array as alternative to **Data key settings form** tab of settings section. |
|
||||
| ``` typeParameters() ``` | Returns [WidgetTypeParameters{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L151) object describing widget datasource parameters. See <span trigger-style="fontSize: 16px;" trigger-text="<b>Type parameters object</b>" tb-help-popup="widget/editor/widget_js_type_parameters_object"></span> | |
|
||||
| ``` actionSources() ``` | Returns map describing available widget action sources ([WidgetActionSource{:target="_blank"}](https://github.com/thingsboard/thingsboard/blob/2627fe51d491055d4140f16617ed543f7f5bd8f6/ui-ngx/src/app/shared/models/widget.models.ts#L121)) used to define user actions. See <span trigger-style="fontSize: 16px;" trigger-text="<b>Action sources object</b>" tb-help-popup="widget/editor/widget_js_action_sources_object"></span> |
|
||||
| ~~getSettingsSchema()~~ | **Deprecated**. Use getSettingsForm() function. |
|
||||
| ~~getDataKeySettingsSchema()~~ | **Deprecated**. Use getDataKeySettingsForm() function. |
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ For [Latest values{:target="_blank"}](${siteBaseUrl}/docs${docPlatformPrefix}/us
|
||||
label: 'Sin', // label of the dataKey. Used as display value (for ex. in the widget legend section)
|
||||
color: '#ffffff', // color of the key. Can be used by widget to set color of the key data (for ex. lines in line chart or segments in the pie chart).
|
||||
funcBody: "", // only applicable for datasource with type "function" and "function" key type. Defines body of the function to generate simulated data.
|
||||
settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section".
|
||||
settings: {} // dataKey specific settings with structure according to the defined Data key settings form.
|
||||
},
|
||||
//...
|
||||
]
|
||||
@ -72,7 +72,7 @@ For [Alarm widget{:target="_blank"}](${siteBaseUrl}/docs${docPlatformPrefix}/use
|
||||
type: 'alarm', // type of the dataKey. Only "alarm" in this case.
|
||||
label: 'Severity', // label of the dataKey. Used as display value (for ex. as a column title in the Alarms table)
|
||||
color: '#ffffff', // color of the key. Can be used by widget to set color of the key data.
|
||||
settings: {} // dataKey specific settings with structure according to the defined Data key settings json schema. See "Settings schema section".
|
||||
settings: {} // dataKey specific settings with structure according to the defined Data key settings form.
|
||||
},
|
||||
//...
|
||||
]
|
||||
|
||||
@ -1699,7 +1699,8 @@
|
||||
"clear-form-prompt": "Are you sure you want to remove all form properties?",
|
||||
"import-form": "Import form from JSON",
|
||||
"export-form": "Export form to JSON",
|
||||
"form-json-file": "Form JSON file",
|
||||
"json-file": "JSON file",
|
||||
"json-content": "JSON content",
|
||||
"invalid-form-json-file-error": "Unable to import form from JSON: Invalid form JSON data structure."
|
||||
},
|
||||
"asset-profile": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user