Commit 6131000c8c48751757bbb1601542057f16c482bd
1 parent
1702ba55
Direct access of core services from widget context. JavaScript editors code auto…
…completion and tooltips.
Showing
17 changed files
with
1487 additions
and
4 deletions
@@ -44,7 +44,8 @@ | @@ -44,7 +44,8 @@ | ||
44 | (ngModelChange)="onActionUpdated()" | 44 | (ngModelChange)="onActionUpdated()" |
45 | [fillHeight]="true" | 45 | [fillHeight]="true" |
46 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']" | 46 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']" |
47 | - [validationArgs]="[]"> | 47 | + [validationArgs]="[]" |
48 | + [editorCompleter]="customPrettyActionEditorCompleter"> | ||
48 | </tb-js-func> | 49 | </tb-js-func> |
49 | </div> | 50 | </div> |
50 | </div> | 51 | </div> |
@@ -35,6 +35,7 @@ import { Store } from '@ngrx/store'; | @@ -35,6 +35,7 @@ import { Store } from '@ngrx/store'; | ||
35 | import { AppState } from '@core/core.state'; | 35 | import { AppState } from '@core/core.state'; |
36 | import { combineLatest } from 'rxjs'; | 36 | import { combineLatest } from 'rxjs'; |
37 | import { CustomActionDescriptor } from '@shared/models/widget.models'; | 37 | import { CustomActionDescriptor } from '@shared/models/widget.models'; |
38 | +import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models'; | ||
38 | 39 | ||
39 | @Component({ | 40 | @Component({ |
40 | selector: 'tb-custom-action-pretty-editor', | 41 | selector: 'tb-custom-action-pretty-editor', |
@@ -63,6 +64,8 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements | @@ -63,6 +64,8 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements | ||
63 | @ViewChildren('rightPanel') | 64 | @ViewChildren('rightPanel') |
64 | rightPanelElmRef: QueryList<ElementRef<HTMLElement>>; | 65 | rightPanelElmRef: QueryList<ElementRef<HTMLElement>>; |
65 | 66 | ||
67 | + customPrettyActionEditorCompleter = CustomPrettyActionEditorCompleter; | ||
68 | + | ||
66 | private propagateChange = (_: any) => {}; | 69 | private propagateChange = (_: any) => {}; |
67 | 70 | ||
68 | constructor(protected store: Store<AppState>) { | 71 | constructor(protected store: Store<AppState>) { |
@@ -94,7 +94,8 @@ | @@ -94,7 +94,8 @@ | ||
94 | [(ngModel)]="action.customFunction" | 94 | [(ngModel)]="action.customFunction" |
95 | (ngModelChange)="notifyActionUpdated()" | 95 | (ngModelChange)="notifyActionUpdated()" |
96 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']" | 96 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']" |
97 | - [validationArgs]="[]"> | 97 | + [validationArgs]="[]" |
98 | + [editorCompleter]="customPrettyActionEditorCompleter"> | ||
98 | </tb-js-func> | 99 | </tb-js-func> |
99 | </mat-tab> | 100 | </mat-tab> |
100 | </mat-tab-group> | 101 | </mat-tab-group> |
@@ -36,6 +36,7 @@ import * as ace from 'ace-builds'; | @@ -36,6 +36,7 @@ import * as ace from 'ace-builds'; | ||
36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | 36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
37 | import { css_beautify, html_beautify } from 'js-beautify'; | 37 | import { css_beautify, html_beautify } from 'js-beautify'; |
38 | import { ResizeObserver } from '@juggle/resize-observer'; | 38 | import { ResizeObserver } from '@juggle/resize-observer'; |
39 | +import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models'; | ||
39 | 40 | ||
40 | @Component({ | 41 | @Component({ |
41 | selector: 'tb-custom-action-pretty-resources-tabs', | 42 | selector: 'tb-custom-action-pretty-resources-tabs', |
@@ -70,6 +71,8 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl | @@ -70,6 +71,8 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl | ||
70 | cssEditor: ace.Ace.Editor; | 71 | cssEditor: ace.Ace.Editor; |
71 | setValuesPending = false; | 72 | setValuesPending = false; |
72 | 73 | ||
74 | + customPrettyActionEditorCompleter = CustomPrettyActionEditorCompleter; | ||
75 | + | ||
73 | constructor(protected store: Store<AppState>, | 76 | constructor(protected store: Store<AppState>, |
74 | private translate: TranslateService, | 77 | private translate: TranslateService, |
75 | private raf: RafService) { | 78 | private raf: RafService) { |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { TbEditorCompleter, TbEditorCompletions } from '@shared/models/ace/completion.models'; | ||
18 | +import { widgetContextCompletions } from '@shared/models/ace/widget-completion.models'; | ||
19 | +import { entityIdHref, entityTypeHref, serviceCompletions } from '@shared/models/ace/service-completion.models'; | ||
20 | + | ||
21 | +const customActionCompletions: TbEditorCompletions = { | ||
22 | + ...{ | ||
23 | + $event: { | ||
24 | + meta: 'argument', | ||
25 | + type: 'Event', | ||
26 | + description: 'The DOM event that triggered this action.' | ||
27 | + }, | ||
28 | + widgetContext: widgetContextCompletions.ctx, | ||
29 | + entityId: { | ||
30 | + meta: 'argument', | ||
31 | + type: entityIdHref, | ||
32 | + description: 'Id of the entity for which the action was triggered.', | ||
33 | + children: { | ||
34 | + id: { | ||
35 | + meta: 'property', | ||
36 | + type: 'string', | ||
37 | + description: 'UUID Id string' | ||
38 | + }, | ||
39 | + entityType: { | ||
40 | + meta: 'property', | ||
41 | + type: entityTypeHref, | ||
42 | + description: 'Entity type' | ||
43 | + } | ||
44 | + } | ||
45 | + }, | ||
46 | + entityName: { | ||
47 | + meta: 'argument', | ||
48 | + type: 'string', | ||
49 | + description: 'Name of the entity for which the action was triggered.' | ||
50 | + }, | ||
51 | + additionalParams: { | ||
52 | + meta: 'argument', | ||
53 | + type: 'object', | ||
54 | + description: 'Optional object holding additional information.' | ||
55 | + }, | ||
56 | + entityLabel: { | ||
57 | + meta: 'argument', | ||
58 | + type: 'string', | ||
59 | + description: 'Label of the entity for which the action was triggered.' | ||
60 | + } | ||
61 | + }, | ||
62 | + ...serviceCompletions | ||
63 | +}; | ||
64 | + | ||
65 | +const customPrettyActionCompletions: TbEditorCompletions = { | ||
66 | + ...{ | ||
67 | + htmlTemplate: { | ||
68 | + meta: 'argument', | ||
69 | + type: 'string', | ||
70 | + description: 'HTML template used to render custom dialog.' | ||
71 | + } | ||
72 | + }, | ||
73 | + ...customActionCompletions | ||
74 | +} | ||
75 | + | ||
76 | +export const CustomActionEditorCompleter = new TbEditorCompleter(customActionCompletions); | ||
77 | +export const CustomPrettyActionEditorCompleter = new TbEditorCompleter(customPrettyActionCompletions); |
@@ -135,6 +135,7 @@ | @@ -135,6 +135,7 @@ | ||
135 | formControlName="customFunction" | 135 | formControlName="customFunction" |
136 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" | 136 | [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']" |
137 | [validationArgs]="[]" | 137 | [validationArgs]="[]" |
138 | + [editorCompleter]="customActionEditorCompleter" | ||
138 | ></tb-js-func> | 139 | ></tb-js-func> |
139 | </ng-template> | 140 | </ng-template> |
140 | <ng-template [ngSwitchCase]="widgetActionType.customPretty"> | 141 | <ng-template [ngSwitchCase]="widgetActionType.customPretty"> |
@@ -43,6 +43,7 @@ import { map, mergeMap, startWith, tap } from 'rxjs/operators'; | @@ -43,6 +43,7 @@ import { map, mergeMap, startWith, tap } from 'rxjs/operators'; | ||
43 | import { DashboardService } from '@core/http/dashboard.service'; | 43 | import { DashboardService } from '@core/http/dashboard.service'; |
44 | import { Dashboard } from '@shared/models/dashboard.models'; | 44 | import { Dashboard } from '@shared/models/dashboard.models'; |
45 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | 45 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
46 | +import { CustomActionEditorCompleter } from '@home/components/widget/action/custom-action.models'; | ||
46 | 47 | ||
47 | export interface WidgetActionDialogData { | 48 | export interface WidgetActionDialogData { |
48 | isAdd: boolean; | 49 | isAdd: boolean; |
@@ -76,6 +77,8 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia | @@ -76,6 +77,8 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia | ||
76 | targetDashboardStateSearchText = ''; | 77 | targetDashboardStateSearchText = ''; |
77 | selectedDashboardStateIds: Observable<Array<string>>; | 78 | selectedDashboardStateIds: Observable<Array<string>>; |
78 | 79 | ||
80 | + customActionEditorCompleter = CustomActionEditorCompleter; | ||
81 | + | ||
79 | submitted = false; | 82 | submitted = false; |
80 | 83 | ||
81 | constructor(protected store: Store<AppState>, | 84 | constructor(protected store: Store<AppState>, |
@@ -19,7 +19,7 @@ import { Inject, Injector, OnDestroy, OnInit } from '@angular/core'; | @@ -19,7 +19,7 @@ import { Inject, Injector, OnDestroy, OnInit } from '@angular/core'; | ||
19 | import { Store } from '@ngrx/store'; | 19 | import { Store } from '@ngrx/store'; |
20 | import { AppState } from '@core/core.state'; | 20 | import { AppState } from '@core/core.state'; |
21 | import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; | 21 | import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; |
22 | -import { HttpErrorResponse } from '@angular/common/http'; | 22 | +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; |
23 | import { RafService } from '@core/services/raf.service'; | 23 | import { RafService } from '@core/services/raf.service'; |
24 | import { | 24 | import { |
25 | NotificationHorizontalPosition, | 25 | NotificationHorizontalPosition, |
@@ -27,6 +27,19 @@ import { | @@ -27,6 +27,19 @@ import { | ||
27 | NotificationVerticalPosition | 27 | NotificationVerticalPosition |
28 | } from '@core/notification/notification.models'; | 28 | } from '@core/notification/notification.models'; |
29 | import { FormBuilder, Validators } from '@angular/forms'; | 29 | import { FormBuilder, Validators } from '@angular/forms'; |
30 | +import { DeviceService } from '@core/http/device.service'; | ||
31 | +import { AssetService } from '@core/http/asset.service'; | ||
32 | +import { EntityViewService } from '@core/http/entity-view.service'; | ||
33 | +import { CustomerService } from '@core/http/customer.service'; | ||
34 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
35 | +import { UserService } from '@core/http/user.service'; | ||
36 | +import { AttributeService } from '@core/http/attribute.service'; | ||
37 | +import { EntityRelationService } from '@core/http/entity-relation.service'; | ||
38 | +import { EntityService } from '@core/http/entity.service'; | ||
39 | +import { DialogService } from '@core/services/dialog.service'; | ||
40 | +import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service'; | ||
41 | +import { DatePipe } from '@angular/common'; | ||
42 | +import { TranslateService } from '@ngx-translate/core'; | ||
30 | 43 | ||
31 | export class DynamicWidgetComponent extends PageComponent implements IDynamicWidgetComponent, OnInit, OnDestroy { | 44 | export class DynamicWidgetComponent extends PageComponent implements IDynamicWidgetComponent, OnInit, OnDestroy { |
32 | 45 | ||
@@ -47,6 +60,21 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid | @@ -47,6 +60,21 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid | ||
47 | @Inject('errorMessages') public readonly errorMessages: string[]) { | 60 | @Inject('errorMessages') public readonly errorMessages: string[]) { |
48 | super(store); | 61 | super(store); |
49 | this.ctx.$injector = $injector; | 62 | this.ctx.$injector = $injector; |
63 | + this.ctx.deviceService = $injector.get(DeviceService); | ||
64 | + this.ctx.assetService = $injector.get(AssetService); | ||
65 | + this.ctx.entityViewService = $injector.get(EntityViewService); | ||
66 | + this.ctx.customerService = $injector.get(CustomerService); | ||
67 | + this.ctx.dashboardService = $injector.get(DashboardService); | ||
68 | + this.ctx.userService = $injector.get(UserService); | ||
69 | + this.ctx.attributeService = $injector.get(AttributeService); | ||
70 | + this.ctx.entityRelationService = $injector.get(EntityRelationService); | ||
71 | + this.ctx.entityService = $injector.get(EntityService); | ||
72 | + this.ctx.dialogs = $injector.get(DialogService); | ||
73 | + this.ctx.customDialog = $injector.get(CustomDialogService); | ||
74 | + this.ctx.date = $injector.get(DatePipe); | ||
75 | + this.ctx.translate = $injector.get(TranslateService); | ||
76 | + this.ctx.http = $injector.get(HttpClient); | ||
77 | + | ||
50 | this.ctx.$scope = this; | 78 | this.ctx.$scope = this; |
51 | if (this.ctx.defaultSubscription) { | 79 | if (this.ctx.defaultSubscription) { |
52 | this.executingRpcRequest = this.ctx.defaultSubscription.executingRpcRequest; | 80 | this.executingRpcRequest = this.ctx.defaultSubscription.executingRpcRequest; |
@@ -26,11 +26,19 @@ import { DatePipe } from '@angular/common'; | @@ -26,11 +26,19 @@ import { DatePipe } from '@angular/common'; | ||
26 | import { UtilsService } from '@core/services/utils.service'; | 26 | import { UtilsService } from '@core/services/utils.service'; |
27 | import { TranslateService } from '@ngx-translate/core'; | 27 | import { TranslateService } from '@ngx-translate/core'; |
28 | import { HttpClient } from '@angular/common/http'; | 28 | import { HttpClient } from '@angular/common/http'; |
29 | +import { EntityViewService } from '@core/http/entity-view.service'; | ||
30 | +import { CustomerService } from '@core/http/customer.service'; | ||
31 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
32 | +import { UserService } from '@core/http/user.service'; | ||
29 | 33 | ||
30 | export const ServicesMap = new Map<string, Type<any>>( | 34 | export const ServicesMap = new Map<string, Type<any>>( |
31 | [ | 35 | [ |
32 | ['deviceService', DeviceService], | 36 | ['deviceService', DeviceService], |
33 | ['assetService', AssetService], | 37 | ['assetService', AssetService], |
38 | + ['entityViewService', EntityViewService], | ||
39 | + ['customerService', CustomerService], | ||
40 | + ['dashboardService', DashboardService], | ||
41 | + ['userService', UserService], | ||
34 | ['attributeService', AttributeService], | 42 | ['attributeService', AttributeService], |
35 | ['entityRelationService', EntityRelationService], | 43 | ['entityRelationService', EntityRelationService], |
36 | ['entityService', EntityService], | 44 | ['entityService', EntityService], |
@@ -43,7 +43,7 @@ import { | @@ -43,7 +43,7 @@ import { | ||
43 | WidgetSubscriptionApi | 43 | WidgetSubscriptionApi |
44 | } from '@core/api/widget-api.models'; | 44 | } from '@core/api/widget-api.models'; |
45 | import { ChangeDetectorRef, ComponentFactory, Injector, NgZone, Type } from '@angular/core'; | 45 | import { ChangeDetectorRef, ComponentFactory, Injector, NgZone, Type } from '@angular/core'; |
46 | -import { HttpErrorResponse } from '@angular/common/http'; | 46 | +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; |
47 | import { RafService } from '@core/services/raf.service'; | 47 | import { RafService } from '@core/services/raf.service'; |
48 | import { WidgetTypeId } from '@shared/models/id/widget-type-id'; | 48 | import { WidgetTypeId } from '@shared/models/id/widget-type-id'; |
49 | import { TenantId } from '@shared/models/id/tenant-id'; | 49 | import { TenantId } from '@shared/models/id/tenant-id'; |
@@ -60,6 +60,19 @@ import { | @@ -60,6 +60,19 @@ import { | ||
60 | import { ActionNotificationShow } from '@core/notification/notification.actions'; | 60 | import { ActionNotificationShow } from '@core/notification/notification.actions'; |
61 | import { AuthUser } from '@shared/models/user.model'; | 61 | import { AuthUser } from '@shared/models/user.model'; |
62 | import { getCurrentAuthUser } from '@core/auth/auth.selectors'; | 62 | import { getCurrentAuthUser } from '@core/auth/auth.selectors'; |
63 | +import { DeviceService } from '@core/http/device.service'; | ||
64 | +import { AssetService } from '@core/http/asset.service'; | ||
65 | +import { EntityViewService } from '@core/http/entity-view.service'; | ||
66 | +import { CustomerService } from '@core/http/customer.service'; | ||
67 | +import { DashboardService } from '@core/http/dashboard.service'; | ||
68 | +import { UserService } from '@core/http/user.service'; | ||
69 | +import { AttributeService } from '@core/http/attribute.service'; | ||
70 | +import { EntityRelationService } from '@core/http/entity-relation.service'; | ||
71 | +import { EntityService } from '@core/http/entity.service'; | ||
72 | +import { DialogService } from '@core/services/dialog.service'; | ||
73 | +import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service'; | ||
74 | +import { DatePipe } from '@angular/common'; | ||
75 | +import { TranslateService } from '@ngx-translate/core'; | ||
63 | 76 | ||
64 | export interface IWidgetAction { | 77 | export interface IWidgetAction { |
65 | name: string; | 78 | name: string; |
@@ -126,6 +139,21 @@ export class WidgetContext { | @@ -126,6 +139,21 @@ export class WidgetContext { | ||
126 | } | 139 | } |
127 | } | 140 | } |
128 | 141 | ||
142 | + deviceService: DeviceService; | ||
143 | + assetService: AssetService; | ||
144 | + entityViewService: EntityViewService; | ||
145 | + customerService: CustomerService; | ||
146 | + dashboardService: DashboardService; | ||
147 | + userService: UserService; | ||
148 | + attributeService: AttributeService; | ||
149 | + entityRelationService: EntityRelationService; | ||
150 | + entityService: EntityService; | ||
151 | + dialogs: DialogService; | ||
152 | + customDialog: CustomDialogService; | ||
153 | + date: DatePipe; | ||
154 | + translate: TranslateService; | ||
155 | + http: HttpClient; | ||
156 | + | ||
129 | private changeDetectorValue: ChangeDetectorRef; | 157 | private changeDetectorValue: ChangeDetectorRef; |
130 | 158 | ||
131 | inited = false; | 159 | inited = false; |
@@ -47,6 +47,7 @@ import { | @@ -47,6 +47,7 @@ import { | ||
47 | import { Subscription } from 'rxjs'; | 47 | import { Subscription } from 'rxjs'; |
48 | import { ResizeObserver } from '@juggle/resize-observer'; | 48 | import { ResizeObserver } from '@juggle/resize-observer'; |
49 | import Timeout = NodeJS.Timeout; | 49 | import Timeout = NodeJS.Timeout; |
50 | +import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; | ||
50 | 51 | ||
51 | // @dynamic | 52 | // @dynamic |
52 | @Component({ | 53 | @Component({ |
@@ -319,6 +320,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe | @@ -319,6 +320,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe | ||
319 | this.jsEditor.on('change', () => { | 320 | this.jsEditor.on('change', () => { |
320 | this.cleanupJsErrors(); | 321 | this.cleanupJsErrors(); |
321 | }); | 322 | }); |
323 | + this.jsEditor.completers = [widgetEditorCompleter, ...(this.jsEditor.completers || [])]; | ||
322 | this.setAceEditorValues(); | 324 | this.setAceEditorValues(); |
323 | } | 325 | } |
324 | 326 |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { TbEditorCompleter, TbEditorCompletions } from '@shared/models/ace/completion.models'; | ||
18 | +import { widgetContextCompletions } from '@shared/models/ace/widget-completion.models'; | ||
19 | +import { serviceCompletions } from '@shared/models/ace/service-completion.models'; | ||
20 | + | ||
21 | +const widgetEditorCompletions: TbEditorCompletions = { | ||
22 | + ... {self: { | ||
23 | + description: 'Built-in variable <b>self</b> that is a reference to the widget instance', | ||
24 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L350">WidgetTypeInstance</a>', | ||
25 | + meta: 'object', | ||
26 | + children: { | ||
27 | + ...{ | ||
28 | + onInit: { | ||
29 | + description: 'The first function which is called when widget is ready for initialization.<br>Should be used to prepare widget DOM, process widget settings and initial subscription information.', | ||
30 | + meta: 'function' | ||
31 | + }, | ||
32 | + onDataUpdated: { | ||
33 | + description: 'Called when the new data is available from the widget subscription.<br>Latest data can be accessed from ' + | ||
34 | + 'the <code>defaultSubscription</code> property of <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">widget context (<code>ctx</code>)</a>.', | ||
35 | + meta: 'function' | ||
36 | + }, | ||
37 | + onResize: { | ||
38 | + description: 'Called when widget container is resized. Latest <code>width</code> and <code>height</code> can be obtained from <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">widget context (<code>ctx</code>)</a>.', | ||
39 | + meta: 'function' | ||
40 | + }, | ||
41 | + onEditModeChanged: { | ||
42 | + description: 'Called when dashboard editing mode is changed. Latest mode is handled by <code>isEdit</code> property of <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">widget context (<code>ctx</code>)</a>.', | ||
43 | + meta: 'function' | ||
44 | + }, | ||
45 | + onMobileModeChanged: { | ||
46 | + description: 'Called when dashboard view width crosses mobile breakpoint. Latest state is handled by <code>isMobile</code> property of <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">widget context (<code>ctx</code>)</a>.', | ||
47 | + meta: 'function' | ||
48 | + }, | ||
49 | + onDestroy: { | ||
50 | + description: 'Called when widget element is destroyed. Should be used to cleanup all resources if necessary.', | ||
51 | + meta: 'function' | ||
52 | + }, | ||
53 | + getSettingsSchema: { | ||
54 | + 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">Settings schema section</a>.', | ||
55 | + meta: 'function', | ||
56 | + return: { | ||
57 | + description: 'An widget settings schema json', | ||
58 | + type: 'object' | ||
59 | + } | ||
60 | + }, | ||
61 | + getDataKeySettingsSchema: { | ||
62 | + 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">Settings schema section</a>.', | ||
63 | + meta: 'function', | ||
64 | + return: { | ||
65 | + description: 'A particular data key settings schema json', | ||
66 | + type: 'object' | ||
67 | + } | ||
68 | + }, | ||
69 | + typeParameters: { | ||
70 | + description: 'Returns object describing widget datasource parameters.', | ||
71 | + meta: 'function', | ||
72 | + return: { | ||
73 | + description: 'An object describing widget datasource parameters.', | ||
74 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L146">WidgetTypeParameters</a>' | ||
75 | + } | ||
76 | + }, | ||
77 | + actionSources: { | ||
78 | + description: 'Returns map describing available widget action sources used to define user actions.', | ||
79 | + meta: 'function', | ||
80 | + return: { | ||
81 | + description: 'A map of action sources by action source id.', | ||
82 | + type: '{[actionSourceId: string]: <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L118">WidgetActionSource</a>}' | ||
83 | + } | ||
84 | + } | ||
85 | + }, | ||
86 | + ...widgetContextCompletions | ||
87 | + } | ||
88 | + }}, | ||
89 | + ...widgetContextCompletions, | ||
90 | + ...serviceCompletions | ||
91 | +}; | ||
92 | + | ||
93 | +export const widgetEditorCompleter = new TbEditorCompleter(widgetEditorCompletions); |
@@ -35,6 +35,8 @@ import { guid, isUndefined } from '@app/core/utils'; | @@ -35,6 +35,8 @@ import { guid, isUndefined } from '@app/core/utils'; | ||
35 | import { TranslateService } from '@ngx-translate/core'; | 35 | import { TranslateService } from '@ngx-translate/core'; |
36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | 36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
37 | import { ResizeObserver } from '@juggle/resize-observer'; | 37 | import { ResizeObserver } from '@juggle/resize-observer'; |
38 | +import { TbEditorCompleter } from '@shared/models/ace/completion.models'; | ||
39 | +import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; | ||
38 | 40 | ||
39 | @Component({ | 41 | @Component({ |
40 | selector: 'tb-js-func', | 42 | selector: 'tb-js-func', |
@@ -77,6 +79,8 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -77,6 +79,8 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
77 | 79 | ||
78 | @Input() fillHeight: boolean; | 80 | @Input() fillHeight: boolean; |
79 | 81 | ||
82 | + @Input() editorCompleter: TbEditorCompleter; | ||
83 | + | ||
80 | private noValidateValue: boolean; | 84 | private noValidateValue: boolean; |
81 | get noValidate(): boolean { | 85 | get noValidate(): boolean { |
82 | return this.noValidateValue; | 86 | return this.noValidateValue; |
@@ -153,6 +157,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -153,6 +157,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
153 | this.cleanupJsErrors(); | 157 | this.cleanupJsErrors(); |
154 | this.updateView(); | 158 | this.updateView(); |
155 | }); | 159 | }); |
160 | + if (this.editorCompleter) { | ||
161 | + this.jsEditor.completers = [this.editorCompleter, ...(this.jsEditor.completers || [])]; | ||
162 | + } | ||
156 | this.editorResize$ = new ResizeObserver(() => { | 163 | this.editorResize$ = new ResizeObserver(() => { |
157 | this.onAceEditorResize(); | 164 | this.onAceEditorResize(); |
158 | }); | 165 | }); |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import * as ace from 'ace-builds'; | ||
18 | + | ||
19 | +export type tbMetaType = 'object' | 'function' | 'service' | 'property' | 'argument'; | ||
20 | + | ||
21 | +export type TbEditorCompletions = {[name: string]: TbEditorCompletion}; | ||
22 | + | ||
23 | +export interface FunctionArgType { | ||
24 | + type?: string; | ||
25 | + description?: string; | ||
26 | +} | ||
27 | + | ||
28 | +export interface FunctionArg extends FunctionArgType { | ||
29 | + name: string; | ||
30 | + type?: string; | ||
31 | + description?: string; | ||
32 | + optional?: boolean; | ||
33 | +} | ||
34 | + | ||
35 | +export interface TbEditorCompletion { | ||
36 | + meta: tbMetaType; | ||
37 | + description?: string; | ||
38 | + type?: string; | ||
39 | + args?: FunctionArg[]; | ||
40 | + return?: FunctionArgType; | ||
41 | + children?: TbEditorCompletions; | ||
42 | +} | ||
43 | + | ||
44 | +interface TbEditorAceCompletion extends ace.Ace.Completion { | ||
45 | + isTbEditorAceCompletion: true; | ||
46 | + snippet: string; | ||
47 | + description?: string; | ||
48 | + type?: string; | ||
49 | + args?: FunctionArg[]; | ||
50 | + return?: FunctionArgType; | ||
51 | +} | ||
52 | + | ||
53 | +export class TbEditorCompleter implements ace.Ace.Completer { | ||
54 | + | ||
55 | + identifierRegexps: RegExp[] = [ | ||
56 | + /[a-zA-Z_0-9\$\-\u00A2-\u2000\u2070-\uFFFF.]/ | ||
57 | + ]; | ||
58 | + | ||
59 | + constructor(private editorCompletions: TbEditorCompletions) { | ||
60 | + } | ||
61 | + | ||
62 | + getCompletions(editor: ace.Ace.Editor, session: ace.Ace.EditSession, | ||
63 | + position: ace.Ace.Point, prefix: string, callback: ace.Ace.CompleterCallback): void { | ||
64 | + const result = this.prepareCompletions(prefix); | ||
65 | + if (result) { | ||
66 | + callback(null, result); | ||
67 | + } | ||
68 | + } | ||
69 | + | ||
70 | + private resolvePath(prefix: string): string[] { | ||
71 | + if (!prefix || !prefix.length) { | ||
72 | + return []; | ||
73 | + } | ||
74 | + let parts = prefix.split('.'); | ||
75 | + if (parts.length) { | ||
76 | + parts.pop(); | ||
77 | + } else { | ||
78 | + parts = []; | ||
79 | + } | ||
80 | + let currentCompletions = this.editorCompletions; | ||
81 | + for (const part of parts) { | ||
82 | + if (currentCompletions[part]) { | ||
83 | + currentCompletions = currentCompletions[part].children; | ||
84 | + if (!currentCompletions) { | ||
85 | + return null; | ||
86 | + } | ||
87 | + } else { | ||
88 | + return null; | ||
89 | + } | ||
90 | + } | ||
91 | + return parts; | ||
92 | + } | ||
93 | + | ||
94 | + private prepareCompletions(prefix: string): ace.Ace.Completion[] { | ||
95 | + const path = this.resolvePath(prefix); | ||
96 | + if (path !== null) { | ||
97 | + return this.toAceCompletionsList(this.editorCompletions, path); | ||
98 | + } else { | ||
99 | + return []; | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + private toAceCompletionsList(completions: TbEditorCompletions, parentPath: string[]): ace.Ace.Completion[] { | ||
104 | + const result: ace.Ace.Completion[] = []; | ||
105 | + let targetCompletions = completions; | ||
106 | + let parentPrefix = ''; | ||
107 | + if (parentPath.length) { | ||
108 | + parentPrefix = parentPath.join('.') + '.'; | ||
109 | + for (const path of parentPath) { | ||
110 | + targetCompletions = targetCompletions[path].children; | ||
111 | + } | ||
112 | + } | ||
113 | + for (const key of Object.keys(targetCompletions)) { | ||
114 | + result.push(this.toAceCompletion(key, targetCompletions[key], parentPrefix)); | ||
115 | + } | ||
116 | + return result; | ||
117 | + } | ||
118 | + | ||
119 | + private toAceCompletion(name: string, completion: TbEditorCompletion, parentPrefix: string): ace.Ace.Completion { | ||
120 | + const aceCompletion: TbEditorAceCompletion = { | ||
121 | + isTbEditorAceCompletion: true, | ||
122 | + snippet: parentPrefix + name, | ||
123 | + name, | ||
124 | + caption: parentPrefix + name, | ||
125 | + score: 100000, | ||
126 | + value: parentPrefix + name, | ||
127 | + meta: completion.meta, | ||
128 | + type: completion.type, | ||
129 | + description: completion.description, | ||
130 | + args: completion.args, | ||
131 | + return: completion.return | ||
132 | + }; | ||
133 | + return aceCompletion; | ||
134 | + } | ||
135 | + | ||
136 | + getDocTooltip(completion: TbEditorAceCompletion) { | ||
137 | + if (completion && completion.isTbEditorAceCompletion) { | ||
138 | + return { | ||
139 | + docHTML: this.createDocHTML(completion) | ||
140 | + }; | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + private createDocHTML(completion: TbEditorAceCompletion): string { | ||
145 | + let title = `<b>${completion.name}</b>`; | ||
146 | + if (completion.meta === 'function') { | ||
147 | + title += '('; | ||
148 | + if (completion.args) { | ||
149 | + const strArgs: string[] = []; | ||
150 | + for (const arg of completion.args) { | ||
151 | + let strArg = `${arg.name}`; | ||
152 | + if (arg.optional) { | ||
153 | + strArg += '?'; | ||
154 | + } | ||
155 | + if (arg.type) { | ||
156 | + strArg += `: ${arg.type}`; | ||
157 | + } | ||
158 | + strArgs.push(strArg); | ||
159 | + } | ||
160 | + title += strArgs.join(', '); | ||
161 | + } | ||
162 | + title += '): '; | ||
163 | + if (completion.return) { | ||
164 | + title += completion.return.type; | ||
165 | + } else { | ||
166 | + title += 'void'; | ||
167 | + } | ||
168 | + } else { | ||
169 | + title += `: ${completion.type ? completion.type : completion.meta}`; | ||
170 | + } | ||
171 | + let html = `<div class="tb-ace-doc-tooltip"><code class="title">${title}</code>`; | ||
172 | + if (completion.description) { | ||
173 | + html += `<hr><div>${completion.description}</div>`; | ||
174 | + } | ||
175 | + if (completion.args || completion.return) { | ||
176 | + let functionInfoBlock = '<div class="tb-function-info">'; | ||
177 | + if (completion.args) { | ||
178 | + functionInfoBlock += '<div class="tb-api-title">Parameters</div>' | ||
179 | + let argsTable = '<table class="tb-api-table"><tbody>'; | ||
180 | + const strArgs: string[] = []; | ||
181 | + for (const arg of completion.args) { | ||
182 | + let strArg = `<tr><td class="arg-name"><code>${arg.name}`; | ||
183 | + if (arg.optional) { | ||
184 | + strArg += ' (optional)'; | ||
185 | + } | ||
186 | + strArg += '</code></td><td>'; | ||
187 | + if (arg.type) { | ||
188 | + strArg += `<code>${arg.type}</code>` | ||
189 | + } | ||
190 | + strArg += '</td><td class="arg-description">'; | ||
191 | + if (arg.description) { | ||
192 | + strArg += `${arg.description}`; | ||
193 | + } | ||
194 | + strArg += '</td></tr>'; | ||
195 | + strArgs.push(strArg); | ||
196 | + } | ||
197 | + argsTable += strArgs.join('') + '</tbody></table>'; | ||
198 | + functionInfoBlock += argsTable; | ||
199 | + } | ||
200 | + if (completion.return) { | ||
201 | + let returnStr = '<div class="tb-api-title">Returns</div>'; | ||
202 | + returnStr += `<div class="tb-function-return"><code>${completion.return.type}</code>`; | ||
203 | + if (completion.return.description) { | ||
204 | + returnStr += `: ${completion.return.description}`; | ||
205 | + } | ||
206 | + returnStr += '</div>'; | ||
207 | + functionInfoBlock += returnStr; | ||
208 | + } | ||
209 | + functionInfoBlock += '</div>'; | ||
210 | + html += functionInfoBlock; | ||
211 | + } | ||
212 | + html += '</div>'; | ||
213 | + return html; | ||
214 | + } | ||
215 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { FunctionArg, FunctionArgType, TbEditorCompletions } from '@shared/models/ace/completion.models'; | ||
18 | + | ||
19 | +export const entityIdHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/id/entity-id.ts#L20">EntityId</a>'; | ||
20 | + | ||
21 | +export const entityTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L36">EntityType</a>'; | ||
22 | + | ||
23 | +export const pageDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/page/page-data.ts#L17">PageData</a>'; | ||
24 | + | ||
25 | +export const deviceInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L33">DeviceInfo</a>'; | ||
26 | + | ||
27 | +export const deviceHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L24">Device</a>'; | ||
28 | + | ||
29 | +export const deviceCredentialsHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L50">DeviceCredentials</a>'; | ||
30 | + | ||
31 | +export const pageLinkArg: FunctionArg = { | ||
32 | + name: 'pageLink', | ||
33 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/page/page-link.ts#L68">PageLink</a>', | ||
34 | + description: 'Page link object used to perform paginated request.' | ||
35 | +}; | ||
36 | + | ||
37 | +export const requestConfigArg: FunctionArg = { | ||
38 | + name: 'config', | ||
39 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/http-utils.ts#L21">RequestConfig</a>', | ||
40 | + description: 'HTTP request configuration.', | ||
41 | + optional: true | ||
42 | +}; | ||
43 | + | ||
44 | +export function observableReturnType(objectType: string): FunctionArgType { | ||
45 | + return { | ||
46 | + type: `Observable<${objectType}>`, | ||
47 | + description: `An <code>Observable</code> of <code>${objectType}</code> object.` | ||
48 | + }; | ||
49 | +} | ||
50 | + | ||
51 | +export function observableVoid(): FunctionArgType { | ||
52 | + return { | ||
53 | + type: `Observable<void>`, | ||
54 | + description: `An <code>Observable</code>.` | ||
55 | + }; | ||
56 | +} | ||
57 | + | ||
58 | +export function observableArrayReturnType(objectType: string): FunctionArgType { | ||
59 | + return { | ||
60 | + type: `Observable<Array<${objectType}>>`, | ||
61 | + description: `An <code>Observable</code> of array of <code>${objectType}</code> objects.` | ||
62 | + }; | ||
63 | +} | ||
64 | + | ||
65 | +export function observablePageDataReturnType(objectType: string): FunctionArgType { | ||
66 | + return { | ||
67 | + type: `Observable<${pageDataHref}<${objectType}>>`, | ||
68 | + description: `An <code>Observable</code> of page result as a <code>${pageDataHref}</code> holding array of <code>${objectType}</code> objects.` | ||
69 | + }; | ||
70 | +} | ||
71 | + | ||
72 | +export const serviceCompletions: TbEditorCompletions = { | ||
73 | + deviceService: { | ||
74 | + description: 'Device Service API<br>' + | ||
75 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/device.service.ts#L37">DeviceService</a> for API reference.', | ||
76 | + meta: 'service', | ||
77 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/device.service.ts#L37">DeviceService</a>', | ||
78 | + children: { | ||
79 | + getTenantDeviceInfos: { | ||
80 | + description: 'Get tenant devices', | ||
81 | + meta: 'function', | ||
82 | + args: [ | ||
83 | + pageLinkArg, | ||
84 | + { name: 'type', type: 'string', optional: true, description: 'Device type'}, | ||
85 | + requestConfigArg | ||
86 | + ], | ||
87 | + return: observablePageDataReturnType(deviceInfoHref) | ||
88 | + }, | ||
89 | + getCustomerDeviceInfos: { | ||
90 | + description: 'Get customer devices', | ||
91 | + meta: 'function', | ||
92 | + args: [ | ||
93 | + { name: 'customerId', type: 'string', description: 'Id of the customer'}, | ||
94 | + pageLinkArg, | ||
95 | + { name: 'type', type: 'string', optional: true, description: 'Device type'}, | ||
96 | + requestConfigArg | ||
97 | + ], | ||
98 | + return: observablePageDataReturnType(deviceInfoHref) | ||
99 | + }, | ||
100 | + getDevice: { | ||
101 | + description: 'Get device by id', | ||
102 | + meta: 'function', | ||
103 | + args: [ | ||
104 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
105 | + requestConfigArg | ||
106 | + ], | ||
107 | + return: observableReturnType(deviceHref) | ||
108 | + }, | ||
109 | + getDevices: { | ||
110 | + description: 'Get devices by ids', | ||
111 | + meta: 'function', | ||
112 | + args: [ | ||
113 | + { name: 'deviceIds', type: 'Array<string>', description: 'List of device ids'}, | ||
114 | + requestConfigArg | ||
115 | + ], | ||
116 | + return: observableArrayReturnType(deviceHref) | ||
117 | + }, | ||
118 | + getDeviceInfo: { | ||
119 | + description: 'Get device info by id', | ||
120 | + meta: 'function', | ||
121 | + args: [ | ||
122 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
123 | + requestConfigArg | ||
124 | + ], | ||
125 | + return: observableReturnType(deviceInfoHref) | ||
126 | + }, | ||
127 | + saveDevice: { | ||
128 | + description: 'Save device', | ||
129 | + meta: 'function', | ||
130 | + args: [ | ||
131 | + { name: 'device', type: deviceHref, description: 'Device object to save'}, | ||
132 | + requestConfigArg | ||
133 | + ], | ||
134 | + return: observableReturnType(deviceHref) | ||
135 | + }, | ||
136 | + deleteDevice: { | ||
137 | + description: 'Delete device by id', | ||
138 | + meta: 'function', | ||
139 | + args: [ | ||
140 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
141 | + requestConfigArg | ||
142 | + ], | ||
143 | + return: observableVoid() | ||
144 | + }, | ||
145 | + getDeviceTypes: { | ||
146 | + description: 'Get all available devices types', | ||
147 | + meta: 'function', | ||
148 | + args: [ | ||
149 | + requestConfigArg | ||
150 | + ], | ||
151 | + return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295">EntitySubtype</a>') | ||
152 | + }, | ||
153 | + getDeviceCredentials: { | ||
154 | + description: 'Get device credentials by device id', | ||
155 | + meta: 'function', | ||
156 | + args: [ | ||
157 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
158 | + { name: 'sync', type: 'boolean', description: 'Whether to execute HTTP request synchronously (false by default)', optional: true}, | ||
159 | + requestConfigArg | ||
160 | + ], | ||
161 | + return: observableReturnType(deviceCredentialsHref) | ||
162 | + }, | ||
163 | + saveDeviceCredentials: { | ||
164 | + description: 'Save device credentials', | ||
165 | + meta: 'function', | ||
166 | + args: [ | ||
167 | + { name: 'deviceCredentials', type: deviceCredentialsHref, description: 'Device credentials object to save'}, | ||
168 | + requestConfigArg | ||
169 | + ], | ||
170 | + return: observableReturnType(deviceCredentialsHref) | ||
171 | + }, | ||
172 | + makeDevicePublic: { | ||
173 | + description: 'Make device public (available from public dashboard)', | ||
174 | + meta: 'function', | ||
175 | + args: [ | ||
176 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
177 | + requestConfigArg | ||
178 | + ], | ||
179 | + return: observableReturnType(deviceHref) | ||
180 | + }, | ||
181 | + assignDeviceToCustomer: { | ||
182 | + description: 'Assign device to specific customer', | ||
183 | + meta: 'function', | ||
184 | + args: [ | ||
185 | + { name: 'customerId', type: 'string', description: 'Id of the customer'}, | ||
186 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
187 | + requestConfigArg | ||
188 | + ], | ||
189 | + return: observableReturnType(deviceHref) | ||
190 | + }, | ||
191 | + unassignDeviceFromCustomer: { | ||
192 | + description: 'Unassign device from any customer', | ||
193 | + meta: 'function', | ||
194 | + args: [ | ||
195 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
196 | + requestConfigArg | ||
197 | + ], | ||
198 | + return: observableVoid() | ||
199 | + }, | ||
200 | + sendOneWayRpcCommand: { | ||
201 | + description: 'Send one way (without response) RPC command to the device.', | ||
202 | + meta: 'function', | ||
203 | + args: [ | ||
204 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
205 | + { name: 'requestBody', type: 'object', description: 'Request body to be sent to device'}, | ||
206 | + requestConfigArg | ||
207 | + ], | ||
208 | + return: { | ||
209 | + type: `Observable<any>`, | ||
210 | + description: `A command execution <code>Observable</code>.` | ||
211 | + } | ||
212 | + }, | ||
213 | + sendTwoWayRpcCommand: { | ||
214 | + description: 'Sends two way (with response) RPC command to the device.', | ||
215 | + meta: 'function', | ||
216 | + args: [ | ||
217 | + { name: 'deviceId', type: 'string', description: 'Id of the device'}, | ||
218 | + { name: 'requestBody', type: 'object', description: 'Request body to be sent to device'}, | ||
219 | + requestConfigArg | ||
220 | + ], | ||
221 | + return: { | ||
222 | + type: `Observable<any>`, | ||
223 | + description: `A command execution <code>Observable</code> of response body.` | ||
224 | + } | ||
225 | + }, | ||
226 | + findByQuery: { | ||
227 | + description: 'Find devices by search query', | ||
228 | + meta: 'function', | ||
229 | + args: [ | ||
230 | + { name: 'query', type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L57">DeviceSearchQuery</a>', | ||
231 | + description: 'Device search query object'}, | ||
232 | + requestConfigArg | ||
233 | + ], | ||
234 | + return: observableArrayReturnType(deviceHref) | ||
235 | + }, | ||
236 | + findByName: { | ||
237 | + description: 'Find device by name', | ||
238 | + meta: 'function', | ||
239 | + args: [ | ||
240 | + { name: 'deviceName', type: 'string', | ||
241 | + description: 'Search device name'}, | ||
242 | + requestConfigArg | ||
243 | + ], | ||
244 | + return: observableReturnType(deviceHref) | ||
245 | + }, | ||
246 | + claimDevice: { | ||
247 | + description: 'Send claim device request', | ||
248 | + meta: 'function', | ||
249 | + args: [ | ||
250 | + { name: 'deviceName', type: 'string', | ||
251 | + description: 'Claiming device name'}, | ||
252 | + requestConfigArg | ||
253 | + ], | ||
254 | + return: observableReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L71">ClaimResult</a>') | ||
255 | + }, | ||
256 | + unclaimDevice: { | ||
257 | + description: 'Send un-claim device request', | ||
258 | + meta: 'function', | ||
259 | + args: [ | ||
260 | + { name: 'deviceName', type: 'string', | ||
261 | + description: 'Device name to un-claim'}, | ||
262 | + requestConfigArg | ||
263 | + ], | ||
264 | + return: observableVoid() | ||
265 | + } | ||
266 | + } | ||
267 | + }, | ||
268 | + assetService: { | ||
269 | + description: 'Asset Service API<br>' + | ||
270 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/asset.service.ts#L29">AssetService</a> for API reference.', | ||
271 | + meta: 'service', | ||
272 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/asset.service.ts#L29">AssetService</a>' | ||
273 | + }, | ||
274 | + entityViewService: { | ||
275 | + description: 'EntityView Service API<br>' + | ||
276 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-view.service.ts#L29">EntityViewService</a> for API reference.', | ||
277 | + meta: 'service', | ||
278 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-view.service.ts#L29">EntityViewService</a>' | ||
279 | + }, | ||
280 | + customerService: { | ||
281 | + description: 'Customer Service API<br>' + | ||
282 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/customer.service.ts#L28">CustomerService</a> for API reference.', | ||
283 | + meta: 'service', | ||
284 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/customer.service.ts#L28">CustomerService</a>' | ||
285 | + }, | ||
286 | + dashboardService: { | ||
287 | + description: 'Dashboard Service API<br>' + | ||
288 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/dashboard.service.ts#L32">DashboardService</a> for API reference.', | ||
289 | + meta: 'service', | ||
290 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/dashboard.service.ts#L32">DashboardService</a>' | ||
291 | + }, | ||
292 | + userService: { | ||
293 | + description: 'User Service API<br>' + | ||
294 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/user.service.ts#L29">UserService</a> for API reference.', | ||
295 | + meta: 'service', | ||
296 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/user.service.ts#L29">UserService</a>' | ||
297 | + }, | ||
298 | + attributeService: { | ||
299 | + description: 'Attribute Service API<br>' + | ||
300 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/attribute.service.ts#L28">AttributeService</a> for API reference.', | ||
301 | + meta: 'service', | ||
302 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/attribute.service.ts#L28">AttributeService</a>' | ||
303 | + }, | ||
304 | + entityRelationService: { | ||
305 | + description: 'Entity Relation Service API<br>' + | ||
306 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-relation.service.ts#L27">EntityRelationService</a> for API reference.', | ||
307 | + meta: 'service', | ||
308 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-relation.service.ts#L27">EntityRelationService</a>' | ||
309 | + }, | ||
310 | + entityService: { | ||
311 | + description: 'Entity Service API<br>' + | ||
312 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity.service.ts#L64">EntityService</a> for API reference.', | ||
313 | + meta: 'service', | ||
314 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity.service.ts#L64">EntityService</a>' | ||
315 | + }, | ||
316 | + dialogs: { | ||
317 | + description: 'Dialogs Service API<br>' + | ||
318 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/services/dialog.service.ts#L39">DialogService</a> for API reference.', | ||
319 | + meta: 'service', | ||
320 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/services/dialog.service.ts#L39">DialogService</a>' | ||
321 | + }, | ||
322 | + customDialog: { | ||
323 | + description: 'Custom Dialog Service API<br>' + | ||
324 | + 'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts#L33">CustomDialogService</a> for API reference.', | ||
325 | + meta: 'service', | ||
326 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts#L33">CustomDialogService</a>' | ||
327 | + }, | ||
328 | + date: { | ||
329 | + description: 'Date Pipe<br>Formats a date value according to locale rules.<br>' + | ||
330 | + 'See <a href="https://angular.io/api/common/DatePipe">DatePipe</a> for API reference.', | ||
331 | + meta: 'service', | ||
332 | + type: '<a href="https://angular.io/api/common/DatePipe">DatePipe</a>' | ||
333 | + }, | ||
334 | + translate: { | ||
335 | + description: 'Translate Service API<br>' + | ||
336 | + 'See <a href="https://github.com/ngx-translate/core#translateservice">TranslateService</a> for API reference.', | ||
337 | + meta: 'service', | ||
338 | + type: '<a href="https://github.com/ngx-translate/core#translateservice">TranslateService</a>' | ||
339 | + }, | ||
340 | + http: { | ||
341 | + description: 'HTTP Client Service<br>' + | ||
342 | + 'See <a href="https://angular.io/api/common/http/HttpClient">HttpClient</a> for API reference.', | ||
343 | + meta: 'service', | ||
344 | + type: '<a href="https://angular.io/api/common/http/HttpClient">HttpClient</a>' | ||
345 | + } | ||
346 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models'; | ||
18 | +import { entityIdHref, serviceCompletions } from '@shared/models/ace/service-completion.models'; | ||
19 | + | ||
20 | +export const timewindowCompletion: TbEditorCompletion = { | ||
21 | + description: 'Timewindow configuration object', | ||
22 | + meta: 'property', | ||
23 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L80">Timewindow</a>', | ||
24 | + children: { | ||
25 | + displayValue: { | ||
26 | + description: 'Current timewindow display value.', | ||
27 | + meta: 'property', | ||
28 | + type: 'string' | ||
29 | + }, | ||
30 | + hideInterval: { | ||
31 | + description: 'Whether to hide interval selection in timewindow panel.', | ||
32 | + meta: 'property', | ||
33 | + type: 'boolean' | ||
34 | + }, | ||
35 | + hideAggregation: { | ||
36 | + description: 'Whether to hide aggregation selection in timewindow panel.', | ||
37 | + meta: 'property', | ||
38 | + type: 'boolean' | ||
39 | + }, | ||
40 | + hideAggInterval: { | ||
41 | + description: 'Whether to hide aggregation interval selection in timewindow panel.', | ||
42 | + meta: 'property', | ||
43 | + type: 'boolean' | ||
44 | + }, | ||
45 | + selectedTab: { | ||
46 | + description: 'Current selected timewindow type (0 - realtime, 1 - history).', | ||
47 | + meta: 'property', | ||
48 | + type: 'number' | ||
49 | + }, | ||
50 | + realtime: { | ||
51 | + description: 'Realtime timewindow configuration object.', | ||
52 | + meta: 'property', | ||
53 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L39">IntervalWindow</a>', | ||
54 | + children: { | ||
55 | + interval: { | ||
56 | + description: 'Timewindow aggregation interval in milliseconds', | ||
57 | + meta: 'property', | ||
58 | + type: 'number' | ||
59 | + }, | ||
60 | + timewindowMs: { | ||
61 | + description: 'Timewindow interval in milliseconds', | ||
62 | + meta: 'property', | ||
63 | + type: 'number' | ||
64 | + } | ||
65 | + } | ||
66 | + }, | ||
67 | + history: { | ||
68 | + description: 'History timewindow configuration object.', | ||
69 | + meta: 'property', | ||
70 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L49">HistoryWindow</a>', | ||
71 | + children: { | ||
72 | + historyType: { | ||
73 | + description: 'History timewindow type (0 - last interval, 1 - fixed)', | ||
74 | + meta: 'property', | ||
75 | + type: 'number' | ||
76 | + }, | ||
77 | + interval: { | ||
78 | + description: 'Timewindow aggregation interval in milliseconds', | ||
79 | + meta: 'property', | ||
80 | + type: 'number' | ||
81 | + }, | ||
82 | + timewindowMs: { | ||
83 | + description: 'Timewindow interval in milliseconds', | ||
84 | + meta: 'property', | ||
85 | + type: 'number' | ||
86 | + }, | ||
87 | + fixedTimewindow: { | ||
88 | + description: 'Fixed history timewindow configuration object', | ||
89 | + meta: 'property', | ||
90 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L44">FixedWindow</a>', | ||
91 | + children: { | ||
92 | + startTimeMs: { | ||
93 | + description: 'Timewindow start time in UTC milliseconds', | ||
94 | + meta: 'property', | ||
95 | + type: 'number' | ||
96 | + }, | ||
97 | + endTimeMs: { | ||
98 | + description: 'Timewindow end time in UTC milliseconds', | ||
99 | + meta: 'property', | ||
100 | + type: 'number' | ||
101 | + } | ||
102 | + } | ||
103 | + } | ||
104 | + } | ||
105 | + }, | ||
106 | + aggregation: { | ||
107 | + description: 'Timewindow aggregation configuration object.', | ||
108 | + meta: 'property', | ||
109 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L74">Aggregation</a>', | ||
110 | + children: { | ||
111 | + interval: { | ||
112 | + description: 'Aggregation interval in milliseconds', | ||
113 | + meta: 'property', | ||
114 | + type: 'number' | ||
115 | + }, | ||
116 | + type: { | ||
117 | + description: 'Aggregation type', | ||
118 | + meta: 'property', | ||
119 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L54">AggregationType</a>' | ||
120 | + }, | ||
121 | + limit: { | ||
122 | + description: 'Maximum allowed datapoints when aggregation is disabled (<code>AggregationType == \'NONE\'</code>)', | ||
123 | + meta: 'property', | ||
124 | + type: 'number' | ||
125 | + } | ||
126 | + } | ||
127 | + } | ||
128 | + } | ||
129 | +} | ||
130 | + | ||
131 | +export const widgetContextCompletions: TbEditorCompletions = { | ||
132 | + ctx: { | ||
133 | + description: 'A reference to widget context that has all necessary API<br>and data used by widget instance.', | ||
134 | + meta: 'object', | ||
135 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">WidgetContext</a>', | ||
136 | + children: { | ||
137 | + ...{ | ||
138 | + $container: { | ||
139 | + description: 'Container element of the widget.<br>Can be used to dynamically access or modify widget DOM using jQuery API.', | ||
140 | + meta: 'property', | ||
141 | + type: 'jQuery Object' | ||
142 | + }, | ||
143 | + $scope: { | ||
144 | + description: 'Reference to the current widget component.<br>Can be used to access/modify component properties when widget is built using Angular approach.', | ||
145 | + meta: 'property', | ||
146 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L274">IDynamicWidgetComponent</a>' | ||
147 | + }, | ||
148 | + width: { | ||
149 | + description: 'Current width of widget container in pixels.', | ||
150 | + meta: 'property', | ||
151 | + type: 'number' | ||
152 | + }, | ||
153 | + height: { | ||
154 | + description: 'Current height of widget container in pixels.', | ||
155 | + meta: 'property', | ||
156 | + type: 'number' | ||
157 | + }, | ||
158 | + isEdit: { | ||
159 | + description: 'Indicates whether the dashboard is in in the view or editing state.', | ||
160 | + meta: 'property', | ||
161 | + type: 'boolean' | ||
162 | + }, | ||
163 | + isMobile: { | ||
164 | + description: 'Indicates whether the dashboard view is less then 960px width (default mobile breakpoint).', | ||
165 | + meta: 'property', | ||
166 | + type: 'boolean' | ||
167 | + }, | ||
168 | + widgetConfig: { | ||
169 | + description: 'Common widget configuration containing properties such as <code>color</code> (text color), <code>backgroundColor</code> (widget background color), etc.', | ||
170 | + meta: 'property', | ||
171 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L341">WidgetConfig</a>', | ||
172 | + children: { | ||
173 | + title: { | ||
174 | + description: 'Widget title.', | ||
175 | + meta: 'property', | ||
176 | + type: 'string' | ||
177 | + }, | ||
178 | + titleIcon: { | ||
179 | + description: 'Widget title icon.', | ||
180 | + meta: 'property', | ||
181 | + type: 'string' | ||
182 | + }, | ||
183 | + showTitle: { | ||
184 | + description: 'Whether to show widget title.', | ||
185 | + meta: 'property', | ||
186 | + type: 'boolean' | ||
187 | + }, | ||
188 | + showTitleIcon: { | ||
189 | + description: 'Whether to show widget title icon.', | ||
190 | + meta: 'property', | ||
191 | + type: 'boolean' | ||
192 | + }, | ||
193 | + iconColor: { | ||
194 | + description: 'Widget title icon color.', | ||
195 | + meta: 'property', | ||
196 | + type: 'string' | ||
197 | + }, | ||
198 | + iconSize: { | ||
199 | + description: 'Widget title icon size.', | ||
200 | + meta: 'property', | ||
201 | + type: 'string' | ||
202 | + }, | ||
203 | + titleTooltip: { | ||
204 | + description: 'Widget title tooltip content.', | ||
205 | + meta: 'property', | ||
206 | + type: 'string' | ||
207 | + }, | ||
208 | + dropShadow: { | ||
209 | + description: 'Enable/disable widget card shadow.', | ||
210 | + meta: 'property', | ||
211 | + type: 'boolean' | ||
212 | + }, | ||
213 | + enableFullscreen: { | ||
214 | + description: 'Whether to enable fullscreen button on widget.', | ||
215 | + meta: 'property', | ||
216 | + type: 'boolean' | ||
217 | + }, | ||
218 | + useDashboardTimewindow: { | ||
219 | + description: 'Whether to use dashboard timewindow (applicable for timeseries widgets).', | ||
220 | + meta: 'property', | ||
221 | + type: 'boolean' | ||
222 | + }, | ||
223 | + displayTimewindow: { | ||
224 | + description: 'Whether to display timewindow (applicable for timeseries widgets).', | ||
225 | + meta: 'property', | ||
226 | + type: 'boolean' | ||
227 | + }, | ||
228 | + showLegend: { | ||
229 | + description: 'Whether to show legend.', | ||
230 | + meta: 'property', | ||
231 | + type: 'boolean' | ||
232 | + }, | ||
233 | + legendConfig: { | ||
234 | + description: 'Legend configuration.', | ||
235 | + meta: 'property', | ||
236 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L198">LegendConfig</a>', | ||
237 | + children: { | ||
238 | + position: { | ||
239 | + description: 'Legend position. Possible values: <code>\'top\', \'bottom\', \'left\', \'right\'</code>', | ||
240 | + meta: 'property', | ||
241 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L182">LegendPosition</a>', | ||
242 | + }, | ||
243 | + direction: { | ||
244 | + description: 'Legend direction. Possible values: <code>\'column\', \'row\'</code>', | ||
245 | + meta: 'property', | ||
246 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L170">LegendDirection</a>', | ||
247 | + }, | ||
248 | + showMin: { | ||
249 | + description: 'Whether to display aggregated min values.', | ||
250 | + meta: 'property', | ||
251 | + type: 'boolean', | ||
252 | + }, | ||
253 | + showMax: { | ||
254 | + description: 'Whether to display aggregated max values.', | ||
255 | + meta: 'property', | ||
256 | + type: 'boolean', | ||
257 | + }, | ||
258 | + showAvg: { | ||
259 | + description: 'Whether to display aggregated average values.', | ||
260 | + meta: 'property', | ||
261 | + type: 'boolean', | ||
262 | + }, | ||
263 | + showTotal: { | ||
264 | + description: 'Whether to display aggregated total values.', | ||
265 | + meta: 'property', | ||
266 | + type: 'boolean', | ||
267 | + } | ||
268 | + } | ||
269 | + }, | ||
270 | + timewindow: timewindowCompletion, | ||
271 | + mobileHeight: { | ||
272 | + description: 'Widget height in mobile mode.', | ||
273 | + meta: 'property', | ||
274 | + type: 'number' | ||
275 | + }, | ||
276 | + mobileOrder: { | ||
277 | + description: 'Widget order in mobile mode.', | ||
278 | + meta: 'property', | ||
279 | + type: 'number' | ||
280 | + }, | ||
281 | + color: { | ||
282 | + description: 'Widget text color.', | ||
283 | + meta: 'property', | ||
284 | + type: 'string' | ||
285 | + }, | ||
286 | + backgroundColor: { | ||
287 | + description: 'Widget background color.', | ||
288 | + meta: 'property', | ||
289 | + type: 'string' | ||
290 | + }, | ||
291 | + padding: { | ||
292 | + description: 'Widget card padding.', | ||
293 | + meta: 'property', | ||
294 | + type: 'string' | ||
295 | + }, | ||
296 | + margin: { | ||
297 | + description: 'Widget card margin.', | ||
298 | + meta: 'property', | ||
299 | + type: 'string' | ||
300 | + }, | ||
301 | + widgetStyle: { | ||
302 | + description: 'Widget element style object.', | ||
303 | + meta: 'property', | ||
304 | + type: 'object' | ||
305 | + }, | ||
306 | + titleStyle: { | ||
307 | + description: 'Widget title element style object.', | ||
308 | + meta: 'property', | ||
309 | + type: 'object' | ||
310 | + }, | ||
311 | + units: { | ||
312 | + description: 'Optional property defining units text of values displayed by widget. Useful for simple widgets like cards or gauges.', | ||
313 | + meta: 'property', | ||
314 | + type: 'string' | ||
315 | + }, | ||
316 | + decimals: { | ||
317 | + description: 'Optional property defining how many positions should be used to display decimal part of the value number.', | ||
318 | + meta: 'property', | ||
319 | + type: 'number' | ||
320 | + }, | ||
321 | + actions: { | ||
322 | + description: 'Map of configured widget actions.', | ||
323 | + meta: 'property', | ||
324 | + type: 'object' | ||
325 | + }, | ||
326 | + settings: { | ||
327 | + description: 'Object holding widget settings according to widget type.', | ||
328 | + meta: 'property', | ||
329 | + type: 'object' | ||
330 | + }, | ||
331 | + alarmSource: { | ||
332 | + description: 'Configured alarm source for alarm widget type.', | ||
333 | + meta: 'property', | ||
334 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250">Datasource</a>' | ||
335 | + }, | ||
336 | + alarmSearchStatus: { | ||
337 | + description: 'Configured default alarm search status for alarm widget type.', | ||
338 | + meta: 'property', | ||
339 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/alarm.models.ts#L41">AlarmSearchStatus</a>' | ||
340 | + }, | ||
341 | + alarmsPollingInterval: { | ||
342 | + description: 'Configured alarms polling interval for alarm widget type.', | ||
343 | + meta: 'property', | ||
344 | + type: 'number' | ||
345 | + }, | ||
346 | + alarmsMaxCountLoad: { | ||
347 | + description: 'Configured maximum alarms to load for alarm widget type.', | ||
348 | + meta: 'property', | ||
349 | + type: 'number' | ||
350 | + }, | ||
351 | + alarmsFetchSize: { | ||
352 | + description: 'Configured alarms page size used to load alarms.', | ||
353 | + meta: 'property', | ||
354 | + type: 'number' | ||
355 | + }, | ||
356 | + datasources: { | ||
357 | + description: 'Array of configured widget datasources.', | ||
358 | + meta: 'property', | ||
359 | + type: 'Array<<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250">Datasource</a>>' | ||
360 | + } | ||
361 | + } | ||
362 | + }, | ||
363 | + settings: { | ||
364 | + 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">settings json schema</a>', | ||
365 | + meta: 'property', | ||
366 | + type: 'object' | ||
367 | + }, | ||
368 | + units: { | ||
369 | + description: 'Optional property defining units text of values displayed by widget. Useful for simple widgets like cards or gauges.', | ||
370 | + meta: 'property', | ||
371 | + type: 'string' | ||
372 | + }, | ||
373 | + decimals: { | ||
374 | + description: 'Optional property defining how many positions should be used to display decimal part of the value number.', | ||
375 | + meta: 'property', | ||
376 | + type: 'number' | ||
377 | + }, | ||
378 | + hideTitlePanel: { | ||
379 | + description: 'Manages visibility of widget title panel. Useful for widget with custom title panels or different states.', | ||
380 | + meta: 'property', | ||
381 | + type: 'boolean' | ||
382 | + }, | ||
383 | + defaultSubscription: { | ||
384 | + description: 'Default widget subscription object contains all subscription information,<br>including current data, according to the widget type.', | ||
385 | + meta: 'property', | ||
386 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L220">IWidgetSubscription</a>' | ||
387 | + }, | ||
388 | + timewindowFunctions: { | ||
389 | + description: 'Object with timewindow functions used to manage widget data time frame. Can by used by Time-series or Alarm widgets.', | ||
390 | + meta: 'property', | ||
391 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L45">TimewindowFunctions</a>', | ||
392 | + children: { | ||
393 | + onUpdateTimewindow: { | ||
394 | + description: 'This function can be used to update current subscription time frame<br>to historical one identified by <code>startTimeMs</code> and <code>endTimeMs</code> arguments.', | ||
395 | + meta: 'function', | ||
396 | + args: [ | ||
397 | + { | ||
398 | + name: 'startTimeMs', | ||
399 | + description: 'Timewindow start time in UTC milliseconds', | ||
400 | + type: 'number' | ||
401 | + }, | ||
402 | + { | ||
403 | + name: 'endTimeMs', | ||
404 | + description: 'Timewindow end time in UTC milliseconds', | ||
405 | + type: 'number' | ||
406 | + } | ||
407 | + ] | ||
408 | + }, | ||
409 | + onResetTimewindow: { | ||
410 | + description: 'Resets subscription time frame to default defined by widget timewindow component<br>or dashboard timewindow depending on widget settings.', | ||
411 | + meta: 'function' | ||
412 | + } | ||
413 | + } | ||
414 | + }, | ||
415 | + controlApi: { | ||
416 | + description: 'Object that provides API functions for RPC (Control) widgets.', | ||
417 | + meta: 'property', | ||
418 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L58">RpcApi</a>', | ||
419 | + children: { | ||
420 | + sendOneWayCommand: { | ||
421 | + description: 'Sends one way (without response) RPC command to the device.', | ||
422 | + meta: 'function', | ||
423 | + args: [ | ||
424 | + { | ||
425 | + name: 'method', | ||
426 | + description: 'RPC method name', | ||
427 | + type: 'string' | ||
428 | + }, | ||
429 | + { | ||
430 | + name: 'params', | ||
431 | + description: 'RPC method params, custom json object', | ||
432 | + type: 'object', | ||
433 | + optional: true | ||
434 | + }, | ||
435 | + { | ||
436 | + name: 'timeout', | ||
437 | + description: 'Maximum delay in milliseconds to wait until response/acknowledgement is received.', | ||
438 | + type: 'number', | ||
439 | + optional: true | ||
440 | + } | ||
441 | + ], | ||
442 | + return: { | ||
443 | + description: 'A command execution Observable.', | ||
444 | + type: 'Observable<any>' | ||
445 | + } | ||
446 | + }, | ||
447 | + sendTwoWayCommand: { | ||
448 | + description: 'Sends two way (with response) RPC command to the device.', | ||
449 | + meta: 'function', | ||
450 | + args: [ | ||
451 | + { | ||
452 | + name: 'method', | ||
453 | + description: 'RPC method name', | ||
454 | + type: 'string' | ||
455 | + }, | ||
456 | + { | ||
457 | + name: 'params', | ||
458 | + description: 'RPC method params, custom json object', | ||
459 | + type: 'object', | ||
460 | + optional: true | ||
461 | + }, | ||
462 | + { | ||
463 | + name: 'timeout', | ||
464 | + description: 'Maximum delay in milliseconds to wait until response/acknowledgement is received.', | ||
465 | + type: 'number', | ||
466 | + optional: true | ||
467 | + } | ||
468 | + ], | ||
469 | + return: { | ||
470 | + description: 'A command execution Observable of response body.', | ||
471 | + type: 'Observable<any>' | ||
472 | + } | ||
473 | + } | ||
474 | + } | ||
475 | + }, | ||
476 | + actionsApi: { | ||
477 | + description: 'Set of API functions to work with user defined actions.', | ||
478 | + meta: 'property', | ||
479 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L67">WidgetActionsApi</a>', | ||
480 | + children: { | ||
481 | + getActionDescriptors: { | ||
482 | + description: 'Get list of action descriptors for provided <code>actionSourceId</code>.', | ||
483 | + meta: 'function', | ||
484 | + args: [ | ||
485 | + { | ||
486 | + name: 'actionSourceId', | ||
487 | + description: 'Id of widget action source', | ||
488 | + type: 'string' | ||
489 | + } | ||
490 | + ], | ||
491 | + return: { | ||
492 | + description: 'The list of action descriptors', | ||
493 | + type: 'Array<<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323">WidgetActionDescriptor</a>>' | ||
494 | + } | ||
495 | + }, | ||
496 | + handleWidgetAction: { | ||
497 | + description: 'Handle action produced by particular action source.', | ||
498 | + meta: 'function', | ||
499 | + args: [ | ||
500 | + { | ||
501 | + name: '$event', | ||
502 | + description: 'DOM event object associated with action.', | ||
503 | + type: 'Event' | ||
504 | + }, | ||
505 | + { | ||
506 | + name: 'descriptor', | ||
507 | + description: 'An action descriptor.', | ||
508 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323">WidgetActionDescriptor</a>' | ||
509 | + }, | ||
510 | + { | ||
511 | + name: 'entityId', | ||
512 | + description: 'Current entity id provided by action source if available.', | ||
513 | + type: entityIdHref, | ||
514 | + optional: true | ||
515 | + }, | ||
516 | + { | ||
517 | + name: 'entityName', | ||
518 | + description: 'Current entity name provided by action source if available.', | ||
519 | + type: 'string', | ||
520 | + optional: true | ||
521 | + } | ||
522 | + ] | ||
523 | + } | ||
524 | + } | ||
525 | + }, | ||
526 | + stateController: { | ||
527 | + description: 'Reference to Dashboard state controller, providing API to manage current dashboard state.', | ||
528 | + meta: 'property', | ||
529 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L121">IStateController</a>', | ||
530 | + children: { | ||
531 | + openState: { | ||
532 | + description: 'Navigate to new dashboard state.', | ||
533 | + meta: 'function', | ||
534 | + args: [ | ||
535 | + { | ||
536 | + name: 'id', | ||
537 | + description: 'An id of the target dashboard state.', | ||
538 | + type: 'string' | ||
539 | + }, | ||
540 | + { | ||
541 | + name: 'params', | ||
542 | + description: 'An object with state parameters to use by the new state.', | ||
543 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>', | ||
544 | + optional: true | ||
545 | + }, | ||
546 | + { | ||
547 | + name: 'openRightLayout', | ||
548 | + description: 'An optional boolean argument to force open right dashboard layout if present in mobile view mode.', | ||
549 | + type: 'boolean', | ||
550 | + optional: true | ||
551 | + } | ||
552 | + ] | ||
553 | + }, | ||
554 | + updateState: { | ||
555 | + description: 'Updates current dashboard state.', | ||
556 | + meta: 'function', | ||
557 | + args: [ | ||
558 | + { | ||
559 | + name: 'id', | ||
560 | + description: 'An optional id of the target dashboard state to replace current state id.', | ||
561 | + type: 'string', | ||
562 | + optional: true | ||
563 | + }, | ||
564 | + { | ||
565 | + name: 'params', | ||
566 | + description: 'An object with state parameters to update current state parameters.', | ||
567 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>', | ||
568 | + optional: true | ||
569 | + }, | ||
570 | + { | ||
571 | + name: 'openRightLayout', | ||
572 | + description: 'An optional boolean argument to force open right dashboard layout if present in mobile view mode.', | ||
573 | + type: 'boolean', | ||
574 | + optional: true | ||
575 | + } | ||
576 | + ] | ||
577 | + }, | ||
578 | + getStateId: { | ||
579 | + description: 'Get current dashboard state id.', | ||
580 | + meta: 'function', | ||
581 | + return: { | ||
582 | + description: 'current dashboard state id.', | ||
583 | + type: 'string' | ||
584 | + } | ||
585 | + }, | ||
586 | + getStateParams: { | ||
587 | + description: 'Get current dashboard state parameters.', | ||
588 | + meta: 'function', | ||
589 | + return: { | ||
590 | + description: 'current dashboard state parameters.', | ||
591 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>' | ||
592 | + } | ||
593 | + }, | ||
594 | + getStateParamsByStateId: { | ||
595 | + description: 'Get state parameters for particular dashboard state identified by <code>id</code>.', | ||
596 | + meta: 'function', | ||
597 | + args: [ | ||
598 | + { | ||
599 | + name: 'id', | ||
600 | + description: 'An id of the target dashboard state.', | ||
601 | + type: 'string' | ||
602 | + } | ||
603 | + ], | ||
604 | + return: { | ||
605 | + description: 'current dashboard state parameters.', | ||
606 | + type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>' | ||
607 | + } | ||
608 | + } | ||
609 | + } | ||
610 | + } | ||
611 | + }, | ||
612 | + ...serviceCompletions | ||
613 | + } | ||
614 | + } | ||
615 | +} |
@@ -416,6 +416,58 @@ mat-label { | @@ -416,6 +416,58 @@ mat-label { | ||
416 | } | 416 | } |
417 | } | 417 | } |
418 | 418 | ||
419 | +.tb-ace-doc-tooltip { | ||
420 | + code { | ||
421 | + color: #444; | ||
422 | + &.title { | ||
423 | + font-size: 14px; | ||
424 | + } | ||
425 | + } | ||
426 | + div.tb-function-info { | ||
427 | + font-size: 14px; | ||
428 | + } | ||
429 | + div.tb-function-return { | ||
430 | + font-size: 1rem; | ||
431 | + letter-spacing: 0.03rem; | ||
432 | + color: #444; | ||
433 | + code { | ||
434 | + font-size: 14px; | ||
435 | + letter-spacing: normal; | ||
436 | + } | ||
437 | + } | ||
438 | + div.tb-api-title { | ||
439 | + font-weight: bold; | ||
440 | + font-size: 16px; | ||
441 | + color: #6e6e6e; | ||
442 | + padding-top: 12px; | ||
443 | + padding-bottom: 12px; | ||
444 | + } | ||
445 | + table.tb-api-table { | ||
446 | + width: 100%; | ||
447 | + border-collapse: collapse; | ||
448 | + tr { | ||
449 | + border-bottom: 1px solid #a8a8a8; | ||
450 | + &:last-child { | ||
451 | + border-bottom: none; | ||
452 | + } | ||
453 | + td { | ||
454 | + font-size: 14px; | ||
455 | + line-height: 1.6rem; | ||
456 | + &:first-child { | ||
457 | + font-weight: 600; | ||
458 | + padding-left: 16px; | ||
459 | + width: 20%; | ||
460 | + } | ||
461 | + &.arg-description { | ||
462 | + font-size: 1rem; | ||
463 | + letter-spacing: .03rem; | ||
464 | + color: #444; | ||
465 | + } | ||
466 | + } | ||
467 | + } | ||
468 | + } | ||
469 | +} | ||
470 | + | ||
419 | .tb-default, .tb-dark { | 471 | .tb-default, .tb-dark { |
420 | 472 | ||
421 | /********************************* | 473 | /********************************* |