Merge branch 'master' of github.com:thingsboard/thingsboard

This commit is contained in:
Andrii Shvaika 2024-09-25 18:10:06 +03:00
commit 5632b07009
40 changed files with 950 additions and 319 deletions

View File

@ -59,7 +59,7 @@
"flot.curvedlines": "https://github.com/MichaelZinsmaier/CurvedLines.git#master",
"font-awesome": "^4.7.0",
"html2canvas": "^1.4.1",
"jquery": "^3.6.3",
"jquery": "^3.7.1",
"jquery.terminal": "^2.35.3",
"js-beautify": "1.14.7",
"json-schema-defaults": "^0.4.0",
@ -127,7 +127,7 @@
"@types/flowjs": "^2.13.9",
"@types/jasmine": "~3.10.2",
"@types/jasminewd2": "^2.0.10",
"@types/jquery": "^3.5.16",
"@types/jquery": "^3.5.30",
"@types/js-beautify": "^1.13.3",
"@types/leaflet": "1.8.0",
"@types/leaflet-polylinedecorator": "1.6.4",

View File

@ -32,6 +32,7 @@ import { AuthService } from '@core/auth/auth.service';
import { svgIcons, svgIconsUrl } from '@shared/models/icon.models';
import { ActionSettingsChangeLanguage } from '@core/settings/settings.actions';
import { SETTINGS_KEY } from '@core/settings/settings.effects';
import { initCustomJQueryEvents } from '@shared/models/jquery-event.models';
@Component({
selector: 'tb-root',
@ -74,6 +75,8 @@ export class AppComponent implements OnInit {
this.setupTranslate();
this.setupAuth();
initCustomJQueryEvents();
}
setupTranslate() {

View File

@ -27,7 +27,7 @@
[class.center-vertical]="centerVertical"
[class.center-horizontal]="centerHorizontal"
(mousedown)="onDashboardMouseDown($event)"
(contextmenu)="openDashboardContextMenu($event)">
(tbcontextmenu)="openDashboardContextMenu($event)">
<div #dashboardMenuTrigger="matMenuTrigger" style="visibility: hidden; position: fixed"
[style.left]="dashboardMenuPosition.x"
[style.top]="dashboardMenuPosition.y"

View File

@ -58,6 +58,7 @@ import { WidgetComponentAction, WidgetComponentActionType } from '@home/componen
import { TbPopoverComponent } from '@shared/components/popover.component';
import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
import { coerceBoolean } from '@shared/decorators/coercion';
import { TbContextMenuEvent } from '@shared/models/jquery-event.models';
@Component({
selector: 'tb-dashboard',
@ -187,13 +188,13 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
dashboardMenuPosition = { x: '0px', y: '0px' };
dashboardContextMenuEvent: MouseEvent;
dashboardContextMenuEvent: TbContextMenuEvent;
@ViewChild('widgetMenuTrigger', {static: true}) widgetMenuTrigger: MatMenuTrigger;
widgetMenuPosition = { x: '0px', y: '0px' };
widgetContextMenuEvent: MouseEvent;
widgetContextMenuEvent: TbContextMenuEvent;
dashboardWidgets = new DashboardWidgets(this,
this.differs.find([]).create<Widget>((_, item) => item),
@ -395,7 +396,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
}
}
openDashboardContextMenu($event: MouseEvent) {
openDashboardContextMenu($event: TbContextMenuEvent) {
if (this.callbacks && this.callbacks.prepareDashboardContextMenu) {
const items = this.callbacks.prepareDashboardContextMenu($event);
if (items && items.length) {
@ -410,7 +411,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
}
}
private openWidgetContextMenu($event: MouseEvent, widget: DashboardWidget) {
private openWidgetContextMenu($event: TbContextMenuEvent, widget: DashboardWidget) {
if (this.callbacks && this.callbacks.prepareWidgetContextMenu) {
const items = this.callbacks.prepareWidgetContextMenu($event, widget.widget, widget.isReference);
if (items && items.length) {

View File

@ -16,20 +16,9 @@
-->
<ng-container [formGroup]="rpcParametersFormGroup">
<div fxFlex fxLayout="row">
<mat-form-field fxFlex="100">
<mat-label>{{ 'gateway.key' | translate }}</mat-label>
<input matInput name="value" formControlName="tag" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.key-required') | translate"
*ngIf="rpcParametersFormGroup.get('tag').hasError('required') &&
rpcParametersFormGroup.get('tag').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
<div class="tb-form-hint tb-primary-fill tb-flex no-padding-top hint-container">
{{ 'gateway.rpc.hint.modbus-response-reading' | translate }}<br>
{{ 'gateway.rpc.hint.modbus-writing-functions' | translate }}
</div>
<div fxFlex fxLayout="row" fxLayoutGap="10px">
<mat-form-field fxFlex="50" class="mat-block">
@ -45,21 +34,6 @@
</mat-select>
</mat-form-field>
</div>
<div fxFlex fxLayout="row">
<mat-form-field fxFlex="100" *ngIf="writeFunctionCodes.includes(rpcParametersFormGroup.get('functionCode').value)">
<mat-label>{{ 'gateway.rpc.value' | translate }}</mat-label>
<input matInput name="value" formControlName="value" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.value-required') | translate"
*ngIf="rpcParametersFormGroup.get('value').hasError('required') &&
rpcParametersFormGroup.get('value').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
<div fxFlex fxLayout="row" fxLayoutGap="10px">
<mat-form-field fxFlex="50">
<mat-label>{{ 'gateway.rpc.address' | translate }}</mat-label>
@ -88,5 +62,20 @@
/>
</mat-form-field>
</div>
<div *ngIf="writeFunctionCodes.includes(rpcParametersFormGroup.get('functionCode').value)" fxFlex fxLayout="row">
<mat-form-field fxFlex="100">
<mat-label>{{ 'gateway.rpc.value' | translate }}</mat-label>
<input matInput name="value" formControlName="value" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.value-required') | translate"
*ngIf="rpcParametersFormGroup.get('value').hasError('required') && rpcParametersFormGroup.get('value').touched"
class="tb-error"
>
warning
</mat-icon>
</mat-form-field>
</div>
</ng-container>

View File

@ -0,0 +1,20 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.hint-container {
margin-bottom: 12px;
}
}

View File

@ -39,13 +39,14 @@ import {
ModbusEditableDataTypes,
ModbusFunctionCodeTranslationsMap,
ModbusObjectCountByDataType,
ModbusValue,
noLeadTrailSpacesRegex,
RPCTemplateConfigModbus,
} from '@home/components/widget/lib/gateway/gateway-widget.models';
@Component({
selector: 'tb-modbus-rpc-parameters',
templateUrl: './modbus-rpc-parameters.component.html',
styleUrls: ['./modbus-rpc-parameters.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
@ -80,14 +81,13 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid
private readonly readFunctionCodes = [1, 2, 3, 4];
private readonly bitsFunctionCodes = [...this.readFunctionCodes, ...this.writeFunctionCodes];
private onChange: (value: ModbusValue) => void;
private onChange: (value: RPCTemplateConfigModbus) => void;
private onTouched: () => void;
private destroy$ = new Subject<void>();
constructor(private fb: FormBuilder) {
this.rpcParametersFormGroup = this.fb.group({
tag: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
type: [ModbusDataType.BYTES, [Validators.required]],
functionCode: [this.defaultFunctionCodes[0], [Validators.required]],
value: [{value: '', disabled: true}, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
@ -106,7 +106,7 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid
this.destroy$.complete();
}
registerOnChange(fn: (value: ModbusValue) => void): void {
registerOnChange(fn: (value: RPCTemplateConfigModbus) => void): void {
this.onChange = fn;
}
@ -120,7 +120,7 @@ export class ModbusRpcParametersComponent implements ControlValueAccessor, Valid
};
}
writeValue(value: ModbusValue): void {
writeValue(value: RPCTemplateConfigModbus): void {
this.rpcParametersFormGroup.patchValue(value, {emitEvent: false});
}

View File

@ -0,0 +1,48 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ng-container [formGroup]="rpcParametersFormGroup">
<mat-form-field>
<mat-label>{{ 'gateway.rpc.method-name' | translate }}</mat-label>
<input matInput formControlName="methodFilter"
placeholder="echo"/>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'gateway.rpc.requestTopicExpression' | translate }}</mat-label>
<input matInput formControlName="requestTopicExpression"
placeholder="sensor/${deviceName}/request/${methodName}/${requestId}"/>
</mat-form-field>
<mat-slide-toggle class="margin" (click)="$event.stopPropagation()" formControlName="withResponse">
{{ 'gateway.rpc.withResponse' | translate }}
</mat-slide-toggle>
<mat-form-field *ngIf="rpcParametersFormGroup.get('withResponse')?.value">
<mat-label>{{ 'gateway.rpc.responseTopicExpression' | translate }}</mat-label>
<input matInput formControlName="responseTopicExpression"
placeholder="sensor/${deviceName}/response/${methodName}/${requestId}"/>
</mat-form-field>
<mat-form-field *ngIf="rpcParametersFormGroup.get('withResponse')?.value">
<mat-label>{{ 'gateway.rpc.responseTimeout' | translate }}</mat-label>
<input matInput formControlName="responseTimeout" type="number"
placeholder="10000" min="10" step="1"/>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
<input matInput formControlName="valueExpression"
placeholder="${params}"/>
</mat-form-field>
</ng-container>

View File

@ -0,0 +1,24 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
display: flex;
flex-direction: column;
.mat-mdc-slide-toggle.margin {
margin-bottom: 10px;
margin-left: 10px;
}
}

View File

@ -0,0 +1,139 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import {
ChangeDetectionStrategy,
Component,
forwardRef,
OnDestroy,
} from '@angular/core';
import {
ControlValueAccessor,
FormBuilder,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormGroup,
ValidationErrors,
Validator, Validators,
} from '@angular/forms';
import { SharedModule } from '@shared/shared.module';
import { CommonModule } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil, tap } from 'rxjs/operators';
import {
integerRegex,
noLeadTrailSpacesRegex,
RPCTemplateConfigMQTT
} from '@home/components/widget/lib/gateway/gateway-widget.models';
@Component({
selector: 'tb-mqtt-rpc-parameters',
templateUrl: './mqtt-rpc-parameters.component.html',
styleUrls: ['./mqtt-rpc-parameters.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MqttRpcParametersComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MqttRpcParametersComponent),
multi: true
}
],
standalone: true,
imports: [
CommonModule,
SharedModule,
],
})
export class MqttRpcParametersComponent implements ControlValueAccessor, Validator, OnDestroy {
rpcParametersFormGroup: UntypedFormGroup;
private onChange: (value: RPCTemplateConfigMQTT) => void = (_) => {};
private onTouched: () => void = () => {};
private destroy$ = new Subject<void>();
constructor(private fb: FormBuilder) {
this.rpcParametersFormGroup = this.fb.group({
methodFilter: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
requestTopicExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
responseTopicExpression: [{ value: null, disabled: true }, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
responseTimeout: [{ value: null, disabled: true }, [Validators.min(10), Validators.pattern(integerRegex)]],
valueExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
withResponse: [false, []],
});
this.observeValueChanges();
this.observeWithResponse();
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
registerOnChange(fn: (value: RPCTemplateConfigMQTT) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
validate(): ValidationErrors | null {
return this.rpcParametersFormGroup.valid ? null : {
rpcParametersFormGroup: { valid: false }
};
}
writeValue(value: RPCTemplateConfigMQTT): void {
this.rpcParametersFormGroup.patchValue(value, {emitEvent: false});
this.toggleResponseFields(value.withResponse);
}
private observeValueChanges(): void {
this.rpcParametersFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
this.onChange(value);
this.onTouched();
});
}
private observeWithResponse(): void {
this.rpcParametersFormGroup.get('withResponse').valueChanges.pipe(
tap((isActive: boolean) => this.toggleResponseFields(isActive)),
takeUntil(this.destroy$),
).subscribe();
}
private toggleResponseFields(enabled: boolean): void {
const responseTopicControl = this.rpcParametersFormGroup.get('responseTopicExpression');
const responseTimeoutControl = this.rpcParametersFormGroup.get('responseTimeout');
if (enabled) {
responseTopicControl.enable();
responseTimeoutControl.enable();
} else {
responseTopicControl.disable();
responseTimeoutControl.disable();
}
}
}

View File

@ -0,0 +1,93 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ng-container [formGroup]="rpcParametersFormGroup">
<div class="tb-form-hint tb-primary-fill tb-flex no-padding-top hint-container">
{{ 'gateway.rpc.hint.opc-method' | translate }}
</div>
<mat-form-field class="tb-flex">
<mat-label>{{ 'gateway.rpc.method' | translate }}</mat-label>
<input matInput formControlName="method" placeholder="multiply"/>
</mat-form-field>
<fieldset class="tb-form-panel stroked arguments-container" fxLayout="column" formArrayName="arguments">
<strong>
<span class="fields-label">{{ 'gateway.rpc.arguments' | translate }}</span>
</strong>
<div fxFlex fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center"
*ngFor="let argumentFormGroup of rpcParametersFormGroup.get('arguments')['controls']; let i = index" [formGroup]="argumentFormGroup">
<div class="tb-form-row column-xs type-container" fxLayoutAlign="space-between center">
<div class="tb-required" translate>gateway.type</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap fill-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="type">
<mat-select-trigger>
<div class="tb-flex align-center">
<mat-icon class="tb-mat-18" [svgIcon]="valueTypes.get(argumentFormGroup.get('type').value)?.icon">
</mat-icon>
<span>{{ valueTypes.get(argumentFormGroup.get('type').value)?.name | translate }}</span>
</div>
</mat-select-trigger>
<mat-option *ngFor="let valueType of valueTypeKeys" [value]="valueType">
<mat-icon class="tb-mat-20" svgIcon="{{ valueTypes.get(valueType).icon }}">
</mat-icon>
<span>{{ valueTypes.get(valueType).name | translate }}</span>
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="tb-form-row column-xs value-container" fxLayoutAlign="space-between center">
<div class="tb-required" translate>gateway.value</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute">
<ng-container [ngSwitch]="argumentFormGroup.get('type').value">
<input *ngSwitchCase="MappingValueType.STRING" matInput required formControlName="string"
placeholder="{{ 'gateway.set' | translate }}" />
<input *ngSwitchCase="MappingValueType.INTEGER" matInput required formControlName="integer" type="number"
placeholder="{{ 'gateway.set' | translate }}" />
<input *ngSwitchCase="MappingValueType.DOUBLE" matInput required formControlName="double" type="number"
placeholder="{{ 'gateway.set' | translate }}" />
<mat-select *ngSwitchCase="MappingValueType.BOOLEAN" formControlName="boolean">
<mat-option [value]="true">true</mat-option>
<mat-option [value]="false">false</mat-option>
</mat-select>
</ng-container>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.value-required') | translate"
*ngIf="argumentFormGroup.get(argumentFormGroup.get('type').value).hasError('required')
&& argumentFormGroup.get(argumentFormGroup.get('type').value).touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
<button mat-icon-button (click)="removeArgument(i)"
class="tb-box-button"
matTooltip="{{ 'gateway.rpc.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
<button mat-raised-button
fxFlexAlign="start"
(click)="addArgument()">
{{ 'gateway.rpc.add-argument' | translate }}
</button>
</fieldset>
</ng-container>

View File

@ -0,0 +1,32 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.arguments-container {
margin-bottom: 10px;
}
.type-container {
width: 40%;
}
.value-container {
width: 50%;
}
.hint-container {
margin-bottom: 12px;
}
}

View File

@ -0,0 +1,169 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
forwardRef,
OnDestroy,
} from '@angular/core';
import {
ControlValueAccessor,
FormArray,
FormBuilder,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormGroup,
ValidationErrors,
Validator, Validators,
} from '@angular/forms';
import { SharedModule } from '@shared/shared.module';
import { CommonModule } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import {
integerRegex,
MappingValueType,
mappingValueTypesMap,
noLeadTrailSpacesRegex,
OPCTypeValue,
RPCTemplateConfigOPC
} from '@home/components/widget/lib/gateway/gateway-widget.models';
import { isDefinedAndNotNull, isEqual } from '@core/utils';
@Component({
selector: 'tb-opc-rpc-parameters',
templateUrl: './opc-rpc-parameters.component.html',
styleUrls: ['./opc-rpc-parameters.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => OpcRpcParametersComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => OpcRpcParametersComponent),
multi: true
}
],
standalone: true,
imports: [
CommonModule,
SharedModule,
],
})
export class OpcRpcParametersComponent implements ControlValueAccessor, Validator, OnDestroy {
rpcParametersFormGroup: UntypedFormGroup;
readonly valueTypeKeys: MappingValueType[] = Object.values(MappingValueType);
readonly MappingValueType = MappingValueType;
readonly valueTypes = mappingValueTypesMap;
private onChange: (value: RPCTemplateConfigOPC) => void = (_) => {} ;
private onTouched: () => void = () => {};
private destroy$ = new Subject<void>();
constructor(private fb: FormBuilder, private cdr: ChangeDetectorRef) {
this.rpcParametersFormGroup = this.fb.group({
method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
arguments: this.fb.array([]),
});
this.observeValueChanges();
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
registerOnChange(fn: (value: RPCTemplateConfigOPC) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
validate(): ValidationErrors | null {
return this.rpcParametersFormGroup.valid ? null : {
rpcParametersFormGroup: { valid: false }
};
}
writeValue(params: RPCTemplateConfigOPC): void {
this.clearArguments();
params.arguments?.map(({type, value}) => ({type, [type]: value }))
.forEach(argument => this.addArgument(argument as OPCTypeValue));
this.cdr.markForCheck();
this.rpcParametersFormGroup.get('method').patchValue(params.method);
}
private observeValueChanges(): void {
this.rpcParametersFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(params => {
const updatedArguments = params.arguments.map(({type, ...config}) => ({type, value: config[type]}));
this.onChange({method: params.method, arguments: updatedArguments});
this.onTouched();
});
}
removeArgument(index: number): void {
(this.rpcParametersFormGroup.get('arguments') as FormArray).removeAt(index);
}
addArgument(value: OPCTypeValue = {} as OPCTypeValue): void {
const fromGroup = this.fb.group({
type: [value.type ?? MappingValueType.STRING],
string: [
value.string ?? { value: '', disabled: !(isEqual(value, {}) || value.string)},
[Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]
],
integer: [
{value: value.integer ?? 0, disabled: !isDefinedAndNotNull(value.integer)},
[Validators.required, Validators.pattern(integerRegex)]
],
double: [{value: value.double ?? 0, disabled: !isDefinedAndNotNull(value.double)}, [Validators.required]],
boolean: [{value: value.boolean ?? false, disabled: !isDefinedAndNotNull(value.boolean)}, [Validators.required]],
});
this.observeTypeChange(fromGroup);
(this.rpcParametersFormGroup.get('arguments') as FormArray).push(fromGroup, {emitEvent: false});
}
clearArguments(): void {
const formArray = this.rpcParametersFormGroup.get('arguments') as FormArray;
while (formArray.length !== 0) {
formArray.removeAt(0);
}
}
private observeTypeChange(dataKeyFormGroup: FormGroup): void {
dataKeyFormGroup.get('type').valueChanges
.pipe(takeUntil(this.destroy$))
.subscribe(type => {
dataKeyFormGroup.disable({emitEvent: false});
dataKeyFormGroup.get('type').enable({emitEvent: false});
dataKeyFormGroup.get(type).enable({emitEvent: false});
});
}
}

View File

@ -70,8 +70,8 @@
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.value-required') | translate"
*ngIf="keyControl.get(keyControl.get('type').value).hasError('required')
&& keyControl.get(keyControl.get('type').value).touched"
*ngIf="keyControl.get(keyControl.get('value').value).hasError('required')
&& keyControl.get(keyControl.get('value').value).touched"
class="tb-error">
warning
</mat-icon>

View File

@ -104,7 +104,7 @@ export class TypeValuePanelComponent implements ControlValueAccessor, Validator,
dataKeyFormGroup.disable({emitEvent: false});
dataKeyFormGroup.get('type').enable({emitEvent: false});
dataKeyFormGroup.get(type).enable({emitEvent: false});
})
});
}
deleteKey($event: Event, index: number): void {

View File

@ -44,7 +44,11 @@
<div class="template-key">
{{!innerValue ? ('gateway.rpc.' + config.key | translate) : config.key}}
</div>
<div *ngIf="!isObject(config.value) else RPCObjectRow"
<div *ngIf="isArray(config.value)" tbTruncateWithTooltip class="array-value">
{{ config.value | getRpcTemplateArrayView }}
</div>
<ng-container *ngIf="isObject(config.value)" [ngTemplateOutlet]="RPCObjectRow"></ng-container>
<div *ngIf="!isObject(config.value) && !isArray(config.value)"
[ngClass]="{'boolean-true': config.value === true,
'boolean-false': config.value === false }">
<ng-container *ngIf="config.key === 'method' else value" [ngTemplateOutlet]="SNMPMethod"></ng-container>

View File

@ -104,6 +104,10 @@
flex: 1;
margin: 0;
}
.array-value {
margin-left: 10px;
}
}

View File

@ -49,7 +49,8 @@ export class GatewayServiceRPCConnectorTemplatesComponent implements OnInit {
rpcTemplates: Array<RPCTemplate>;
public readonly originalOrder = (): number => 0;
public readonly isObject = (value: any) => isLiteralObject(value);
public readonly isObject = (value: unknown) => isLiteralObject(value);
public readonly isArray = (value: unknown) => Array.isArray(value);
public readonly SNMPMethodsTranslations = SNMPMethodsTranslations;
constructor(private attributeService: AttributeService) {

View File

@ -20,36 +20,6 @@
class="mat-subtitle-1 title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}</div>
<ng-template [ngIf]="connectorType">
<ng-container [ngSwitch]="connectorType">
<ng-template [ngSwitchCase]="ConnectorType.MQTT">
<mat-form-field>
<mat-label>{{ 'gateway.rpc.methodFilter' | translate }}</mat-label>
<input matInput formControlName="methodFilter"
placeholder="echo"/>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'gateway.rpc.requestTopicExpression' | translate }}</mat-label>
<input matInput formControlName="requestTopicExpression"
placeholder="sensor/${deviceName}/request/${methodName}/${requestId}"/>
</mat-form-field>
<mat-slide-toggle class="margin" (click)="$event.stopPropagation()" formControlName="withResponse">
{{ 'gateway.rpc.withResponse' | translate }}
</mat-slide-toggle>
<mat-form-field *ngIf="commandForm.get('withResponse')?.value">
<mat-label>{{ 'gateway.rpc.responseTopicExpression' | translate }}</mat-label>
<input matInput formControlName="responseTopicExpression"
placeholder="sensor/${deviceName}/response/${methodName}/${requestId}"/>
</mat-form-field>
<mat-form-field *ngIf="commandForm.get('withResponse')?.value">
<mat-label>{{ 'gateway.rpc.responseTimeout' | translate }}</mat-label>
<input matInput formControlName="responseTimeout" type="number"
placeholder="10000" min="10" step="1"/>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'gateway.rpc.valueExpression' | translate }}</mat-label>
<input matInput formControlName="valueExpression"
placeholder="${params}"/>
</mat-form-field>
</ng-template>
<ng-template [ngSwitchCase]="ConnectorType.BACNET">
<mat-form-field>
<mat-label>{{ 'gateway.rpc.methodRPC' | translate }}</mat-label>
@ -407,31 +377,6 @@
</button>
</fieldset>
</ng-template>
<ng-template [ngSwitchCase]="ConnectorType.OPCUA" #OPCUAForm>
<mat-form-field >
<mat-label>{{ 'gateway.rpc.method' | translate }}</mat-label>
<input matInput formControlName="method" placeholder="multiply"/>
</mat-form-field>
<fieldset class="fields border" fxLayout="column" fxLayoutGap="10px" formArrayName="arguments">
<span class="fields-label">{{ 'gateway.rpc.arguments' | translate }}</span>
<div fxFlex fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center"
*ngFor="let control of getFormArrayControls('arguments'); let i = index">
<mat-form-field appearance="outline" fxFlex>
<input matInput [formControl]="control" required/>
</mat-form-field>
<mat-icon style="cursor:pointer;"
fxFlex="30px"
(click)="removeOCPUAArguments(i)"
matTooltip="{{ 'gateway.rpc.remove' | translate }}">delete
</mat-icon>
</div>
<button mat-raised-button
fxFlexAlign="start"
(click)="addOCPUAArguments()">
{{ 'gateway.rpc.add-argument' | translate }}
</button>
</fieldset>
</ng-template>
<ng-template ngSwitchDefault>
<mat-form-field>
<mat-label>{{ 'gateway.statistics.command' | translate }}</mat-label>

View File

@ -51,7 +51,6 @@ import {
} from '@shared/components/dialog/json-object-edit-dialog.component';
import { jsonRequired } from '@shared/components/json-object-edit.component';
import { deepClone } from '@core/utils';
import { takeUntil, tap } from "rxjs/operators";
import { Subject } from "rxjs";
@Component({
@ -129,7 +128,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
this.propagateChange({...this.commandForm.value, ...value});
}
});
this.observeMQTTWithResponse();
}
ngOnDestroy(): void {
@ -141,16 +139,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
let formGroup: FormGroup;
switch (type) {
case ConnectorType.MQTT:
formGroup = this.fb.group({
methodFilter: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
requestTopicExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
responseTopicExpression: [{ value: null, disabled: true }, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
responseTimeout: [{ value: null, disabled: true }, [Validators.min(10), Validators.pattern(this.numbersOnlyPattern)]],
valueExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
withResponse: [false, []],
});
break;
case ConnectorType.BACNET:
formGroup = this.fb.group({
method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
@ -246,12 +234,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
httpHeaders: this.fb.array([]),
})
break;
case ConnectorType.OPCUA:
formGroup = this.fb.group({
method: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
arguments: this.fb.array([]),
})
break;
default:
formGroup = this.fb.group({
command: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
@ -293,18 +275,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
return (this.commandForm.get(path) as FormArray).controls as FormControl[];
}
addOCPUAArguments(value: string = null) {
const oidsFA = this.commandForm.get('arguments') as FormArray;
if (oidsFA) {
oidsFA.push(this.fb.control(value, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]), {emitEvent: false});
}
}
removeOCPUAArguments(index: number) {
const oidsFA = this.commandForm.get('arguments') as FormArray;
oidsFA.removeAt(index);
}
openEditJSONDialog($event: Event) {
if ($event) {
$event.stopPropagation();
@ -368,34 +338,8 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, OnDestroy, C
})
delete value.httpHeaders;
break;
case ConnectorType.OPCUA:
this.clearFromArrayByName("arguments");
value.arguments.forEach(value => {
this.addOCPUAArguments(value)
})
delete value.arguments;
break;
}
this.commandForm.patchValue(value, {onlySelf: false});
}
}
private observeMQTTWithResponse(): void {
if (this.connectorType === ConnectorType.MQTT) {
this.commandForm.get('withResponse').valueChanges.pipe(
tap((isActive: boolean) => {
const responseTopicControl = this.commandForm.get('responseTopicExpression');
const responseTimeoutControl = this.commandForm.get('responseTimeout');
if (isActive) {
responseTopicControl.enable();
responseTimeoutControl.enable();
} else {
responseTopicControl.disable();
responseTimeoutControl.disable();
}
}),
takeUntil(this.destroy$),
).subscribe();
}
}
}

View File

@ -42,16 +42,20 @@
</ng-container>
<ng-template #connectorForm>
<tb-gateway-service-rpc-connector
*ngIf="connectorType !== ConnectorType.MODBUS else modbusParameters"
*ngIf="!typesWithUpdatedParams.has(connectorType) else updatedParameters"
formControlName="params"
[connectorType]="connectorType"
(sendCommand)="sendCommand()"
(saveTemplate)="saveTemplate()"
/>
<ng-template #modbusParameters>
<ng-template #updatedParameters>
<div fxLayout="column" class="rpc-parameters">
<div class="mat-subtitle-1 tb-form-panel-title">{{ 'gateway.rpc.title' | translate: {type: gatewayConnectorDefaultTypesTranslates.get(connectorType)} }}</div>
<tb-modbus-rpc-parameters formControlName="params"/>
<ng-container [ngSwitch]="connectorType">
<tb-modbus-rpc-parameters *ngSwitchCase="ConnectorType.MODBUS" formControlName="params"/>
<tb-mqtt-rpc-parameters *ngSwitchCase="ConnectorType.MQTT" formControlName="params"/>
<tb-opc-rpc-parameters *ngSwitchCase="ConnectorType.OPCUA" formControlName="params"/>
</ng-container>
<div class="template-actions" fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="10px">
<button mat-raised-button
(click)="saveTemplate()"

View File

@ -74,6 +74,11 @@ export class GatewayServiceRPCComponent implements OnInit {
readonly ConnectorType = ConnectorType;
readonly gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslatesMap;
readonly typesWithUpdatedParams = new Set<ConnectorType>([
ConnectorType.MQTT,
ConnectorType.OPCUA,
ConnectorType.MODBUS,
]);
private subscription: IWidgetSubscription;
private subscriptionOptions: WidgetSubscriptionOptions = {

View File

@ -297,7 +297,7 @@ export interface LegacyTimeseries {
export interface RpcArgument {
type: string;
value: number;
value: number | string | boolean;
}
export interface RpcMethod {
@ -542,6 +542,37 @@ export interface RPCTemplateConfig {
[key: string]: any;
}
export interface RPCTemplateConfigMQTT {
methodFilter: string;
requestTopicExpression: string;
responseTopicExpression?: string;
responseTimeout?: number;
valueExpression: string;
withResponse: boolean;
}
export interface RPCTemplateConfigModbus {
tag: string;
type: ModbusDataType;
functionCode?: number;
objectsCount: number;
address: number;
value?: string;
}
export interface RPCTemplateConfigOPC {
method: string;
arguments: RpcArgument[];
}
export interface OPCTypeValue {
type: MappingValueType;
boolean?: boolean;
double?: number;
integer?: number;
string?: string;
}
export interface SaveRPCTemplateData {
config: RPCTemplateConfig;
templates: Array<RPCTemplate>;

View File

@ -0,0 +1,28 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'getRpcTemplateArrayView',
standalone: true,
})
export class RpcTemplateArrayViewPipe implements PipeTransform {
transform(values: {value: string | boolean | number}[]): string {
return values.map(({value}) => value.toString()).join(', ');
}
}

View File

@ -141,9 +141,6 @@ import {
import {
TypeValuePanelComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/type-value-panel/type-value-panel.component';
import {
ModbusRpcParametersComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component';
import { ScadaSymbolWidgetComponent } from '@home/components/widget/lib/scada/scada-symbol-widget.component';
import {
MqttLegacyBasicConfigComponent
@ -161,7 +158,17 @@ import {
ModbusLegacyBasicConfigComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component';
import {
ReportStrategyComponent
MqttRpcParametersComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/mqtt-rpc-parameters/mqtt-rpc-parameters.component';
import {
OpcRpcParametersComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/opc-rpc-parameters/opc-rpc-parameters.component';
import {
ModbusRpcParametersComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/rpc-parameters/modbus-rpc-parameters/modbus-rpc-parameters.component';
import { RpcTemplateArrayViewPipe } from '@home/components/widget/lib/gateway/pipes/rpc-template-array-view.pipe';
import {
ReportStrategyComponent
} from '@home/components/widget/lib/gateway/connectors-configuration/report-strategy/report-strategy.component';
@NgModule({
@ -256,6 +263,10 @@ import {
GatewayAdvancedConfigurationComponent,
OpcUaLegacyBasicConfigComponent,
ModbusLegacyBasicConfigComponent,
MqttRpcParametersComponent,
OpcRpcParametersComponent,
ModbusRpcParametersComponent,
RpcTemplateArrayViewPipe,
ReportStrategyComponent,
],
exports: [

View File

@ -45,6 +45,7 @@ import { UtilsService } from '@core/services/utils.service';
import { from } from 'rxjs';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import { TbContextMenuEvent } from '@shared/models/jquery-event.models';
export enum WidgetComponentActionType {
MOUSE_DOWN,
@ -57,7 +58,7 @@ export enum WidgetComponentActionType {
}
export class WidgetComponentAction {
event: MouseEvent;
event: MouseEvent | TbContextMenuEvent;
actionType: WidgetComponentActionType;
}
@ -151,7 +152,7 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O
}
$(this.gridsterItem.el).on('mousedown', (e) => this.onMouseDown(e.originalEvent));
$(this.gridsterItem.el).on('click', (e) => this.onClicked(e.originalEvent));
$(this.gridsterItem.el).on('contextmenu', (e) => this.onContextMenu(e.originalEvent));
$(this.gridsterItem.el).on('tbcontextmenu', (e: TbContextMenuEvent) => this.onContextMenu(e));
const dashboardContentElement = this.widget.widgetContext.dashboardContentElement;
if (dashboardContentElement) {
this.initEditWidgetActionTooltip(dashboardContentElement);
@ -180,6 +181,9 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O
if (this.editWidgetActionsTooltip && !this.editWidgetActionsTooltip.status().destroyed) {
this.editWidgetActionsTooltip.destroy();
}
$(this.gridsterItem.el).off('mousedown');
$(this.gridsterItem.el).off('click');
$(this.gridsterItem.el).off('tbcontextmenu');
}
isHighlighted(widget: DashboardWidget) {
@ -219,7 +223,7 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O
});
}
onContextMenu(event: MouseEvent) {
onContextMenu(event: TbContextMenuEvent) {
if (event) {
event.stopPropagation();
}

View File

@ -185,7 +185,7 @@
matTooltipPosition="above">
<mat-icon>{{ isFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
</button>
<div class="tb-absolute-fill tb-rulechain-graph" (contextmenu)="openRuleChainContextMenu($event)">
<div class="tb-absolute-fill tb-rulechain-graph" (tbcontextmenu)="openRuleChainContextMenu($event)">
<div #ruleChainMenuTrigger="matMenuTrigger" style="visibility: hidden; position: fixed"
[style.left]="ruleChainMenuPosition.x"
[style.top]="ruleChainMenuPosition.y"

View File

@ -94,6 +94,7 @@ import { VersionControlComponent } from '@home/components/vc/version-control.com
import { ComponentClusteringMode } from '@shared/models/component-descriptor.models';
import { MatDrawer } from '@angular/material/sidenav';
import { HttpStatusCode } from '@angular/common/http';
import { TbContextMenuEvent } from '@shared/models/jquery-event.models';
import Timeout = NodeJS.Timeout;
@Component({
@ -131,7 +132,7 @@ export class RuleChainPageComponent extends PageComponent
ruleChainMenuPosition = { x: '0px', y: '0px' };
contextMenuEvent: MouseEvent;
contextMenuEvent: TbContextMenuEvent;
ruleNodeTypeDescriptorsMap = ruleNodeTypeDescriptors;
ruleNodeTypesLibraryArray = ruleNodeTypesLibrary;
@ -657,7 +658,7 @@ export class RuleChainPageComponent extends PageComponent
this.validate();
}
openRuleChainContextMenu($event: MouseEvent) {
openRuleChainContextMenu($event: TbContextMenuEvent) {
if (this.ruleChainCanvas.modelService && !$event.ctrlKey && !$event.metaKey) {
const x = $event.clientX;
const y = $event.clientY;

View File

@ -1103,8 +1103,9 @@ export const generalStateRenderFunctionCompletions = (ctxCompletion: TbEditorCom
ctx: ctxCompletion,
svg: {
meta: 'argument',
type: '<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg">SVG.Svg</a>',
description: 'A root svg node. Instance of <a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg">SVG.Svg</a>.'
type: '<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg" target="_blank">SVG.Svg</a>',
description: 'A root svg node. Instance of <a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg" ' +
'target="_blank">SVG.Svg</a>.'
}
});
@ -1114,8 +1115,9 @@ export const elementStateRenderFunctionCompletions = (ctxCompletion: TbEditorCom
meta: 'argument',
type: 'Element',
description: 'SVG element.<br>' +
'See <a href="https://svgjs.dev/docs/3.2/manipulating/">Manipulating</a> section to manipulate the element.<br>' +
'See <a href="https://svgjs.dev/docs/3.2/animating/">Animating</a> section to animate the element.'
'See <a href="https://svgjs.dev/docs/3.2/manipulating/" ' +
'target="_blank">Manipulating</a> section to manipulate the element.<br>' +
'See <a href="https://svgjs.dev/docs/3.2/animating/" target="_blank">Animating</a> section to animate the element.'
}
});
@ -1133,7 +1135,7 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags
customTranslate: CustomTranslatePipe): TbEditorCompletion => {
const scadaSymbolAnimationLink = HelpLinks.linksMap.scadaSymbolDevAnimation;
const scadaSymbolAnimation = `<a href="${scadaSymbolAnimationLink}">ScadaSymbolAnimation</a>`;
const scadaSymbolAnimation = `<a href="${scadaSymbolAnimationLink}" target="_blank">ScadaSymbolAnimation</a>`;
const properties: TbEditorCompletion = {
meta: 'object',
@ -1282,8 +1284,8 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags
text: {
meta: 'function',
description: 'Set text to element(s). Only applicable for elements of type ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-text">SVG.Text</a> or ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-tspan">SVG.Tspan</a>.',
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-text" target="_blank">SVG.Text</a> or ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-tspan" target="_blank">SVG.Tspan</a>.',
args: [
{
name: 'element',
@ -1300,8 +1302,8 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags
font: {
meta: 'function',
description: 'Set element(s) text font and color. Only applicable for elements of type ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-text">SVG.Text</a> or ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-tspan">SVG.Tspan</a>.',
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-text" target="_blank">SVG.Text</a> or ' +
'<a href="https://svgjs.dev/docs/3.2/shape-elements/#svg-tspan" target="_blank">SVG.Tspan</a>.',
args: [
{
name: 'element',
@ -1323,7 +1325,7 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags
icon: {
meta: 'function',
description: 'Draws icon inside element(s). Only applicable for elements of type ' +
'<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-g">SVG.G</a>.',
'<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-g" target="_blank">SVG.G</a>.',
args: [
{
name: 'element',
@ -1431,8 +1433,9 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags
tags: tagsCompletions,
svg: {
meta: 'argument',
type: '<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg">SVG.Svg</a>',
description: 'A root svg node. Instance of <a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg">SVG.Svg</a>.'
type: '<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg" target="_blank">SVG.Svg</a>',
description: 'A root svg node. Instance of <a href="https://svgjs.dev/docs/3.2/container-elements/#svg-svg" ' +
'target="_blank">SVG.Svg</a>.'
}
}
};

View File

@ -21,7 +21,7 @@ import { serviceCompletions } from '@shared/models/ace/service-completion.models
const widgetEditorCompletions: TbEditorCompletions = {
... {self: {
description: 'Built-in variable <b>self</b> that is a reference to the widget instance',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L350">WidgetTypeInstance</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L350" target="_blank">WidgetTypeInstance</a>',
meta: 'object',
children: {
...{
@ -31,19 +31,19 @@ const widgetEditorCompletions: TbEditorCompletions = {
},
onDataUpdated: {
description: 'Called when the new data is available from the widget subscription.<br>Latest data can be accessed from ' +
'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>.',
'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" target="_blank">widget context (<code>ctx</code>)</a>.',
meta: 'function'
},
onResize: {
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>.',
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" target="_blank">widget context (<code>ctx</code>)</a>.',
meta: 'function'
},
onEditModeChanged: {
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>.',
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" target="_blank">widget context (<code>ctx</code>)</a>.',
meta: 'function'
},
onMobileModeChanged: {
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>.',
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" target="_blank">widget context (<code>ctx</code>)</a>.',
meta: 'function'
},
onDestroy: {
@ -51,7 +51,7 @@ const widgetEditorCompletions: TbEditorCompletions = {
meta: 'function'
},
getSettingsSchema: {
description: 'Optional function returning widget settings schema json as alternative to <b>Settings tab</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section">Settings schema section</a>.',
description: 'Optional function returning widget settings schema json as alternative to <b>Settings tab</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">Settings schema section</a>.',
meta: 'function',
return: {
description: 'An widget settings schema json',
@ -59,7 +59,7 @@ const widgetEditorCompletions: TbEditorCompletions = {
}
},
getDataKeySettingsSchema: {
description: 'Optional function returning particular data key settings schema json as alternative to <b>Data key settings schema</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section">Settings schema section</a>.',
description: 'Optional function returning particular data key settings schema json as alternative to <b>Data key settings schema</b> of <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">Settings schema section</a>.',
meta: 'function',
return: {
description: 'A particular data key settings schema json',
@ -71,7 +71,7 @@ const widgetEditorCompletions: TbEditorCompletions = {
meta: 'function',
return: {
description: 'An object describing widget datasource parameters.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L146">WidgetTypeParameters</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L146" target="_blank">WidgetTypeParameters</a>'
}
},
actionSources: {
@ -79,7 +79,7 @@ const widgetEditorCompletions: TbEditorCompletions = {
meta: 'function',
return: {
description: 'A map of action sources by action source id.',
type: '{[actionSourceId: string]: <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L118">WidgetActionSource</a>}'
type: '{[actionSourceId: string]: <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L118" target="_blank">WidgetActionSource</a>}'
}
}
},

View File

@ -0,0 +1,35 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Directive, ElementRef, EventEmitter, OnDestroy, Output } from '@angular/core';
import { TbContextMenuEvent } from '@shared/models/jquery-event.models';
@Directive({
selector: '[tbcontextmenu]'
})
export class ContextMenuDirective implements OnDestroy {
@Output()
tbcontextmenu = new EventEmitter<TbContextMenuEvent>();
constructor(private el: ElementRef) {
$(this.el.nativeElement).on('tbcontextmenu', (e: TbContextMenuEvent) => this.tbcontextmenu.emit(e));
}
ngOnDestroy() {
$(this.el.nativeElement).off('tbcontextmenu');
}
}

View File

@ -16,3 +16,4 @@
export * from './truncate-with-tooltip.directive';
export * from './ellipsis-chip-list.directive';
export * from './context-menu.directive';

View File

@ -16,101 +16,101 @@
import { FunctionArg, FunctionArgType, TbEditorCompletions } from '@shared/models/ace/completion.models';
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>';
export const entityIdHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/id/entity-id.ts#L20" target="_blank">EntityId</a>';
export const baseDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/base-data.ts#L22">Base data</a>';
export const baseDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/base-data.ts#L22" target="_blank">Base data</a>';
export const alarmDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L573">Alarm data</a>';
export const alarmDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L573" target="_blank">Alarm data</a>';
export const alarmDataQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L558">Alarm data query</a>';
export const alarmDataQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L558" target="_blank">Alarm data query</a>';
export const attributeScopeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L37">Attribute scope</a>';
export const attributeScopeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L37" target="_blank">Attribute scope</a>';
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>';
export const entityTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L36" target="_blank">EntityType</a>';
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>';
export const pageDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/page/page-data.ts#L17" target="_blank">PageData</a>';
export const deviceInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L33">DeviceInfo</a>';
export const deviceInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L33" target="_blank">DeviceInfo</a>';
export const assetInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L32">AssetInfo</a>';
export const assetInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L32" target="_blank">AssetInfo</a>';
export const entityViewInfoHref = '<a href = "https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-view.models.ts#L47">EntityViewInfo</a>';
export const entityViewInfoHref = '<a href = "https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-view.models.ts#L47" target="_blank">EntityViewInfo</a>';
export const entityRelationsQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L69">EntityRelationsQuery</a>';
export const entityRelationsQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L69" target="_blank">EntityRelationsQuery</a>';
export const entityRelationInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L87">EntityRelationInfo</a>';
export const entityRelationInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L87" target="_blank">EntityRelationInfo</a>';
export const dashboardInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/dashboard.models.ts#L25">DashboardInfo</a>';
export const dashboardInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/dashboard.models.ts#L25" target="_blank">DashboardInfo</a>';
export const deviceHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L24">Device</a>';
export const deviceHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L24" target="_blank">Device</a>';
export const assetHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L23">Asset</a>';
export const assetHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L23" target="_blank">Asset</a>';
export const entityViewHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-view.models.ts#L35">entityView</a>';
export const entityViewHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-view.models.ts#L35" target="_blank">entityView</a>';
export const entityRelationHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L79">Entity relation</a>';
export const entityRelationHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/relation.models.ts#L79" target="_blank">Entity relation</a>';
export const dashboardHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/dashboard.models.ts#L102">Dashboard</a>';
export const dashboardHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/dashboard.models.ts#L102" target="_blank">Dashboard</a>';
export const customerHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/customer.model.ts#L21">Customer</a>';
export const customerHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/customer.model.ts#L21" target="_blank">Customer</a>';
export const attributeDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L76">Attribute Data</a>';
export const attributeDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L76" target="_blank">Attribute Data</a>';
export const timeseriesDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/627c0577b08452308f925cecb3860e35292c649e/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L91">Timeseries Data</a>';
export const timeseriesDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/627c0577b08452308f925cecb3860e35292c649e/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L91" target="_blank">Timeseries Data</a>';
export const aggregationTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/a8ea887eacf7729e603ace13ce2d7d89dae82931/ui-ngx/src/app/shared/models/time/time.models.ts#L54">Aggregation Type</a>';
export const aggregationTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/a8ea887eacf7729e603ace13ce2d7d89dae82931/ui-ngx/src/app/shared/models/time/time.models.ts#L54" target="_blank">Aggregation Type</a>';
export const dataSortOrderHref = '<a href="https://github.com/thingsboard/thingsboard/blob/627c0577b08452308f925cecb3860e35292c649e/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L95">Data Sort Order</a>';
export const dataSortOrderHref = '<a href="https://github.com/thingsboard/thingsboard/blob/627c0577b08452308f925cecb3860e35292c649e/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L95" target="_blank">Data Sort Order</a>';
export const userHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/user.model.ts#L23">User</a>';
export const userHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/user.model.ts#L23" target="_blank">User</a>';
export const entityDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L567">Entity data</a>';
export const entityDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L567" target="_blank">Entity data</a>';
export const entityDataQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L555">Entity Data Query</a>';
export const entityDataQueryHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L555" target="_blank">Entity Data Query</a>';
export const deviceCredentialsHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L50">DeviceCredentials</a>';
export const deviceCredentialsHref = '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L50" target="_blank">DeviceCredentials</a>';
export const entityFilterHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L487">Entity filter</a>';
export const entityFilterHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/query/query.models.ts#L487" target="_blank">Entity filter</a>';
export const entityInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L20">Entity info</a>';
export const entityInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L20" target="_blank">Entity info</a>';
export const aliasEntityTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity-type.models.ts#L51">Alias Entity Type</a>';
export const aliasEntityTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity-type.models.ts#L51" target="_blank">Alias Entity Type</a>';
export const aliasFilterTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity-type.models.ts#L51">Alias filter type</a>';
export const aliasFilterTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity-type.models.ts#L51" target="_blank">Alias filter type</a>';
export const entityAliasHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L150">Entity alias</a>';
export const entityAliasHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L150" target="_blank">Entity alias</a>';
export const dataKeyTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L27">Data key type</a>';
export const dataKeyTypeHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts#L27" target="_blank">Data key type</a>';
export const subscriptionInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L155">Subscription info</a>';
export const subscriptionInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L155" target="_blank">Subscription info</a>';
export const dataSourceHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/widget.models.ts#L257">Datasource</a>';
export const dataSourceHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/widget.models.ts#L257" target="_blank">Datasource</a>';
export const stateParamsHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L129">State params</a>';
export const stateParamsHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L129" target="_blank">State params</a>';
export const aliasInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L88">Alias info</a>';
export const aliasInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L88" target="_blank">Alias info</a>';
export const entityAliasFilterHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L134">Entity alias filter</a>';
export const entityAliasFilterHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L134" target="_blank">Entity alias filter</a>';
export const entityAliasFilterResultHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L158">Entity alias filter result</a>';
export const entityAliasFilterResultHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/alias.models.ts#L158" target="_blank">Entity alias filter result</a>';
export const importEntityDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L28">Import entity data</a>';
export const importEntityDataHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L28" target="_blank">Import entity data</a>';
export const importEntitiesResultInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L42">Import entities result info</a>';
export const importEntitiesResultInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/shared/models/entity.models.ts#L42" target="_blank">Import entities result info</a>';
export const customDialogComponentHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts#L48">CustomDialogComponent</a>';
export const customDialogComponentHref = '<a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts#L48" target="_blank">CustomDialogComponent</a>';
export const resourceInfoHref = '<a https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/shared/models/resource.models.ts#L51">Resource info</a>';
export const resourceInfoHref = '<a href="https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/shared/models/resource.models.ts#L51" target="_blank">Resource info</a>';
export const pageLinkArg: FunctionArg = {
name: 'pageLink',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/page/page-link.ts#L68">PageLink</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/page/page-link.ts#L68" target="_blank">PageLink</a>',
description: 'Page link object used to perform paginated request.'
};
export const requestConfigArg: FunctionArg = {
name: 'config',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/http-utils.ts#L21">RequestConfig</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/http-utils.ts#L21" target="_blank">RequestConfig</a>',
description: 'HTTP request configuration.',
optional: true
};
@ -167,9 +167,9 @@ export function observablePageDataReturnType(objectType: string): FunctionArgTyp
export const serviceCompletions: TbEditorCompletions = {
deviceService: {
description: 'Device Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/device.service.ts#L37" target="_blank">DeviceService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/device.service.ts#L37">DeviceService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/device.service.ts#L37" target="_blank">DeviceService</a>',
children: {
getTenantDeviceInfos: {
description: 'Get tenant devices',
@ -243,7 +243,7 @@ export const serviceCompletions: TbEditorCompletions = {
args: [
requestConfigArg
],
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295">EntitySubtype</a>')
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295" target="_blank">EntitySubtype</a>')
},
getDeviceCredentials: {
description: 'Get device credentials by device id',
@ -322,7 +322,7 @@ export const serviceCompletions: TbEditorCompletions = {
description: 'Find devices by search query',
meta: 'function',
args: [
{ name: 'query', type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L57">DeviceSearchQuery</a>',
{ name: 'query', type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L57" target="_blank">DeviceSearchQuery</a>',
description: 'Device search query object'},
requestConfigArg
],
@ -346,7 +346,7 @@ export const serviceCompletions: TbEditorCompletions = {
description: 'Claiming device name'},
requestConfigArg
],
return: observableReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L71">ClaimResult</a>')
return: observableReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/device.models.ts#L71" target="_blank">ClaimResult</a>')
},
unclaimDevice: {
description: 'Send un-claim device request',
@ -362,9 +362,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
assetService: {
description: 'Asset Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/asset.service.ts#L29" target="_blank">AssetService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/asset.service.ts#L29">AssetService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/asset.service.ts#L29" target="_blank">AssetService</a>',
children: {
getTenantAssetInfos: {
description: 'Get tenant assets',
@ -438,7 +438,7 @@ export const serviceCompletions: TbEditorCompletions = {
args: [
requestConfigArg
],
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295">EntitySubtype</a>')
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295" target="_blank">EntitySubtype</a>')
},
makeAssetPublic: {
description: 'Make asset public (available from public dashboard)',
@ -474,7 +474,7 @@ export const serviceCompletions: TbEditorCompletions = {
args: [
{
name: 'query',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L37">AssetSearchQuery</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L37" target="_blank">AssetSearchQuery</a>',
description: 'Asset search query object'
},
requestConfigArg
@ -497,9 +497,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
entityViewService: {
description: 'EntityView Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-view.service.ts#L29" target="_blank">EntityViewService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-view.service.ts#L29">EntityViewService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-view.service.ts#L29" target="_blank">EntityViewService</a>',
children: {
getTenantEntityViewInfos: {
description: 'Get tenant entity view infos',
@ -564,7 +564,7 @@ export const serviceCompletions: TbEditorCompletions = {
args: [
requestConfigArg
],
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295">EntitySubtype</a>')
return: observableArrayReturnType('<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/entity-type.models.ts#L295" target="_blank">EntitySubtype</a>')
},
makeEntityViewPublic: {
description: 'Make entity view public (available from public dashboard)',
@ -600,7 +600,7 @@ export const serviceCompletions: TbEditorCompletions = {
args: [
{
name: 'query',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L37">AssetSearchQuery</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/asset.models.ts#L37" target="_blank">AssetSearchQuery</a>',
description: 'Entity view search query object'
},
requestConfigArg
@ -611,9 +611,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
customerService: {
description: 'Customer Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/customer.service.ts#L28" target="_blank">CustomerService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/customer.service.ts#L28">CustomerService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/customer.service.ts#L28" target="_blank">CustomerService</a>',
children: {
getCustomer: {
description: 'Get customer by id',
@ -655,9 +655,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
dashboardService: {
description: 'Dashboard Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/dashboard.service.ts#L32" target="_blank">DashboardService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/dashboard.service.ts#L32">DashboardService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/dashboard.service.ts#L32" target="_blank">DashboardService</a>',
children: {
getTenantDashboards: {
description: 'Get tenant dashboards',
@ -814,9 +814,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
userService: {
description: 'User Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/user.service.ts#L29" target="_blank">UserService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/user.service.ts#L29">UserService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/user.service.ts#L29" target="_blank">UserService</a>',
children: {
getUsers: {
description: 'Get users',
@ -907,9 +907,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
entityRelationService: {
description: 'Entity Relation Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-relation.service.ts#L27" target="_blank">EntityRelationService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-relation.service.ts#L27">EntityRelationService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity-relation.service.ts#L27" target="_blank">EntityRelationService</a>',
children: {
saveRelation: {
description: 'Save relation',
@ -1029,9 +1029,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
attributeService: {
description: 'Attribute Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/attribute.service.ts#L28" target="_blank">AttributeService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/attribute.service.ts#L28">AttributeService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/attribute.service.ts#L28" target="_blank">AttributeService</a>',
children: {
getEntityAttributes: {
description: 'Get entity attributes by id',
@ -1109,9 +1109,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
entityService: {
description: 'Entity Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity.service.ts#L64" target="_blank">EntityService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity.service.ts#L64">EntityService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/http/entity.service.ts#L64" target="_blank">EntityService</a>',
children: {
getEntity: {
description: 'Get entity by id',
@ -1304,9 +1304,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
resourceService: {
description: 'Resource Service API<br>' +
'See <a href="https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/core/http/resource.service.ts#L29">ResourceService</a> for API reference.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/core/http/resource.service.ts#L29" target="_blank">ResourceService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/core/http/resource.service.ts#L29">ResourceService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/b033b51712244d08e0f5e0beb8be60c9f8fa4cd2/ui-ngx/src/app/core/http/resource.service.ts#L29" target="_blank">ResourceService</a>',
children: {
getResources: {
description: 'Find resources by search text',
@ -1321,9 +1321,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
dialogs: {
description: 'Dialogs Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/services/dialog.service.ts#L39" target="_blank">DialogService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/services/dialog.service.ts#L39">DialogService</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/services/dialog.service.ts#L39" target="_blank">DialogService</a>',
children: {
confirm: {
description: 'Confirm',
@ -1382,9 +1382,9 @@ export const serviceCompletions: TbEditorCompletions = {
},
customDialog: {
description: 'Custom Dialog Service API<br>' +
'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.',
'See <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts#L33" target="_blank">CustomDialogService</a> for API reference.',
meta: 'service',
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>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts#L33" target="_blank">CustomDialogService</a>',
children: {
customDialog: {
description: 'Custom Dialog',
@ -1400,32 +1400,32 @@ export const serviceCompletions: TbEditorCompletions = {
},
date: {
description: 'Date Pipe<br>Formats a date value according to locale rules.<br>' +
'See <a href="https://angular.io/api/common/DatePipe">DatePipe</a> for API reference.',
'See <a href="https://angular.io/api/common/DatePipe" target="_blank">DatePipe</a> for API reference.',
meta: 'service',
type: '<a href="https://angular.io/api/common/DatePipe">DatePipe</a>'
type: '<a href="https://angular.io/api/common/DatePipe" target="_blank">DatePipe</a>'
},
translate: {
description: 'Translate Service API<br>' +
'See <a href="https://github.com/ngx-translate/core#translateservice">TranslateService</a> for API reference.',
'See <a href="https://github.com/ngx-translate/core#translateservice" target="_blank">TranslateService</a> for API reference.',
meta: 'service',
type: '<a href="https://github.com/ngx-translate/core#translateservice">TranslateService</a>'
type: '<a href="https://github.com/ngx-translate/core#translateservice" target="_blank">TranslateService</a>'
},
http: {
description: 'HTTP Client Service<br>' +
'See <a href="https://angular.io/api/common/http/HttpClient">HttpClient</a> for API reference.',
'See <a href="https://angular.io/api/common/http/HttpClient" target="_blank">HttpClient</a> for API reference.',
meta: 'service',
type: '<a href="https://angular.io/api/common/http/HttpClient">HttpClient</a>'
type: '<a href="https://angular.io/api/common/http/HttpClient" target="_blank">HttpClient</a>'
},
sanitizer: {
description: 'DomSanitizer Service<br>' +
'See <a href="https://angular.io/api/platform-browser/DomSanitizer">DomSanitizer</a> for API reference.',
'See <a href="https://angular.io/api/platform-browser/DomSanitizer" target="_blank">DomSanitizer</a> for API reference.',
meta: 'service',
type: '<a href="https://angular.io/api/platform-browser/DomSanitizer">DomSanitizer</a>'
type: '<a href="https://angular.io/api/platform-browser/DomSanitizer" target="_blank">DomSanitizer</a>'
},
router: {
description: 'Router Service<br>' +
'See <a href="https://angular.io/api/router/Router">Router</a> for API reference.',
'See <a href="https://angular.io/api/router/Router" target="_blank">Router</a> for API reference.',
meta: 'service',
type: '<a href="https://angular.io/api/router/Router">Router</a>'
type: '<a href="https://angular.io/api/router/Router" target="_blank">Router</a>'
}
};

View File

@ -20,7 +20,7 @@ import { entityIdHref, serviceCompletions } from '@shared/models/ace/service-com
export const timewindowCompletion: TbEditorCompletion = {
description: 'Timewindow configuration object',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L80">Timewindow</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L80" target="_blank">Timewindow</a>',
children: {
displayValue: {
description: 'Current timewindow display value.',
@ -50,7 +50,7 @@ export const timewindowCompletion: TbEditorCompletion = {
realtime: {
description: 'Realtime timewindow configuration object.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L39">IntervalWindow</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L39" target="_blank">IntervalWindow</a>',
children: {
interval: {
description: 'Timewindow aggregation interval in milliseconds',
@ -67,7 +67,7 @@ export const timewindowCompletion: TbEditorCompletion = {
history: {
description: 'History timewindow configuration object.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L49">HistoryWindow</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L49" target="_blank">HistoryWindow</a>',
children: {
historyType: {
description: 'History timewindow type (0 - last interval, 1 - fixed)',
@ -87,7 +87,7 @@ export const timewindowCompletion: TbEditorCompletion = {
fixedTimewindow: {
description: 'Fixed history timewindow configuration object',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L44">FixedWindow</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L44" target="_blank">FixedWindow</a>',
children: {
startTimeMs: {
description: 'Timewindow start time in UTC milliseconds',
@ -106,7 +106,7 @@ export const timewindowCompletion: TbEditorCompletion = {
aggregation: {
description: 'Timewindow aggregation configuration object.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L74">Aggregation</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L74" target="_blank">Aggregation</a>',
children: {
interval: {
description: 'Aggregation interval in milliseconds',
@ -116,7 +116,7 @@ export const timewindowCompletion: TbEditorCompletion = {
type: {
description: 'Aggregation type',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L54">AggregationType</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L54" target="_blank">AggregationType</a>'
},
limit: {
description: 'Maximum allowed datapoints when aggregation is disabled (<code>AggregationType == \'NONE\'</code>)',
@ -132,7 +132,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
ctx: {
description: 'A reference to widget context that has all necessary API<br>and data used by widget instance.',
meta: 'object',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83">WidgetContext</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L83" target="_blank">WidgetContext</a>',
children: {
...{
$container: {
@ -143,7 +143,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
$scope: {
description: 'Reference to the current widget component.<br>Can be used to access/modify component properties when widget is built using Angular approach.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L274">IDynamicWidgetComponent</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/modules/home/models/widget-component.models.ts#L274" target="_blank">IDynamicWidgetComponent</a>'
},
width: {
description: 'Current width of widget container in pixels.',
@ -168,7 +168,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
widgetConfig: {
description: 'Common widget configuration containing properties such as <code>color</code> (text color), <code>backgroundColor</code> (widget background color), etc.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L341">WidgetConfig</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L341" target="_blank">WidgetConfig</a>',
children: {
title: {
description: 'Widget title.',
@ -233,17 +233,17 @@ export const widgetContextCompletions: TbEditorCompletions = {
legendConfig: {
description: 'Legend configuration.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L198">LegendConfig</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L198" target="_blank">LegendConfig</a>',
children: {
position: {
description: 'Legend position. Possible values: <code>\'top\', \'bottom\', \'left\', \'right\'</code>',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L182">LegendPosition</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L182" target="_blank">LegendPosition</a>',
},
direction: {
description: 'Legend direction. Possible values: <code>\'column\', \'row\'</code>',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L170">LegendDirection</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L170" target="_blank">LegendDirection</a>',
},
showMin: {
description: 'Whether to display aggregated min values.',
@ -331,12 +331,12 @@ export const widgetContextCompletions: TbEditorCompletions = {
alarmSource: {
description: 'Configured alarm source for alarm widget type.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250">Datasource</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250" target="_blank">Datasource</a>'
},
alarmSearchStatus: {
description: 'Configured default alarm search status for alarm widget type.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/alarm.models.ts#L41">AlarmSearchStatus</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/alarm.models.ts#L41" target="_blank">AlarmSearchStatus</a>'
},
alarmsPollingInterval: {
description: 'Configured alarms polling interval for alarm widget type.',
@ -356,29 +356,29 @@ export const widgetContextCompletions: TbEditorCompletions = {
datasources: {
description: 'Array of configured widget datasources.',
meta: 'property',
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;'
type: 'Array&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250" target="_blank">Datasource</a>&gt;'
}
}
},
settings: {
description: 'Widget settings containing widget specific properties according to the defined <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section">settings json schema</a>',
description: 'Widget settings containing widget specific properties according to the defined <a href="https://thingsboard.io/docs/user-guide/contribution/widgets-development/#settings-schema-section" target="_blank">settings json schema</a>',
meta: 'property',
type: 'object'
},
datasources: {
description: 'Array of resolved widget datasources.',
meta: 'property',
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;'
type: 'Array&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L250" target="_blank">Datasource</a>&gt;'
},
data: {
description: 'Array of latest datasources data.',
meta: 'property',
type: 'Array&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L275">DatasourceData</a>&gt;'
type: 'Array&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L275" target="_blank">DatasourceData</a>&gt;'
},
timeWindow: {
description: 'Current widget timewindow (applicable for timeseries widgets).',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L104">WidgetTimewindow</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/time/time.models.ts#L104" target="_blank">WidgetTimewindow</a>'
},
units: {
description: 'Optional property defining units text of values displayed by widget. Useful for simple widgets like cards or gauges.',
@ -393,7 +393,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
currentUser: {
description: 'Current user object.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/user.model.ts#L45">AuthUser</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/user.model.ts#L45" target="_blank">AuthUser</a>',
children: {
sub: {
description: 'User subject (email).',
@ -443,7 +443,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
authority: {
description: 'User authority. Possible values: SYS_ADMIN, TENANT_ADMIN, CUSTOMER_USER',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/authority.enum.ts#L17">Authority</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/authority.enum.ts#L17" target="_blank">Authority</a>'
}
}
},
@ -468,12 +468,12 @@ export const widgetContextCompletions: TbEditorCompletions = {
defaultSubscription: {
description: 'Default widget subscription object contains all subscription information,<br>including current data, according to the widget type.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L220">IWidgetSubscription</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L220" target="_blank">IWidgetSubscription</a>'
},
timewindowFunctions: {
description: 'Object with timewindow functions used to manage widget data time frame. Can by used by Time-series or Alarm widgets.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L45">TimewindowFunctions</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L45" target="_blank">TimewindowFunctions</a>',
children: {
onUpdateTimewindow: {
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.',
@ -500,7 +500,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
controlApi: {
description: 'Object that provides API functions for RPC (Control) widgets.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L58">RpcApi</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L58" target="_blank">RpcApi</a>',
children: {
sendOneWayCommand: {
description: 'Sends one way (without response) RPC command to the device.',
@ -585,7 +585,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
actionsApi: {
description: 'Set of API functions to work with user defined actions.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L67">WidgetActionsApi</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L67" target="_blank">WidgetActionsApi</a>',
children: {
getActionDescriptors: {
description: 'Get list of action descriptors for provided <code>actionSourceId</code>.',
@ -599,7 +599,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
],
return: {
description: 'The list of action descriptors',
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;'
type: 'Array&lt;<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323" target="_blank">WidgetActionDescriptor</a>&gt;'
}
},
handleWidgetAction: {
@ -614,7 +614,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
{
name: 'descriptor',
description: 'An action descriptor.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323">WidgetActionDescriptor</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/shared/models/widget.models.ts#L323" target="_blank">WidgetActionDescriptor</a>'
},
{
name: 'entityId',
@ -635,7 +635,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
stateController: {
description: 'Reference to Dashboard state controller, providing API to manage current dashboard state.',
meta: 'property',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L121">IStateController</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L121" target="_blank">IStateController</a>',
children: {
openState: {
description: 'Navigate to new dashboard state.',
@ -649,7 +649,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
{
name: 'params',
description: 'An object with state parameters to use by the new state.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111" target="_blank">StateParams</a>',
optional: true
},
{
@ -667,7 +667,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
{
name: 'id',
description: 'An array state object of the target dashboard state.',
type: 'Array <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L140">StateObject</a>',
type: 'Array <a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L140" target="_blank">StateObject</a>',
},
{
name: 'openRightLayout',
@ -690,7 +690,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
{
name: 'params',
description: 'An object with state parameters to update current state parameters.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111" target="_blank">StateParams</a>',
optional: true
},
{
@ -714,7 +714,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
meta: 'function',
return: {
description: 'current dashboard state parameters.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111" target="_blank">StateParams</a>'
}
},
getStateParamsByStateId: {
@ -729,7 +729,7 @@ export const widgetContextCompletions: TbEditorCompletions = {
],
return: {
description: 'current dashboard state parameters.',
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111">StateParams</a>'
type: '<a href="https://github.com/thingsboard/thingsboard/blob/13e6b10b7ab830e64d31b99614a9d95a1a25928a/ui-ngx/src/app/core/api/widget-api.models.ts#L111" target="_blank">StateParams</a>'
}
}
}

View File

@ -0,0 +1,80 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import Timeout = NodeJS.Timeout;
export interface TbContextMenuEvent extends Event {
clientX: number;
clientY: number;
ctrlKey: boolean;
metaKey: boolean;
}
const isIOSDevice = (): boolean =>
/iPhone|iPad|iPod/i.test(navigator.userAgent) || (navigator.userAgent.includes('Mac') && 'ontouchend' in document);
export const initCustomJQueryEvents = () => {
$.event.special.tbcontextmenu = {
setup(this: HTMLElement) {
const el = $(this);
if (isIOSDevice()) {
let timeoutId: Timeout;
el.on('touchstart', (e) => {
e.stopPropagation();
timeoutId = setTimeout(() => {
timeoutId = null;
e.stopPropagation();
const touch = e.originalEvent.changedTouches[0];
const event = $.Event('tbcontextmenu', {
clientX: touch.clientX,
clientY: touch.clientY,
ctrlKey: false,
metaKey: false
});
el.trigger(event, e);
}, 500);
});
el.on('touchend touchmove', () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
});
} else {
el.on('contextmenu', (e) => {
e.preventDefault();
e.stopPropagation();
const event = $.Event('tbcontextmenu', {
clientX: e.originalEvent.clientX,
clientY: e.originalEvent.clientY,
ctrlKey: e.originalEvent.ctrlKey,
metaKey: e.originalEvent.metaKey,
});
el.trigger(event, e);
});
}
},
teardown(this: HTMLElement) {
const el = $(this);
if (isIOSDevice()) {
el.off('touchstart touchend touchmove');
} else {
el.off('contextmenu');
}
}
};
};

View File

@ -68,6 +68,7 @@ import { NgxHmCarouselModule } from 'ngx-hm-carousel';
import { EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular';
import { UserMenuComponent } from '@shared/components/user-menu.component';
import { TruncateWithTooltipDirective } from '@shared/directives/truncate-with-tooltip.directive';
import { ContextMenuDirective } from '@shared/directives/context-menu.directive';
import { NospacePipe } from '@shared/pipe/nospace.pipe';
import { TranslateModule } from '@ngx-translate/core';
import { TbCheckboxComponent } from '@shared/components/tb-checkbox.component';
@ -371,6 +372,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
LedLightComponent,
MarkdownEditorComponent,
TruncateWithTooltipDirective,
ContextMenuDirective,
NospacePipe,
MillisecondsToTimeStringPipe,
EnumToArrayPipe,
@ -633,6 +635,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
LedLightComponent,
MarkdownEditorComponent,
TruncateWithTooltipDirective,
ContextMenuDirective,
NospacePipe,
MillisecondsToTimeStringPipe,
EnumToArrayPipe,

View File

@ -1208,7 +1208,7 @@
"dropShadow": false,
"enableFullscreen": false,
"widgetStyle": {},
"widgetCss": " .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding: 0;\n}\n\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 8px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n padding: 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1182px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n gap: 0;\n }\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n min-width: 150px;\n }\n}\n\n@media screen and (max-width: 960px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 120px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 160px;\n }\n}\n\n@media screen and (min-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 125px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 160px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-height: 960px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode-label {\n display: none;\n }\n}",
"widgetCss": " .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding: 0;\n}\n\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 8px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n padding: 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1182px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n gap: 0;\n }\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n min-width: 150px;\n }\n}\n\n@media screen and (max-width: 960px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 120px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 160px;\n }\n}\n\n@media screen and (min-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 125px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 160px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-height: 965px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode-label {\n display: none;\n }\n}",
"showTitleIcon": false,
"titleTooltip": "",
"titleStyle": null,

View File

@ -3142,10 +3142,11 @@
"title": "{{type}} Connector RPC parameters",
"templates-title": "Connector RPC Templates",
"methodFilter": "Method filter",
"method-name": "Method name",
"requestTopicExpression": "Request topic expression",
"responseTopicExpression": "Response topic expression",
"responseTimeout": "Response Time",
"valueExpression": "Value Expression",
"responseTimeout": "Response timeout",
"valueExpression": "Value expression",
"tag": "Tag",
"type": "Type",
"functionCode": "Function Code",
@ -3184,6 +3185,11 @@
"tries": "Tries",
"httpHeaders": "HTTP Headers",
"header-name": "Header name",
"hint": {
"modbus-response-reading": "RPC response will return all subtracted values from all connected devices when the reading functions are selected.",
"modbus-writing-functions": "RPC will write a filled value to all connected devices when the writing functions are selected.",
"opc-method": "A filled method name is the OPC-UA method that will processed on the server side (make sure your node has the requested method)."
},
"security-name": "Security name",
"value": "Value",
"security": "Security",

View File

@ -14,6 +14,9 @@
/// limitations under the License.
///
import { TbContextMenuEvent } from '@shared/models/jquery-event.models';
interface JQuery {
terminal(options?: any): any;
on(events: 'tbcontextmenu', handler: (e: TbContextMenuEvent) => void): this;
}

View File

@ -3052,10 +3052,10 @@
dependencies:
"@types/jasmine" "*"
"@types/jquery@*", "@types/jquery@^3.5.16", "@types/jquery@^3.5.29":
version "3.5.29"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.29.tgz#3c06a1f519cd5fc3a7a108971436c00685b5dcea"
integrity sha512-oXQQC9X9MOPRrMhPHHOsXqeQDnWeCDT3PelUIg/Oy8FAbzSZtFHRjc7IpbfFVmpLtJ+UOoywpRsuO5Jxjybyeg==
"@types/jquery@*", "@types/jquery@^3.5.29", "@types/jquery@^3.5.30":
version "3.5.30"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.30.tgz#888d584cbf844d3df56834b69925085038fd80f7"
integrity sha512-nbWKkkyb919DOUxjmRVk8vwtDb0/k8FKncmUKFi+NY+QXqWltooxTrswvz4LspQwxvLdvzBN1TImr6cw3aQx2A==
dependencies:
"@types/sizzle" "*"
@ -7377,7 +7377,7 @@ jquery.terminal@^2.35.3:
optionalDependencies:
fsevents "^2.3.2"
jquery@>=1.9.1, jquery@^3.5.0, jquery@^3.6.3, jquery@^3.7.1:
jquery@>=1.9.1, jquery@^3.5.0, jquery@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==