Commit 6131000c8c48751757bbb1601542057f16c482bd

Authored by Igor Kulikov
1 parent 1702ba55

Direct access of core services from widget context. JavaScript editors code auto…

…completion and tooltips.
... ... @@ -44,7 +44,8 @@
44 44 (ngModelChange)="onActionUpdated()"
45 45 [fillHeight]="true"
46 46 [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']"
47   - [validationArgs]="[]">
  47 + [validationArgs]="[]"
  48 + [editorCompleter]="customPrettyActionEditorCompleter">
48 49 </tb-js-func>
49 50 </div>
50 51 </div>
... ...
... ... @@ -35,6 +35,7 @@ import { Store } from '@ngrx/store';
35 35 import { AppState } from '@core/core.state';
36 36 import { combineLatest } from 'rxjs';
37 37 import { CustomActionDescriptor } from '@shared/models/widget.models';
  38 +import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models';
38 39
39 40 @Component({
40 41 selector: 'tb-custom-action-pretty-editor',
... ... @@ -63,6 +64,8 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements
63 64 @ViewChildren('rightPanel')
64 65 rightPanelElmRef: QueryList<ElementRef<HTMLElement>>;
65 66
  67 + customPrettyActionEditorCompleter = CustomPrettyActionEditorCompleter;
  68 +
66 69 private propagateChange = (_: any) => {};
67 70
68 71 constructor(protected store: Store<AppState>) {
... ...
... ... @@ -94,7 +94,8 @@
94 94 [(ngModel)]="action.customFunction"
95 95 (ngModelChange)="notifyActionUpdated()"
96 96 [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel']"
97   - [validationArgs]="[]">
  97 + [validationArgs]="[]"
  98 + [editorCompleter]="customPrettyActionEditorCompleter">
98 99 </tb-js-func>
99 100 </mat-tab>
100 101 </mat-tab-group>
... ...
... ... @@ -36,6 +36,7 @@ import * as ace from 'ace-builds';
36 36 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
37 37 import { css_beautify, html_beautify } from 'js-beautify';
38 38 import { ResizeObserver } from '@juggle/resize-observer';
  39 +import { CustomPrettyActionEditorCompleter } from '@home/components/widget/action/custom-action.models';
39 40
40 41 @Component({
41 42 selector: 'tb-custom-action-pretty-resources-tabs',
... ... @@ -70,6 +71,8 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
70 71 cssEditor: ace.Ace.Editor;
71 72 setValuesPending = false;
72 73
  74 + customPrettyActionEditorCompleter = CustomPrettyActionEditorCompleter;
  75 +
73 76 constructor(protected store: Store<AppState>,
74 77 private translate: TranslateService,
75 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 135 formControlName="customFunction"
136 136 [functionArgs]="['$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel']"
137 137 [validationArgs]="[]"
  138 + [editorCompleter]="customActionEditorCompleter"
138 139 ></tb-js-func>
139 140 </ng-template>
140 141 <ng-template [ngSwitchCase]="widgetActionType.customPretty">
... ...
... ... @@ -43,6 +43,7 @@ import { map, mergeMap, startWith, tap } from 'rxjs/operators';
43 43 import { DashboardService } from '@core/http/dashboard.service';
44 44 import { Dashboard } from '@shared/models/dashboard.models';
45 45 import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
  46 +import { CustomActionEditorCompleter } from '@home/components/widget/action/custom-action.models';
46 47
47 48 export interface WidgetActionDialogData {
48 49 isAdd: boolean;
... ... @@ -76,6 +77,8 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
76 77 targetDashboardStateSearchText = '';
77 78 selectedDashboardStateIds: Observable<Array<string>>;
78 79
  80 + customActionEditorCompleter = CustomActionEditorCompleter;
  81 +
79 82 submitted = false;
80 83
81 84 constructor(protected store: Store<AppState>,
... ...
... ... @@ -19,7 +19,7 @@ import { Inject, Injector, OnDestroy, OnInit } from '@angular/core';
19 19 import { Store } from '@ngrx/store';
20 20 import { AppState } from '@core/core.state';
21 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 23 import { RafService } from '@core/services/raf.service';
24 24 import {
25 25 NotificationHorizontalPosition,
... ... @@ -27,6 +27,19 @@ import {
27 27 NotificationVerticalPosition
28 28 } from '@core/notification/notification.models';
29 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 44 export class DynamicWidgetComponent extends PageComponent implements IDynamicWidgetComponent, OnInit, OnDestroy {
32 45
... ... @@ -47,6 +60,21 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid
47 60 @Inject('errorMessages') public readonly errorMessages: string[]) {
48 61 super(store);
49 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 78 this.ctx.$scope = this;
51 79 if (this.ctx.defaultSubscription) {
52 80 this.executingRpcRequest = this.ctx.defaultSubscription.executingRpcRequest;
... ...
... ... @@ -26,11 +26,19 @@ import { DatePipe } from '@angular/common';
26 26 import { UtilsService } from '@core/services/utils.service';
27 27 import { TranslateService } from '@ngx-translate/core';
28 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 34 export const ServicesMap = new Map<string, Type<any>>(
31 35 [
32 36 ['deviceService', DeviceService],
33 37 ['assetService', AssetService],
  38 + ['entityViewService', EntityViewService],
  39 + ['customerService', CustomerService],
  40 + ['dashboardService', DashboardService],
  41 + ['userService', UserService],
34 42 ['attributeService', AttributeService],
35 43 ['entityRelationService', EntityRelationService],
36 44 ['entityService', EntityService],
... ...
... ... @@ -43,7 +43,7 @@ import {
43 43 WidgetSubscriptionApi
44 44 } from '@core/api/widget-api.models';
45 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 47 import { RafService } from '@core/services/raf.service';
48 48 import { WidgetTypeId } from '@shared/models/id/widget-type-id';
49 49 import { TenantId } from '@shared/models/id/tenant-id';
... ... @@ -60,6 +60,19 @@ import {
60 60 import { ActionNotificationShow } from '@core/notification/notification.actions';
61 61 import { AuthUser } from '@shared/models/user.model';
62 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 77 export interface IWidgetAction {
65 78 name: string;
... ... @@ -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 157 private changeDetectorValue: ChangeDetectorRef;
130 158
131 159 inited = false;
... ...
... ... @@ -47,6 +47,7 @@ import {
47 47 import { Subscription } from 'rxjs';
48 48 import { ResizeObserver } from '@juggle/resize-observer';
49 49 import Timeout = NodeJS.Timeout;
  50 +import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models';
50 51
51 52 // @dynamic
52 53 @Component({
... ... @@ -319,6 +320,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
319 320 this.jsEditor.on('change', () => {
320 321 this.cleanupJsErrors();
321 322 });
  323 + this.jsEditor.completers = [widgetEditorCompleter, ...(this.jsEditor.completers || [])];
322 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 35 import { TranslateService } from '@ngx-translate/core';
36 36 import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
37 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 41 @Component({
40 42 selector: 'tb-js-func',
... ... @@ -77,6 +79,8 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
77 79
78 80 @Input() fillHeight: boolean;
79 81
  82 + @Input() editorCompleter: TbEditorCompleter;
  83 +
80 84 private noValidateValue: boolean;
81 85 get noValidate(): boolean {
82 86 return this.noValidateValue;
... ... @@ -153,6 +157,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
153 157 this.cleanupJsErrors();
154 158 this.updateView();
155 159 });
  160 + if (this.editorCompleter) {
  161 + this.jsEditor.completers = [this.editorCompleter, ...(this.jsEditor.completers || [])];
  162 + }
156 163 this.editorResize$ = new ResizeObserver(() => {
157 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&lt;${objectType}&gt;`,
  47 + description: `An <code>Observable</code> of <code>${objectType}</code> object.`
  48 + };
  49 +}
  50 +
  51 +export function observableVoid(): FunctionArgType {
  52 + return {
  53 + type: `Observable&lt;void&gt;`,
  54 + description: `An <code>Observable</code>.`
  55 + };
  56 +}
  57 +
  58 +export function observableArrayReturnType(objectType: string): FunctionArgType {
  59 + return {
  60 + type: `Observable&lt;Array&lt;${objectType}&gt;&gt;`,
  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&lt;${pageDataHref}&lt;${objectType}&gt;&gt;`,
  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&lt;any&gt;`,
  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&lt;any&gt;`,
  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&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250">Datasource</a>&gt;'
  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&lt;any&gt;'
  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&lt;any&gt;'
  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&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323">WidgetActionDescriptor</a>&gt;'
  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 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 471 .tb-default, .tb-dark {
420 472
421 473 /*********************************
... ...