UI: Updated gateway dashboard to use new tb-resources

This commit is contained in:
Vladyslav_Prykhodko 2024-11-11 18:47:34 +02:00
parent cfce9b8950
commit 8d6906f286
3 changed files with 21 additions and 14 deletions

View File

@ -1,6 +1,6 @@
{
"title": "ThingsBoard IoT Gateways",
"image": "tb-image:Z2F0ZXdheS1kYXNoYm9hcmRfKDEpLnBuZw==:Z2F0ZXdheS1kYXNoYm9hcmQucG5n;data:image/png;base64,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",
"image": "tb-image;/api/images/system/gateway-dashboard.png",
"mobileHide": false,
"mobileOrder": 6,
"configuration": {
@ -186,10 +186,15 @@
"useShowWidgetActionFunction": null,
"showWidgetActionFunction": "return true;",
"type": "customPretty",
"customHtml": "<div class=\"container\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>{{ 'gateway.launch-command' | translate }}</h2>\n <span fxFlex></span>\n <div [tb-help]=\"'gatewayInstall'\"></div>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <tb-gateway-command [deviceId]=\"entityId\"></tb-gateway-command>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n (click)=\"cancel()\" cdkFocusInitial>\n {{ 'action.close' | translate }}\n </button>\n </div>\n</div>\n",
"customHtml": "<div class=\"container\">\n <mat-toolbar class=\"flex flex-row items-center\" color=\"primary\">\n <h2>{{ 'gateway.launch-command' | translate }}</h2>\n <span class=\"flex-1\"></span>\n <div [tb-help]=\"'gatewayInstall'\"></div>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <tb-gateway-command [deviceId]=\"entityId\"></tb-gateway-command>\n <div mat-dialog-actions class=\"flex flex-row justify-end items-center\">\n <button mat-button color=\"primary\" type=\"button\" (click)=\"cancel()\" cdkFocusInitial>\n {{ 'action.close' | translate }}\n </button>\n </div>\n</div>\n",
"customCss": ".container {\n display: grid;\n grid-template-rows: min-content minmax(auto, 1fr) min-content;\n height: 100%;\n max-height: 100vh;\n width: 600px;\n max-width: 100%;\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\n\nopenCommands();\n\nfunction openCommands() {\n customDialog.customDialog(htmlTemplate, CommandsDialogController, {panelClass: \"test\"}).subscribe();\n}\n\nfunction CommandsDialogController(instance) {\n let vm = instance;\n \n vm.entityId = entityId.id;\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n}\n",
"customResources": [],
"customResources": [
{
"url": "tb-resource;/api/resource/js_module/system/gateway-management-extension.js",
"isModule": true
}
],
"openInSeparateDialog": false,
"openInPopover": false,
"id": "ae2e5995-505f-a241-5fb2-6cbaf08b1b55"
@ -203,7 +208,12 @@
"customHtml": "<mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n</mat-progress-bar>\n<tb-gateway-configuration\n class=\"gateway-config\"\n mat-dialog-content\n [device]=\"device\"\n [dialogRef]=\"dialogRef\">\n</tb-gateway-configuration>",
"customCss": ".gateway-config {\n width: 800px !important;\n padding: 0 !important;\n min-height: 75vh;\n max-width: 100%;\n display: grid !important;\n}\n\n@media screen and (max-width: 599px) {\n .mat-mdc-dialog-content {\n max-height: calc(100% - 60px) !important;\n }\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\n\nopenAddEntityDialog();\n\nfunction openAddEntityDialog() {\n customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();\n}\n\nfunction AddEntityDialogController(instance) {\n let vm = instance;\n \n vm.device = additionalParams.entity.id;\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n}\n",
"customResources": [],
"customResources": [
{
"url": "tb-resource;/api/resource/js_module/system/gateway-management-extension.js",
"isModule": true
}
],
"openInSeparateDialog": false,
"openInPopover": false,
"id": "a54acd30-5c5f-d709-b892-5fc14f780e34"
@ -246,7 +256,7 @@
"useShowWidgetActionFunction": null,
"showWidgetActionFunction": "return true;",
"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",
"customHtml": "<form #addEntityForm=\"ngForm\" [formGroup]=\"addEntityFormGroup\"\r\n (ngSubmit)=\"save($event)\" class=\"add-entity-form\">\r\n <mat-toolbar class=\"flex flex-row items-center\" color=\"primary\">\r\n <h2>Add gateway</h2>\r\n <span class=\"flex-1\"></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 class=\"h-1\" *ngIf=\"!(isLoading$ | async)\"></div>\r\n <div mat-dialog-content class=\"flex flex-col\">\r\n <div class=\"flex flex-row gap-2 flex-wrap\" >\r\n <mat-form-field class=\"w-full sm:w-auto\">\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 class=\"flex flex-row gap-2 flex-wrap\">\r\n <tb-entity-subtype-autocomplete\r\n class=\"w-full sm:w-auto\"\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 class=\"flex flex-row justify-end items-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 == \"Launch command\");\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": [],
@ -592,7 +602,7 @@
"settings": {
"useMarkdownTextFunction": true,
"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>`;",
"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 class=\"flex flex-row flex-wrap gap-2 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}"
},
@ -1916,15 +1926,12 @@
"useShowWidgetActionFunction": null,
"showWidgetActionFunction": "return true;",
"type": "customPretty",
"customHtml": "<div class=\"container\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>{{ 'gateway.launch-command' | translate }}</h2>\n <span fxFlex></span>\n <div [tb-help]=\"'gatewayInstall'\"></div>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <tb-gateway-command [deviceId]=\"entityId\"></tb-gateway-command>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n (click)=\"cancel()\" cdkFocusInitial>\n {{ 'action.close' | translate }}\n </button>\n </div>\n</div>\n",
"customHtml":"<div class=\"container\">\n <mat-toolbar class=\"flex flex-row items-center\" color=\"primary\">\n <h2>{{ 'gateway.launch-command' | translate }}</h2>\n <span class=\"flex-1\"></span>\n <div [tb-help]=\"'gatewayInstall'\"></div>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <tb-gateway-command [deviceId]=\"entityId\"></tb-gateway-command>\n <div mat-dialog-actions class=\"flex flex-row justify-end items-center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n (click)=\"cancel()\" cdkFocusInitial>\n {{ 'action.close' | translate }}\n </button>\n </div>\n</div>\n",
"customCss": ".container {\n display: grid;\n grid-template-rows: min-content minmax(auto, 1fr) min-content;\n height: 100%;\n max-height: 100vh;\n width: 600px;\n max-width: 100%;\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\n\nopenCommands();\n\nfunction openCommands() {\n customDialog.customDialog(htmlTemplate, CommandsDialogController, {panelClass: \"test\"}).subscribe();\n}\n\nfunction CommandsDialogController(instance) {\n let vm = instance;\n \n vm.entityId = entityId.id;\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n}\n",
"customResources": [
{
"url": {
"entityType": "TB_RESOURCE",
"id": "tb-resource;/api/resource/js_module/system/gateway-management-extension.js"
},
"url": "tb-resource;/api/resource/js_module/system/gateway-management-extension.js",
"isModule": true
}
],
@ -2006,7 +2013,7 @@
"padding": "8px",
"settings": {
"useMarkdownTextFunction": true,
"markdownTextFunction": "let buttonsHtml = \"\" \nctx.actionsApi.getActionDescriptors('elementClick').forEach((btn, index)=>{\n let disabled =false;\n if (index == 2) {\n disabled = data[0] && data[0].RemoteLoggingLevel ? data[0].RemoteLoggingLevel == \"NONE\" : true;\n } else if (index == 4) {\n const conf = data[0].general_configuration? JSON.parse(data[0].general_configuration): {};\n disabled = !conf.remoteShell;\n }\n buttonsHtml += `<button mat-raised-button disabled=${disabled} color=\"primary\"(click)=\"ctx.actionsApi.handleWidgetAction($event, ctx.actionsApi.getActionDescriptors('elementClick')[${index}], ctx.datasources[0].entity.id)\" fxFlex fxflex.md=\"50\">${btn.displayName}</button>`\n});\n\nreturn `<div class=\"action-buttons-container\" fxLayout=\"columnd\" fxLayout.md=\"row wrap\" fxLayoutGap=\"5px\" >${buttonsHtml}</div>`;",
"markdownTextFunction": "let buttonsHtml = \"\" \nctx.actionsApi.getActionDescriptors('elementClick').forEach((btn, index)=>{\n let disabled = false;\n if (index == 2) {\n disabled = data[0] && data[0].RemoteLoggingLevel ? data[0].RemoteLoggingLevel == \"NONE\" : true;\n } else if (index == 4) {\n const conf = data[0].general_configuration ? JSON.parse(data[0].general_configuration) : {};\n disabled = !conf.remoteShell;\n }\n buttonsHtml += `<button mat-raised-button disabled=${disabled} color=\"primary\" (click)=\"ctx.actionsApi.handleWidgetAction($event, ctx.actionsApi.getActionDescriptors('elementClick')[${index}], ctx.datasources[0].entity.id)\" class=\"w-full md:w-1/2\">${btn.displayName}</button>`\n});\n\nreturn `<div class=\"action-buttons-container flex flex-col md:flex-row flex-wrap gap-1\">${buttonsHtml}</div>`;",
"applyDefaultMarkdownStyle": false,
"markdownCss": ".action-buttons-container {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex-direction: row;\r\n height: 100%;\r\n width: 100%;\r\n align-content: start;\r\n}\r\n\r\nbutton {\r\n flex-grow: 1;\r\n margin: 10px;\r\n min-width: 150px;\r\n height: auto;\r\n line-height: 36px;\n}"
},
@ -2613,7 +2620,7 @@
"padding": "0px",
"settings": {
"useMarkdownTextFunction": false,
"markdownTextPattern": "<div style=\"width: 100%; height: 100%; padding: 0;\" fxFlex fxLayout=\"column\">\n <mat-tab-group class=devices-tabs>\n <mat-tab label=\"All\" value=\"gateway_devices_0\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_0\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${mqttCount}\" label=\"MQTT\" value=\"gateway_devices_1\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_1\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${modbusCount}\" label=\"MODBUS\" value=\"gateway_devices_2\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_2\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${grpcCount}\" label=\"GRPC\" value=\"gateway_devices_3\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_3\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${opcuaCount}\" label=\"OPCUA\" value=\"gateway_devices_4\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_4\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${bleCount}\" label=\"BLE\" value=\"gateway_devices_6\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_6\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${requestCount}\" label=\"REQUEST\" value=\"gateway_devices_7\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_7\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${canCount}\" label=\"CAN\" value=\"gateway_devices_8\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_8\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${bacnetCount}\" label=\"BACNET\" value=\"gateway_devices_9\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_9\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${odbcCount}\" label=\"ODBC\" value=\"gateway_devices_10\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_10\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${restCount}\" label=\"REST\" value=\"gateway_devices_11\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_11\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${snmpCount}\" label=\"SNMP\" value=\"gateway_devices_12\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_12\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${ftpCount}\" label=\"FTP\" value=\"gateway_devices_13\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_13\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${socketCount}\" label=\"SOCKET\" value=\"gateway_devices_14\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_14\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${xmppCount}\" label=\"XMPP\" value=\"gateway_devices_15\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_15\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${ocppCount}\" label=\"OCPP\" value=\"gateway_devices_16\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_16\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${customCount}\" label=\"CUSTOM\" value=\"gateway_devices_17\">\n <tb-dashboard-state [ctx]=\"ctx\" fxFlex syncParentStateParams=\"true\" stateId=\"gateway_devices_17\"></tb-dashboard-state>\n </mat-tab>\n </mat-tab-group>\n</div>\n",
"markdownTextPattern": "<div style=\"width: 100%; height: 100%; padding: 0;\" class=\"flex flex-col\">\n <mat-tab-group class=\"devices-tabs\">\n <mat-tab label=\"All\" value=\"gateway_devices_0\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_0\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${mqttCount}\" label=\"MQTT\" value=\"gateway_devices_1\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_1\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${modbusCount}\" label=\"MODBUS\" value=\"gateway_devices_2\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_2\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${grpcCount}\" label=\"GRPC\" value=\"gateway_devices_3\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_3\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${opcuaCount}\" label=\"OPCUA\" value=\"gateway_devices_4\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_4\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${bleCount}\" label=\"BLE\" value=\"gateway_devices_6\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_6\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${requestCount}\" label=\"REQUEST\" value=\"gateway_devices_7\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_7\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${canCount}\" label=\"CAN\" value=\"gateway_devices_8\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_8\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${bacnetCount}\" label=\"BACNET\" value=\"gateway_devices_9\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_9\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${odbcCount}\" label=\"ODBC\" value=\"gateway_devices_10\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_10\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${restCount}\" label=\"REST\" value=\"gateway_devices_11\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_11\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${snmpCount}\" label=\"SNMP\" value=\"gateway_devices_12\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_12\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${ftpCount}\" label=\"FTP\" value=\"gateway_devices_13\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_13\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${socketCount}\" label=\"SOCKET\" value=\"gateway_devices_14\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_14\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${xmppCount}\" label=\"XMPP\" value=\"gateway_devices_15\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_15\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${ocppCount}\" label=\"OCPP\" value=\"gateway_devices_16\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_16\"></tb-dashboard-state>\n </mat-tab>\n <mat-tab *ngIf=\"${customCount}\" label=\"CUSTOM\" value=\"gateway_devices_17\">\n <tb-dashboard-state [ctx]=\"ctx\" class=\"flex-1\" syncParentStateParams=\"true\" stateId=\"gateway_devices_17\"></tb-dashboard-state>\n </mat-tab>\n </mat-tab-group>\n</div>\n",
"applyDefaultMarkdownStyle": false,
"markdownCss": ".mat-mdc-form-field-subscript-wrapper {\n display: none !important;\n}\n\n.devices-tabs {\n height: 100%;\n}\n\n::ng-deep .mat-mdc-tab-body-wrapper {\n height: 100%;\n}"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

File diff suppressed because one or more lines are too long