UI: gateway dashboard bug-fixes and improvements
This commit is contained in:
parent
214f9d178e
commit
355acfc30a
@ -136,7 +136,7 @@
|
||||
{
|
||||
"name": "active_connectors",
|
||||
"type": "attribute",
|
||||
"label": "Active Connectors",
|
||||
"label": "Enabled Connectors",
|
||||
"color": "#3f51b5",
|
||||
"settings": {
|
||||
"columnWidth": "20%",
|
||||
@ -248,7 +248,7 @@
|
||||
"type": "customPretty",
|
||||
"customHtml": "<form #addEntityForm=\"ngForm\" [formGroup]=\"addEntityFormGroup\"\r\n (ngSubmit)=\"save($event)\" class=\"add-entity-form\">\r\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\r\n <h2>Add gateway</h2>\r\n <span fxFlex></span>\r\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\r\n <mat-icon class=\"material-icons\">close</mat-icon>\r\n </button>\r\n </mat-toolbar>\r\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\r\n </mat-progress-bar>\r\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\r\n <div mat-dialog-content fxLayout=\"column\">\r\n <div fxLayout=\"row\" fxLayoutGap=\"8px\" fxLayout.xs=\"column\" fxLayoutGap.xs=\"0\">\r\n <mat-form-field fxFlex class=\"mat-block\">\r\n <mat-label>Name</mat-label>\r\n <input matInput formControlName=\"entityName\" required>\r\n <mat-error *ngIf=\"addEntityFormGroup.get('entityName').hasError('required')\">\r\n Gateway name is required.\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n <div fxLayout=\"row\" fxLayoutGap=\"8px\" fxLayout.xs=\"column\" fxLayoutGap.xs=\"0\">\r\n <tb-entity-subtype-autocomplete\r\n fxFlex\r\n class=\"mat-block\"\r\n formControlName=\"type\"\r\n [required]=\"true\"\r\n [entityType]=\"'DEVICE'\"\r\n ></tb-entity-subtype-autocomplete>\r\n </div>\r\n </div>\r\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\r\n <button mat-button color=\"primary\"\r\n type=\"button\"\r\n [disabled]=\"(isLoading$ | async)\"\r\n (click)=\"cancel()\" cdkFocusInitial>\r\n Cancel\r\n </button>\r\n <button mat-button mat-raised-button color=\"primary\"\r\n type=\"submit\"\r\n [disabled]=\"(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty\">\r\n Create\r\n </button>\r\n </div>\r\n</form>\r\n",
|
||||
"customCss": ".add-entity-form {\r\n min-width: 400px !important;\r\n}\r\n\r\n.add-entity-form .boolean-value-input {\r\n padding-left: 5px;\r\n}\r\n\r\n.add-entity-form .boolean-value-input .checkbox-label {\r\n margin-bottom: 8px;\r\n color: rgba(0,0,0,0.54);\r\n font-size: 12px;\r\n}\r\n\r\n.relations-list .header {\r\n padding-right: 5px;\r\n padding-bottom: 5px;\r\n padding-left: 5px;\r\n}\r\n\r\n.relations-list .header .cell {\r\n padding-right: 5px;\r\n padding-left: 5px;\r\n font-size: 12px;\r\n font-weight: 700;\r\n color: rgba(0, 0, 0, .54);\r\n white-space: nowrap;\r\n}\r\n\r\n.relations-list .mat-form-field-infix {\r\n width: auto !important;\r\n}\r\n\r\n.relations-list .body {\r\n padding-right: 5px;\r\n padding-bottom: 15px;\r\n padding-left: 5px;\r\n}\r\n\r\n.relations-list .body .row {\r\n padding-top: 5px;\r\n}\r\n\r\n.relations-list .body .cell {\r\n padding-right: 5px;\r\n padding-left: 5px;\r\n}\r\n\r\n.relations-list .body .md-button {\r\n margin: 0;\r\n}\r\n\r\n",
|
||||
"customFunction": "let $injector = widgetContext.$scope.$injector;\r\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\r\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\r\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\r\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\r\nlet entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService'));\r\nlet userSettingsService = $injector.get(widgetContext.servicesMap.get('userSettingsService'));\r\n\r\nopenAddEntityDialog();\r\n\r\nfunction openAddEntityDialog() {\r\n customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();\r\n}\r\n\r\nfunction AddEntityDialogController(instance) {\r\n let vm = instance;\r\n let userSettings;\r\n userSettingsService.loadUserSettings().subscribe(settings=> {\r\n userSettings = settings;\r\n if (!userSettings.createdGatewaysCount) userSettings.createdGatewaysCount = 0;\r\n });\r\n \r\n\r\n vm.addEntityFormGroup = vm.fb.group({\r\n entityName: ['', [vm.validators.required]],\r\n entityType: ['DEVICE'],\r\n entityLabel: [''],\r\n type: ['', [vm.validators.required]],\r\n });\r\n\r\n vm.cancel = function() {\r\n vm.dialogRef.close(null);\r\n };\r\n\r\n\r\n vm.save = function($event) {\r\n vm.addEntityFormGroup.markAsPristine();\r\n saveEntityObservable().subscribe(\r\n function (device) {\r\n widgetContext.updateAliases();\r\n userSettingsService.putUserSettings({ createdGatewaysCount: ++userSettings.createdGatewaysCount }).subscribe(_=>{\r\n });\r\n vm.dialogRef.close(null);\r\n openCommandDialog(device, $event);\r\n }\r\n );\r\n };\r\n \r\n function openCommandDialog(device, $event) {\r\n vm.device = device;\r\n let openCommandAction = widgetContext.actionsApi.getActionDescriptors(\"actionCellButton\").find(action => action.name == \"Docker commands\");\r\n widgetContext.actionsApi.handleWidgetAction($event, openCommandAction, device.id, device.name, {newDevice: true});\r\n setTimeout(function() {\r\n document.querySelector(\".dashboard-state-dialog .mat-mdc-button-touch-target\").addEventListener('click', goToConfigState);\r\n document.querySelector(\".dashboard-state-dialog .mat-mdc-button.mat-primary\").addEventListener('click', goToConfigState);\r\n }, 500);\r\n }\r\n\r\n \r\n function goToConfigState() {\r\n document.querySelector(\".dashboard-state-dialog .mat-mdc-button-touch-target\").removeEventListener('click', goToConfigState);\r\n document.querySelector(\".dashboard-state-dialog .mat-mdc-button.mat-primary\").removeEventListener('click', goToConfigState);\r\n const stateParams = {};\r\n stateParams.entityId = vm.device.id;\r\n stateParams.entityName = vm.device.name;\r\n const newStateParams = {\r\n targetEntityParamName: 'default',\r\n new_gateway: {\r\n entityId: vm.device.id,\r\n entityName: vm.device.name\r\n }\r\n }\r\n const params = {...stateParams, ...newStateParams};\r\n widgetContext.stateController.openState('gateway_details', params, false);\r\n }\r\n\r\n function saveEntityObservable() {\r\n const formValues = vm.addEntityFormGroup.value;\r\n let entity = {\r\n name: formValues.entityName,\r\n type: formValues.type,\r\n label: formValues.entityLabel,\r\n additionalInfo: {\r\n gateway: true\r\n }\r\n };\r\n return deviceService.saveDevice(entity);\r\n }\r\n}\r\n",
|
||||
"customFunction": "let $injector = widgetContext.$scope.$injector;\r\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\r\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\r\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\r\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\r\nlet entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService'));\r\nlet userSettingsService = $injector.get(widgetContext.servicesMap.get('userSettingsService'));\r\n\r\nopenAddEntityDialog();\r\n\r\nfunction openAddEntityDialog() {\r\n customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();\r\n}\r\n\r\nfunction AddEntityDialogController(instance) {\r\n let vm = instance;\r\n let userSettings;\r\n userSettingsService.loadUserSettings().subscribe(settings=> {\r\n userSettings = settings;\r\n if (!userSettings.createdGatewaysCount) userSettings.createdGatewaysCount = 0;\r\n });\r\n \r\n\r\n vm.addEntityFormGroup = vm.fb.group({\r\n entityName: ['', [vm.validators.required]],\r\n entityType: ['DEVICE'],\r\n entityLabel: [''],\r\n type: ['', [vm.validators.required]],\r\n });\r\n\r\n vm.cancel = function() {\r\n vm.dialogRef.close(null);\r\n };\r\n\r\n\r\n vm.save = function($event) {\r\n vm.addEntityFormGroup.markAsPristine();\r\n saveEntityObservable().subscribe(\r\n function (device) {\r\n widgetContext.updateAliases();\r\n userSettingsService.putUserSettings({ createdGatewaysCount: ++userSettings.createdGatewaysCount }).subscribe(_=>{\r\n });\r\n vm.dialogRef.close(null);\r\n openCommandDialog(device, $event);\r\n }\r\n );\r\n };\r\n \r\n function openCommandDialog(device, $event) {\r\n vm.device = device;\r\n let openCommandAction = widgetContext.actionsApi.getActionDescriptors(\"actionCellButton\").find(action => action.name == \"Docker commands\");\r\n widgetContext.actionsApi.handleWidgetAction($event, openCommandAction, device.id, device.name, {newDevice: true});\r\n goToConfigState();\r\n }\r\n\r\n \r\n function goToConfigState() {\r\n const stateParams = {};\r\n stateParams.entityId = vm.device.id;\r\n stateParams.entityName = vm.device.name;\r\n const newStateParams = {\r\n targetEntityParamName: 'default',\r\n new_gateway: {\r\n entityId: vm.device.id,\r\n entityName: vm.device.name\r\n }\r\n }\r\n const params = {...stateParams, ...newStateParams};\r\n widgetContext.stateController.openState('gateway_details', params, false);\r\n }\r\n\r\n function saveEntityObservable() {\r\n const formValues = vm.addEntityFormGroup.value;\r\n let entity = {\r\n name: formValues.entityName,\r\n type: formValues.type,\r\n label: formValues.entityLabel,\r\n additionalInfo: {\r\n gateway: true\r\n }\r\n };\r\n return deviceService.saveDevice(entity);\r\n }\r\n}\r\n",
|
||||
"customResources": [],
|
||||
"openInSeparateDialog": false,
|
||||
"openInPopover": false,
|
||||
@ -567,7 +567,8 @@
|
||||
"padding": "8px",
|
||||
"settings": {
|
||||
"useMarkdownTextFunction": true,
|
||||
"markdownTextFunction": "var blockData = '';\nvar connectorsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Connectors\");\nvar logsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Logs\");\nfunction generateMatHeader(index) {\n if( index !== undefined && index > -1) {\n return `<mat-card-header class='tb-home-widget-link' (click)=\"ctx.actionsApi.handleWidgetAction($event, ctx.actionsApi.getActionDescriptors('elementClick')[${index}], ctx.datasources[0].entity.id)\">`\n } else {\n return \"<mat-card-header >\" \n }\n}\nfunction createDataBlock(value, label, dividerStyle, mobile, index) {\n blockData += `\n <mat-card style=\"flex-grow: 1; width: ${mobile? '100%': 'auto'}; min-height: ${mobile? 'auto': '57px'}\" class=\" ${dividerStyle}\">\n <div class=\"divider\"></div>\n <mat-divider vertical style=\"height:100%\"></mat-divider>\n ${generateMatHeader(index)}\n <mat-card-subtitle>${label}</mat-card-subtitle>\n </mat-card-header>\n <mat-card-content> ${value}</mat-card-content>\n </mat-card>`;\n}\ncreateDataBlock(data[0].Status, \"Status\", data[0].Status === \"Active\"? 'divider-green' : 'divider-red');\ncreateDataBlock(data[0].Name, \"Gateway Name\", '', ctx.isMobile);\ncreateDataBlock(data[0].Type, \"Gateway Type\", '');\ncreateDataBlock(\n `<span style=\"color:rgb(25,128,56)\">${(data[1]?data[1].count:0)} </span>`\n + \" | \" + \n `<span style=\"color:rgb(203,37,48)\">${(data[2]?data[2][\"count 2\"]:0)} </span>`\n , \"Devices <span class='tb-hint' style='padding-left: 0'>(Active | Inactive)</span>\", '');\ncreateDataBlock(\n `<span style=\"color:rgb(25,128,56)\">${(data[0].active_connectors?JSON.parse(data[0].active_connectors).length:0)} </span>`\n + \" | \" + \n `<span style=\"color:rgb(203,37,48)\">${(data[0].inactive_connectors?JSON.parse(data[0].inactive_connectors).length:0)} </span>`\n , \"Connectors <span class='tb-hint' style='padding-left: 0'>(Active | Inactive)</span>\", '', '', connectorsIndex);\ncreateDataBlock(data[0].ALL_ERRORS_COUNT || 0, \"Errors\", (data[0].ALL_ERRORS_COUNT || 0) === 0 ? 'divider-green' : 'divider-red', '', logsIndex);\nreturn `<div fxLayout=\"row wrap\" fxLayoutGap=\"8px\" class=\"cards-container\">${blockData}</div>`;",
|
||||
"markdownTextPattern": "# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.",
|
||||
"markdownTextFunction": "var blockData = '';\nvar connectorsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Connectors\");\nvar logsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Logs\");\nfunction generateMatHeader(index) {\n if( index !== undefined && index > -1) {\n return `<mat-card-header class='tb-home-widget-link' (click)=\"ctx.actionsApi.handleWidgetAction($event, ctx.actionsApi.getActionDescriptors('elementClick')[${index}], ctx.datasources[0].entity.id)\">`\n } else {\n return \"<mat-card-header >\" \n }\n}\nfunction createDataBlock(value, label, dividerStyle, mobile, index) {\n blockData += `\n <mat-card style=\"flex-grow: 1; width: ${mobile? '100%': 'auto'}; min-height: ${mobile? 'auto': '57px'}\" class=\" ${dividerStyle}\">\n <div class=\"divider\"></div>\n <mat-divider vertical style=\"height:100%\"></mat-divider>\n ${generateMatHeader(index)}\n <mat-card-subtitle>${label}</mat-card-subtitle>\n </mat-card-header>\n <mat-card-content> ${value}</mat-card-content>\n </mat-card>`;\n}\ncreateDataBlock(data[0].Status, \"Status\", data[0].Status === \"Active\"? 'divider-green' : 'divider-red');\ncreateDataBlock(data[0].Name, \"Gateway Name\", '', ctx.isMobile);\ncreateDataBlock(data[0].Type, \"Gateway Type\", '');\ncreateDataBlock(\n `<span style=\"color:rgb(25,128,56)\">${(data[1]?data[1].count:0)} </span>`\n + \" | \" + \n `<span style=\"color:rgb(203,37,48)\">${(data[2]?data[2][\"count 2\"]:0)} </span>`\n , \"Devices <span class='tb-hint' style='padding-left: 0'>(Active | Inactive)</span>\", '');\ncreateDataBlock(\n `<span style=\"color:rgb(25,128,56)\">${(data[0].active_connectors?JSON.parse(data[0].active_connectors).length:0)} </span>`\n + \" | \" + \n `<span style=\"color:rgb(203,37,48)\">${(data[0].inactive_connectors?JSON.parse(data[0].inactive_connectors).length:0)} </span>`\n , \"Connectors <span class='tb-hint' style='padding-left: 0'>(Enabled | Disabled)</span>\", '', '', connectorsIndex);\ncreateDataBlock(data[0].ALL_ERRORS_COUNT || 0, \"Errors\", (data[0].ALL_ERRORS_COUNT || 0) === 0 ? 'divider-green' : 'divider-red', '', logsIndex);\nreturn `<div fxLayout=\"row wrap\" fxLayoutGap=\"8px\" class=\"cards-container\">${blockData}</div>`;",
|
||||
"applyDefaultMarkdownStyle": false,
|
||||
"markdownCss": ".divider {\n position: absolute;\n width: 3px;\n top: 8px;\n border-radius: 2px;\n bottom: 8px;\n border: 1px solid rgba(31, 70, 144, 1);\n background-color: rgba(31, 70, 144, 1);\n left: 10px;\n}\n.divider-green .divider {\n border: 1px solid rgb(25,128,56);\n background-color: rgb(25,128,56);\n}\n\n.divider-green .mat-mdc-card-content {\n color: rgb(25,128,56);\n}\n\n.divider-red .divider {\n border: 1px solid rgb(203,37,48);\n background-color: rgb(203,37,48);\n}\n\n.divider-red .mat-mdc-card-content {\n color: rgb(203,37,48);\n}\n\n.mdc-card {\n position: relative;\n padding-left: 10px;\n margin-bottom: 1px;\n}\n\n.mat-mdc-card-subtitle {\n font-weight: 400;\n font-size: 12px;\n}\n\n.mat-mdc-card-header {\n padding: 8px 16px 0;\n}\n\n.mat-mdc-card-content:last-child {\n padding-bottom: 8px;\n font-size: 16px;\n}\n\n.cards-container {\n height: calc(100% - 1px);\n justify-content: stretch;\n align-items: center;\n margin-bottom: 1px;\n}\n\n::ng-deep.tb-home-widget-link > div {\n flex-grow: 1;\n cursor: pointer;\n}\n\n .tb-home-widget-link {\n width: 100%;\n }\n\n .tb-home-widget-link:hover::after{\n color: inherit;\n }\n \n .tb-home-widget-link::after{\n content: 'arrow_forward';\n display: inline-block;\n transform: rotate(315deg);\n font-family: 'Material Icons';\n font-weight: normal;\n font-style: normal;\n font-size: 18px;\n color: rgba(0, 0, 0, 0.12);\n vertical-align: bottom;\n margin-left: 6px;\n}"
|
||||
},
|
||||
|
||||
@ -15,14 +15,13 @@
|
||||
///
|
||||
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef, forwardRef,
|
||||
ElementRef,
|
||||
forwardRef,
|
||||
NgZone,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewContainerRef
|
||||
} from '@angular/core';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
@ -47,7 +46,8 @@ import {
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
BrokerSecurityType,
|
||||
BrokerSecurityTypeTranslationsMap, noLeadTrailSpacesRegex,
|
||||
BrokerSecurityTypeTranslationsMap,
|
||||
noLeadTrailSpacesRegex
|
||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@ -69,7 +69,7 @@ import { takeUntil } from 'rxjs/operators';
|
||||
}
|
||||
]
|
||||
})
|
||||
export class BrokerSecurityComponent extends PageComponent implements ControlValueAccessor, Validator, AfterViewInit, OnInit, OnDestroy {
|
||||
export class BrokerSecurityComponent extends PageComponent implements ControlValueAccessor, Validator, OnDestroy {
|
||||
|
||||
BrokerSecurityType = BrokerSecurityType;
|
||||
|
||||
@ -115,18 +115,12 @@ export class BrokerSecurityComponent extends PageComponent implements ControlVal
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
///
|
||||
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
@ -40,7 +39,8 @@ import { UtilsService } from '@core/services/utils.service';
|
||||
import { EntityService } from '@core/http/entity.service';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder, NG_VALIDATORS,
|
||||
FormBuilder,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
UntypedFormGroup,
|
||||
ValidationErrors,
|
||||
@ -73,7 +73,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
|
||||
}
|
||||
]
|
||||
})
|
||||
export class DeviceInfoTableComponent extends PageComponent implements ControlValueAccessor, Validator, AfterViewInit, OnInit, OnDestroy {
|
||||
export class DeviceInfoTableComponent extends PageComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy {
|
||||
|
||||
SourceTypeTranslationsMap = SourceTypeTranslationsMap;
|
||||
|
||||
@ -156,9 +156,6 @@ export class DeviceInfoTableComponent extends PageComponent implements ControlVa
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
@ -15,26 +15,31 @@
|
||||
///
|
||||
|
||||
import {
|
||||
AfterViewInit,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Renderer2
|
||||
} from '@angular/core';
|
||||
import { isEqual } from '@core/utils';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { WINDOW } from '@core/services/window.service';
|
||||
import { fromEvent, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Directive({
|
||||
// eslint-disable-next-line @angular-eslint/directive-selector
|
||||
selector: '[tb-ellipsis-chip-list]'
|
||||
})
|
||||
export class EllipsisChipListDirective implements AfterViewInit, OnDestroy {
|
||||
export class EllipsisChipListDirective implements OnDestroy {
|
||||
|
||||
chipsValue: string[];
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
@Input('tb-ellipsis-chip-list')
|
||||
set chips(value: any[]) {
|
||||
set chips(value: string[]) {
|
||||
if (!isEqual(this.chipsValue, value)) {
|
||||
this.chipsValue = value;
|
||||
setTimeout(() => {
|
||||
@ -45,11 +50,15 @@ export class EllipsisChipListDirective implements AfterViewInit, OnDestroy {
|
||||
|
||||
constructor(private el: ElementRef,
|
||||
private renderer: Renderer2,
|
||||
private translate: TranslateService) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
private translate: TranslateService,
|
||||
@Inject(WINDOW) private window: Window) {
|
||||
this.renderer.setStyle(this.el.nativeElement, 'max-height', '48px');
|
||||
this.renderer.setStyle(this.el.nativeElement, 'overflow', 'auto');
|
||||
fromEvent(window, 'resize').pipe(
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe(() => {
|
||||
this.adjustChips();
|
||||
window.addEventListener('resize', this.adjustChips.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
private adjustChips(): void {
|
||||
@ -58,17 +67,16 @@ export class EllipsisChipListDirective implements AfterViewInit, OnDestroy {
|
||||
const chipNodes = chipListElement.querySelectorAll('mat-chip:not(.ellipsis-chip)');
|
||||
const ellipsisChip = this.el.nativeElement.querySelector('.ellipsis-chip');
|
||||
this.renderer.setStyle(ellipsisChip,'display', 'inline-flex');
|
||||
ellipsisText.innerHTML = this.translate.instant('gateway.ellipsis-chips-text',
|
||||
{count: (this.chipsValue.length)});
|
||||
|
||||
const margin = parseFloat(window.getComputedStyle(ellipsisChip).marginLeft) | 0;
|
||||
const margin = parseFloat(this.window.getComputedStyle(ellipsisChip).marginLeft) || 0;
|
||||
const availableWidth = chipListElement.offsetWidth - (ellipsisChip.offsetWidth + margin);
|
||||
let usedWidth = 0;
|
||||
let visibleChipsCount = 0;
|
||||
|
||||
chipNodes.forEach((chip) => {
|
||||
this.renderer.setStyle(chip, 'display', 'inline-flex');
|
||||
});
|
||||
|
||||
chipNodes.forEach((chip) => {
|
||||
if ((usedWidth + (chip.offsetWidth + margin) <= availableWidth) && (visibleChipsCount < this.chipsValue.length)) {
|
||||
visibleChipsCount++;
|
||||
usedWidth += chip.offsetWidth + margin;
|
||||
@ -85,7 +93,8 @@ export class EllipsisChipListDirective implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
window.removeEventListener('resize', this.adjustChips.bind(this));
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,10 @@
|
||||
<div class="tb-form-panel stroked">
|
||||
<div class="tb-form-panel-title" translate>gateway.platform-side</div>
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
<div class="fixed-title-width tb-required" translate>gateway.key</div>
|
||||
<div class="fixed-title-width tb-required"
|
||||
tb-hint-tooltip-icon="{{ 'gateway.JSONPath-hint' | translate }}" translate>
|
||||
gateway.key
|
||||
</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput name="value" formControlName="key" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
@ -89,7 +92,10 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
<div class="fixed-title-width tb-required" translate>gateway.value</div>
|
||||
<div class="fixed-title-width tb-required"
|
||||
tb-hint-tooltip-icon="{{ 'gateway.JSONPath-hint' | translate }}" translate>
|
||||
gateway.value
|
||||
</div>
|
||||
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-flex no-gap">
|
||||
<input matInput required formControlName="value"
|
||||
placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
|
||||
@ -26,9 +26,6 @@
|
||||
<mat-icon class="material-icons">close</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
||||
</mat-progress-bar>
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<div mat-dialog-content>
|
||||
<div class="tb-form-panel no-border no-padding" fxLayout="column">
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
@ -91,13 +88,12 @@
|
||||
<button mat-button color="primary"
|
||||
type="button"
|
||||
cdkFocusInitial
|
||||
[disabled]="(isLoading$ | async)"
|
||||
(click)="cancel()">
|
||||
{{ 'action.cancel' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button color="primary"
|
||||
(click)="add()"
|
||||
[disabled]="(isLoading$ | async) || connectorForm.invalid || !connectorForm.dirty">
|
||||
[disabled]="connectorForm.invalid || !connectorForm.dirty">
|
||||
{{ 'action.add' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, Inject, OnDestroy } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
@ -23,7 +23,9 @@ import { BaseData, HasId } from '@shared/models/base-data';
|
||||
import { DialogComponent } from '@shared/components/dialog.component';
|
||||
import { Router } from '@angular/router';
|
||||
import {
|
||||
AddConnectorConfigData,
|
||||
ConnectorType,
|
||||
CreatedConnectorConfigData,
|
||||
GatewayConnectorDefaultTypesTranslatesMap,
|
||||
GatewayLogLevel,
|
||||
getDefaultConfig,
|
||||
@ -38,7 +40,7 @@ import { ResourcesService } from '@core/services/resources.service';
|
||||
styleUrls: ['./add-connector-dialog.component.scss'],
|
||||
providers: [],
|
||||
})
|
||||
export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDialogComponent, BaseData<HasId>> implements OnInit, OnDestroy {
|
||||
export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDialogComponent, BaseData<HasId>> implements OnDestroy {
|
||||
|
||||
connectorForm: UntypedFormGroup;
|
||||
|
||||
@ -53,8 +55,8 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
public dialogRef: MatDialogRef<AddConnectorDialogComponent, any>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: AddConnectorConfigData,
|
||||
public dialogRef: MatDialogRef<AddConnectorDialogComponent, CreatedConnectorConfigData>,
|
||||
private fb: FormBuilder,
|
||||
private resourcesService: ResourcesService) {
|
||||
super(store, router, dialogRef);
|
||||
@ -67,9 +69,6 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
|
||||
@ -139,7 +139,10 @@
|
||||
</div>
|
||||
<div class="tb-form-panel no-border no-padding" *ngIf="converterType === ConvertorTypeEnum.CUSTOM">
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
<div class="fixed-title-width tb-required" translate>gateway.extension</div>
|
||||
<div class="fixed-title-width tb-required"
|
||||
tb-hint-tooltip-icon="{{ 'gateway.extension-hint' | translate }}" translate>
|
||||
gateway.extension
|
||||
</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput name="value" formControlName="extension" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
@ -237,6 +240,9 @@
|
||||
<ng-template [ngSwitchCase]="RequestTypeEnum.ATTRIBUTE_REQUEST">
|
||||
<div class="tb-form-panel stroked">
|
||||
<div class="tb-form-panel-title tb-required" translate>gateway.from-device-request-settings</div>
|
||||
<div class="tb-form-hint tb-primary-fill" translate>
|
||||
gateway.from-device-request-settings-hint
|
||||
</div>
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center" formGroupName="deviceInfo">
|
||||
<div class="fixed-title-width tb-flex no-flex align-center" translate>
|
||||
<div class="tb-required" translate>gateway.device-info.device-name-expression</div>
|
||||
@ -302,6 +308,9 @@
|
||||
</div>
|
||||
<div class="tb-form-panel stroked">
|
||||
<div class="tb-form-panel-title tb-required" translate>gateway.to-device-response-settings</div>
|
||||
<div class="tb-form-hint tb-primary-fill" translate>
|
||||
gateway.to-device-response-settings-hint
|
||||
</div>
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
<div class="fixed-title-width tb-required" translate>gateway.response-value-expression</div>
|
||||
<div class="tb-flex no-gap">
|
||||
@ -359,7 +368,10 @@
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="RequestTypeEnum.ATTRIBUTE_UPDATE">
|
||||
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
|
||||
<div class="fixed-title-width tb-required" translate>gateway.device-name-filter</div>
|
||||
<div class="fixed-title-width tb-required"
|
||||
tb-hint-tooltip-icon="{{ 'gateway.device-name-filter-hint' | translate }}" translate>
|
||||
gateway.device-name-filter
|
||||
</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput name="value" formControlName="deviceNameFilter" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
|
||||
.mat-mdc-dialog-content {
|
||||
max-height: 670px;
|
||||
height: 670px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnDestroy, OnInit, Renderer2, ViewContainerRef } from '@angular/core';
|
||||
import { Component, Inject, OnDestroy, Renderer2, ViewContainerRef } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
@ -27,7 +27,6 @@ import {
|
||||
ConvertorTypeTranslationsMap,
|
||||
DataConversionTranslationsMap,
|
||||
DeviceInfoType,
|
||||
MappingDataKey,
|
||||
MappingHintTranslationsMap,
|
||||
MappingInfo,
|
||||
MappingKeysAddKeyTranslationsMap,
|
||||
@ -58,7 +57,7 @@ import { MappingDataKeysPanelComponent } from '@home/components/widget/lib/gatew
|
||||
styleUrls: ['./mapping-dialog.component.scss'],
|
||||
providers: [],
|
||||
})
|
||||
export class MappingDialogComponent extends DialogComponent<MappingDialogComponent, BaseData<HasId>> implements OnInit, OnDestroy {
|
||||
export class MappingDialogComponent extends DialogComponent<MappingDialogComponent, BaseData<HasId>> implements OnDestroy {
|
||||
|
||||
mappingForm: UntypedFormGroup;
|
||||
|
||||
@ -118,7 +117,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
|
||||
}
|
||||
}
|
||||
|
||||
get converterTelemetry(): Array<MappingDataKey> {
|
||||
get converterTelemetry(): Array<string> {
|
||||
if (this.converterType) {
|
||||
return this.mappingForm.get('converter').get(this.converterType).value.timeseries.map(value => value.key);
|
||||
}
|
||||
@ -128,7 +127,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
|
||||
return this.mappingForm.get('converter').get('type').value;
|
||||
}
|
||||
|
||||
get customKeys(): {[key: string]: any} {
|
||||
get customKeys(): Array<string> {
|
||||
return Object.keys(this.mappingForm.get('converter').get('custom').value.extensionConfig);
|
||||
}
|
||||
|
||||
@ -136,9 +135,6 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
|
||||
return this.mappingForm.get('requestType').value;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
<span class="dot"
|
||||
matTooltip="{{ 'Errors: '+ getErrorsCount(attribute)}}"
|
||||
matTooltipPosition="above"
|
||||
(click)="connectorLogs(attribute, $event)"
|
||||
[class]="{'hasErrors': +getErrorsCount(attribute) > 0,
|
||||
'noErrors': +getErrorsCount(attribute) === 0 || getErrorsCount(attribute) === ''}"></span>
|
||||
</mat-cell>
|
||||
@ -127,7 +128,7 @@
|
||||
<mat-icon>private_connectivity</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button
|
||||
matTooltip="Delete connector"
|
||||
matTooltip="Logs"
|
||||
matTooltipPosition="above"
|
||||
(click)="connectorLogs(attribute, $event)">
|
||||
<mat-icon>list</mat-icon>
|
||||
@ -192,7 +193,7 @@
|
||||
<div class="tb-form-panel stroked">
|
||||
<div class="tb-form-panel-title" translate>gateway.logs-configuration</div>
|
||||
<div class="tb-form-row" fxLayoutAlign="space-between center">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="sendDataOnlyOnChange">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="enableRemoteLogging">
|
||||
<mat-label>
|
||||
{{ 'gateway.enable-remote-logging' | translate }}
|
||||
</mat-label>
|
||||
@ -245,13 +246,15 @@
|
||||
<div class="fixed-title-width tb-required" translate>gateway.port</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput type="number" min="0" name="value" formControlName="port" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
<input matInput type="number" min="{{portLimits.MIN}}" max="{{portLimits.MAX}}"
|
||||
name="value" formControlName="port" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="portErrorTooltip | translate"
|
||||
[matTooltip]="portErrorTooltip"
|
||||
*ngIf="(connectorForm.get('basicConfig.broker.port').hasError('required') ||
|
||||
connectorForm.get('basicConfig.broker.port').hasError('min')) &&
|
||||
connectorForm.get('basicConfig.broker.port').hasError('min') ||
|
||||
connectorForm.get('basicConfig.broker.port').hasError('max')) &&
|
||||
connectorForm.get('basicConfig.broker.port').touched"
|
||||
class="tb-error">
|
||||
warning
|
||||
|
||||
@ -56,7 +56,8 @@ import {
|
||||
GatewayLogLevel,
|
||||
MappingType,
|
||||
MqttVersions,
|
||||
noLeadTrailSpacesRegex
|
||||
noLeadTrailSpacesRegex,
|
||||
PortLimits
|
||||
} from './gateway-widget.models';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway/dialog/add-connector-dialog.component';
|
||||
@ -110,6 +111,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
|
||||
mappingTypes = MappingType;
|
||||
|
||||
portLimits = PortLimits;
|
||||
|
||||
mode: ConnectorConfigurationModes = this.connectorConfigurationModes.BASIC;
|
||||
|
||||
initialConnector: GatewayConnector;
|
||||
@ -180,9 +183,13 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
|
||||
get portErrorTooltip(): string {
|
||||
if (this.connectorForm.get('basicConfig.broker.port').hasError('required')) {
|
||||
return 'gateway.port-required';
|
||||
} else if (this.connectorForm.get('basicConfig.broker.port').hasError('min')) {
|
||||
return 'gateway.only-natural-numbers';
|
||||
return this.translate.instant('gateway.port-required');
|
||||
} else if (
|
||||
this.connectorForm.get('basicConfig.broker.port').hasError('min') ||
|
||||
this.connectorForm.get('basicConfig.broker.port').hasError('max')
|
||||
) {
|
||||
return this.translate.instant('gateway.port-limits-error',
|
||||
{min: PortLimits.MIN, max: PortLimits.MAX});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -418,10 +425,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.confirmConnectorChange().subscribe((result) => {
|
||||
if (result) {
|
||||
const connector = attribute.value;
|
||||
if (connector?.name !== this.initialConnector?.name) {
|
||||
this.confirmConnectorChange().subscribe((result) => {
|
||||
if (result) {
|
||||
if (this.connectorForm.disabled) {
|
||||
this.connectorForm.enable();
|
||||
}
|
||||
@ -447,9 +454,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
this.connectorForm.patchValue(connector, {emitEvent: false});
|
||||
this.connectorForm.markAsPristine();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isSameConnector(attribute: AttributeData): boolean {
|
||||
if (!this.initialConnector) {
|
||||
@ -573,6 +580,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.confirmConnectorChange().subscribe((changeConfirmed) => {
|
||||
if (changeConfirmed) {
|
||||
return this.dialog.open<AddConnectorDialogComponent,
|
||||
AddConnectorConfigData>(AddConnectorDialogComponent, {
|
||||
disableClose: true,
|
||||
@ -581,7 +590,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
dataSourceData: this.dataSource.data
|
||||
}
|
||||
}).afterClosed().subscribe((value) => {
|
||||
this.confirmConnectorChange().subscribe((changeConfirmed) => {
|
||||
if (value && changeConfirmed) {
|
||||
this.initialConnector = null;
|
||||
if (this.connectorForm.disabled) {
|
||||
@ -600,7 +608,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
this.generate('basicConfig.broker.clientId');
|
||||
this.saveConnector();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -648,7 +657,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
|
||||
const brokerGroup = this.fb.group({
|
||||
name: ['', []],
|
||||
host: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
port: [null, [Validators.required, Validators.min(0)]],
|
||||
port: [null, [Validators.required, Validators.min(PortLimits.MIN), Validators.max(PortLimits.MAX)]],
|
||||
version: [5, []],
|
||||
clientId: ['', [Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
maxNumberOfWorkers: [100, [Validators.required, Validators.min(1)]],
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
import { ResourcesService } from '@core/services/resources.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ValueTypeData } from '@shared/models/constants';
|
||||
import { Validators } from '@angular/forms';
|
||||
|
||||
export const noLeadTrailSpacesRegex: RegExp = /^(?! )[\S\s]*(?<! )$/;
|
||||
|
||||
@ -39,6 +40,11 @@ export enum GatewayLogLevel {
|
||||
DEBUG = 'DEBUG'
|
||||
}
|
||||
|
||||
export enum PortLimits {
|
||||
MIN = 1,
|
||||
MAX = 65535
|
||||
}
|
||||
|
||||
export const GatewayStatus = {
|
||||
...GatewayLogLevel,
|
||||
...DeviceGatewayStatus
|
||||
@ -314,6 +320,15 @@ export interface AddConnectorConfigData {
|
||||
dataSourceData: Array<any>
|
||||
}
|
||||
|
||||
export interface CreatedConnectorConfigData {
|
||||
type: ConnectorType,
|
||||
name: string,
|
||||
logLevel: GatewayLogLevel,
|
||||
useDefaults: boolean,
|
||||
sendDataOnlyOnChange: boolean,
|
||||
configurationJson?: {[key: string]: any}
|
||||
}
|
||||
|
||||
export interface MappingDataKey {
|
||||
key: string,
|
||||
value: any,
|
||||
|
||||
@ -94,6 +94,3 @@ For bytes converter, expression fields can use slices format only. A slice speci
|
||||
| AM123,mytype,12.2,45 | [:] | AM123,mytype,12.2,45 | Extracting all data |
|
||||
| AM123,mytype,12.2,45 | [18:] | 45 | Extracting humidity value |
|
||||
| AM123,mytype,12.2,45 | [13:17] | 12.2 | Extracting temperature value |
|
||||
|
||||
|
||||
For more information about MQTT connector configuration use the [official documentation](https://thingsboard.io/docs/iot-gateway/config/mqtt/?MqttConverterTypeConfig=json#subsection-security).
|
||||
|
||||
@ -2713,7 +2713,7 @@
|
||||
"advanced": "Advanced",
|
||||
"attributes": "Attributes",
|
||||
"attribute-filter": "Attribute filter",
|
||||
"attribute-filter-hint": "Filter for incoming attribute name from ThingsBoard, supports regular expression.",
|
||||
"attribute-filter-hint": "Filter for incoming attribute name from platform, supports regular expression.",
|
||||
"attribute-filter-required": "Attribute filter required.",
|
||||
"attribute-name-expression": "Attribute name expression",
|
||||
"attribute-name-expression-required": "Attribute name expression required.",
|
||||
@ -2773,7 +2773,7 @@
|
||||
"device-profile-expression-required": "Device profile expression required."
|
||||
},
|
||||
"device-name-filter": "Device name filter",
|
||||
"device-name-filter-hint": "Regular expression for device name.",
|
||||
"device-name-filter-hint": "This field supports Regular expressions to filter incoming data by device name.",
|
||||
"device-name-filter-required": "Device name filter is required.",
|
||||
"details": "Details",
|
||||
"delete-mapping-title": "Delete mapping ?",
|
||||
@ -2816,13 +2816,16 @@
|
||||
"download-tip": "Download configuration file",
|
||||
"drop-file": "Drop file here or",
|
||||
"extension": "Extension",
|
||||
"extension-hint": "Put your converter classname in the field. Custom converter with such class should be in extension/mqtt folder.",
|
||||
"extension-required": "Extension is required.",
|
||||
"extension-configuration": "Extension configuration",
|
||||
"extension-configuration-hint": "Configuration for convertor",
|
||||
"fill-connector-defaults": "Fill configuration with default values",
|
||||
"fill-connector-defaults-hint": "This property allows to fill connector configuration with default values on it's creation.",
|
||||
"from-device-request-settings": "Input request parsing",
|
||||
"to-device-response-settings": "Output request handling",
|
||||
"from-device-request-settings-hint": "These fields support JSONPath expressions to extract a name from incoming message.",
|
||||
"to-device-response-settings": "Output request processing",
|
||||
"to-device-response-settings-hint": "For these fields you can use the following variables and they will be replaced with actual values: ${deviceName}, ${attributeKey}, ${attributeValue}",
|
||||
"gateway": "Gateway",
|
||||
"gateway-exists": "Device with same name is already exists.",
|
||||
"gateway-name": "Gateway name",
|
||||
@ -2862,6 +2865,7 @@
|
||||
"host-required": "Host is required.",
|
||||
"json-parse": "Not valid JSON.",
|
||||
"json-required": "Field cannot be empty.",
|
||||
"JSONPath-hint": "This field supports constants and JSONPath expressions.",
|
||||
"logs": {
|
||||
"logs": "Logs",
|
||||
"days": "days",
|
||||
@ -2913,6 +2917,7 @@
|
||||
"permit-without-calls": "Keep alive permit without calls",
|
||||
"port": "Port",
|
||||
"port-required": "Port is required.",
|
||||
"port-limits-error": "Port should be number from {{min}} to {{max}}.",
|
||||
"private-key-path": "Path to private key file",
|
||||
"path-to-private-key-required": "Path to private key file is required.",
|
||||
"raw": "Raw",
|
||||
@ -3044,7 +3049,6 @@
|
||||
"with-response": "With response",
|
||||
"without-response": "Without response",
|
||||
"other": "Other",
|
||||
"only-natural-numbers": "Only natural numbers allowed.",
|
||||
"save-tip": "Save configuration file",
|
||||
"security": "Security",
|
||||
"security-type": "Security type",
|
||||
@ -3130,9 +3134,9 @@
|
||||
"key": "Key",
|
||||
"keys": "Keys",
|
||||
"key-required": "Key is required.",
|
||||
"thingsboard-host": "ThingsBoard host",
|
||||
"thingsboard-host": "Platform host",
|
||||
"thingsboard-host-required": "Host is required.",
|
||||
"thingsboard-port": "ThingsBoard port",
|
||||
"thingsboard-port": "Platform port",
|
||||
"thingsboard-port-max": "Maximum port number is 65535.",
|
||||
"thingsboard-port-min": "Minimum port number is 1.",
|
||||
"thingsboard-port-pattern": "Port is not valid.",
|
||||
@ -3146,7 +3150,7 @@
|
||||
"tls-path-ca-certificate": "Path to CA certificate on gateway",
|
||||
"tls-path-client-certificate": "Path to client certificate on gateway",
|
||||
"method-filter": "Method filter",
|
||||
"method-filter-hint": "Regular expression for RPC method.",
|
||||
"method-filter-hint": "Regular expression to filter incoming RPC method from platform.",
|
||||
"method-filter-required": "Method filter is required.",
|
||||
"messages-ttl-check-in-hours": "Messages TTL check in hours",
|
||||
"messages-ttl-check-in-hours-required": "Messages TTL check in hours is required.",
|
||||
@ -3173,12 +3177,12 @@
|
||||
"hints": {
|
||||
"remote-configuration": "Enables remote configuration and management of the gateway",
|
||||
"remote-shell": "Enables remote control of the operating system with the gateway from the Remote Shell widget",
|
||||
"host": "Hostname or IP address of ThingsBoard server",
|
||||
"port": "Port of MQTT service on ThingsBoard server",
|
||||
"token": "Access token for the gateway from ThingsBoard server",
|
||||
"client-id": "MQTT client id for the gateway form ThingsBoard server",
|
||||
"username": "MQTT username for the gateway form ThingsBoard server",
|
||||
"password": "MQTT password for the gateway form ThingsBoard server",
|
||||
"host": "Hostname or IP address of platform server",
|
||||
"port": "Port of MQTT service on platform server",
|
||||
"token": "Access token for the gateway from platform server",
|
||||
"client-id": "MQTT client id for the gateway form platform server",
|
||||
"username": "MQTT username for the gateway form platform server",
|
||||
"password": "MQTT password for the gateway form platform server",
|
||||
"ca-cert": "Path to CA certificate file",
|
||||
"date-form": "Date format in log message",
|
||||
"data-folder": "Path to folder, that will contains data (Relative or Absolute)",
|
||||
@ -3187,10 +3191,10 @@
|
||||
"backup-count": "If backup count is > 0, when a rollover is done, no more than backup count files are kept - the oldest ones are deleted",
|
||||
"storage": "Provides configuration for saving incoming data before it is sent to the platform",
|
||||
"max-file-count": "Maximum count of file that will be created",
|
||||
"max-read-count": "Count of messages to get from storage and send to ThingsBoard",
|
||||
"max-read-count": "Count of messages to get from storage and send to platform",
|
||||
"max-records": "Maximum count of records that will be stored in one file",
|
||||
"read-record-count": "Count of messages to get from storage and send to ThingsBoard",
|
||||
"max-records-count": "Maximum count of data in storage before send to ThingsBoard",
|
||||
"read-record-count": "Count of messages to get from storage and send to platform",
|
||||
"max-records-count": "Maximum count of data in storage before send to platform",
|
||||
"ttl-check-hour": "How often will Gateway check data for obsolescence",
|
||||
"ttl-messages-day": "Maximum days that storage will save data",
|
||||
"commands": "Commands for collecting additional statistic",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user