Commit 12667d89eaa523bfe48f1d7ae3749ee4c77cedd8
Merge branch 'master' of github.com:thingsboard/thingsboard
Showing
70 changed files
with
2960 additions
and
161 deletions
... | ... | @@ -18,7 +18,7 @@ |
18 | 18 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
21 | - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Device admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Device admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add device\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"addDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"addDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addDeviceForm.invalid || !addDeviceForm.dirty\\\">\\n Create\\n </button>\\n <button mat-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddDeviceDialog();\\n\\nfunction openAddDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();\\n}\\n\\nfunction AddDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.addDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addDeviceFormGroup.markAsPristine();\\n let device = {\\n name: vm.addDeviceFormGroup.get('deviceName').value,\\n type: vm.addDeviceFormGroup.get('deviceType').value,\\n label: vm.addDeviceFormGroup.get('deviceLabel').value\\n };\\n deviceService.saveDevice(device).subscribe(\\n function (device) {\\n saveAttributes(device.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit device\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"editDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"editDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || editDeviceForm.invalid || !editDeviceForm.dirty\\\">\\n Update\\n </button>\\n <button mat-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditDeviceDialog();\\n\\nfunction openEditDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();\\n}\\n\\nfunction EditDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.device = null;\\n vm.attributes = {};\\n \\n vm.editDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editDeviceFormGroup.markAsPristine();\\n vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,\\n vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,\\n vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value\\n deviceService.saveDevice(vm.device).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n deviceService.getDevice(entityId.id).subscribe(\\n function (device) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.device = device;\\n vm.editDeviceFormGroup.patchValue(\\n {\\n deviceName: vm.device.name,\\n deviceType: vm.device.type,\\n deviceLabel: vm.device.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete device\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\n\\nopenDeleteDeviceDialog();\\n\\nfunction openDeleteDeviceDialog() {\\n let title = \\\"Are you sure you want to delete the device \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the device and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteDevice();\\n }\\n }\\n );\\n}\\n\\nfunction deleteDevice() {\\n deviceService.deleteDevice(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" | |
21 | + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Device admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Device admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add device\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"addDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"addDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addDeviceForm.invalid || !addDeviceForm.dirty\\\">\\n Create\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddDeviceDialog();\\n\\nfunction openAddDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();\\n}\\n\\nfunction AddDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.addDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addDeviceFormGroup.markAsPristine();\\n let device = {\\n name: vm.addDeviceFormGroup.get('deviceName').value,\\n type: vm.addDeviceFormGroup.get('deviceType').value,\\n label: vm.addDeviceFormGroup.get('deviceLabel').value\\n };\\n deviceService.saveDevice(device).subscribe(\\n function (device) {\\n saveAttributes(device.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit device\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"editDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"editDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || editDeviceForm.invalid || !editDeviceForm.dirty\\\">\\n Update\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditDeviceDialog();\\n\\nfunction openEditDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();\\n}\\n\\nfunction EditDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.device = null;\\n vm.attributes = {};\\n \\n vm.editDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editDeviceFormGroup.markAsPristine();\\n vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,\\n vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,\\n vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value\\n deviceService.saveDevice(vm.device).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n deviceService.getDevice(entityId.id).subscribe(\\n function (device) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.device = device;\\n vm.editDeviceFormGroup.patchValue(\\n {\\n deviceName: vm.device.name,\\n deviceType: vm.device.type,\\n deviceLabel: vm.device.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete device\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\n\\nopenDeleteDeviceDialog();\\n\\nfunction openDeleteDeviceDialog() {\\n let title = \\\"Are you sure you want to delete the device \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the device and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteDevice();\\n }\\n }\\n );\\n}\\n\\nfunction deleteDevice() {\\n deviceService.deleteDevice(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" | |
22 | 22 | } |
23 | 23 | }, |
24 | 24 | { |
... | ... | @@ -34,8 +34,8 @@ |
34 | 34 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", |
35 | 35 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", |
36 | 36 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
37 | - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Asset admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Asset admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add asset\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addAssetForm=\\\"ngForm\\\" [formGroup]=\\\"addAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"addAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addAssetForm.invalid || !addAssetForm.dirty\\\">\\n Create\\n </button>\\n <button mat-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddAssetDialog();\\n\\nfunction openAddAssetDialog() {\\n customDialog.customDialog(htmlTemplate, AddAssetDialogController).subscribe();\\n}\\n\\nfunction AddAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.addAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addAssetFormGroup.markAsPristine();\\n let asset = {\\n name: vm.addAssetFormGroup.get('assetName').value,\\n type: vm.addAssetFormGroup.get('assetType').value,\\n label: vm.addAssetFormGroup.get('assetLabel').value\\n };\\n assetService.saveAsset(asset).subscribe(\\n function (asset) {\\n saveAttributes(asset.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit asset\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editAssetForm=\\\"ngForm\\\" [formGroup]=\\\"editAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"editAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxFlex fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || editAssetForm.invalid || !editAssetForm.dirty\\\">\\n Update\\n </button>\\n <button mat-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditAssetDialog();\\n\\nfunction openEditAssetDialog() {\\n customDialog.customDialog(htmlTemplate, EditAssetDialogController).subscribe();\\n}\\n\\nfunction EditAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.asset = null;\\n vm.attributes = {};\\n \\n vm.editAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editAssetFormGroup.markAsPristine();\\n vm.asset.name = vm.editAssetFormGroup.get('assetName').value,\\n vm.asset.type = vm.editAssetFormGroup.get('assetType').value,\\n vm.asset.label = vm.editAssetFormGroup.get('assetLabel').value\\n assetService.saveAsset(vm.asset).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n assetService.getAsset(entityId.id).subscribe(\\n function (asset) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.asset = asset;\\n vm.editAssetFormGroup.patchValue(\\n {\\n assetName: vm.asset.name,\\n assetType: vm.asset.type,\\n assetLabel: vm.asset.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete asset\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\n\\nopenDeleteAssetDialog();\\n\\nfunction openDeleteAssetDialog() {\\n let title = \\\"Are you sure you want to delete the asset \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the asset and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteAsset();\\n }\\n }\\n );\\n}\\n\\nfunction deleteAsset() {\\n assetService.deleteAsset(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" | |
37 | + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Asset admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Asset admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add asset\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addAssetForm=\\\"ngForm\\\" [formGroup]=\\\"addAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"addAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addAssetForm.invalid || !addAssetForm.dirty\\\">\\n Create\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddAssetDialog();\\n\\nfunction openAddAssetDialog() {\\n customDialog.customDialog(htmlTemplate, AddAssetDialogController).subscribe();\\n}\\n\\nfunction AddAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.addAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addAssetFormGroup.markAsPristine();\\n let asset = {\\n name: vm.addAssetFormGroup.get('assetName').value,\\n type: vm.addAssetFormGroup.get('assetType').value,\\n label: vm.addAssetFormGroup.get('assetLabel').value\\n };\\n assetService.saveAsset(asset).subscribe(\\n function (asset) {\\n saveAttributes(asset.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit asset\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editAssetForm=\\\"ngForm\\\" [formGroup]=\\\"editAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"editAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n style=\\\"margin-right: 20px;\\\"\\n [disabled]=\\\"(isLoading$ | async) || editAssetForm.invalid || !editAssetForm.dirty\\\">\\n Update\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditAssetDialog();\\n\\nfunction openEditAssetDialog() {\\n customDialog.customDialog(htmlTemplate, EditAssetDialogController).subscribe();\\n}\\n\\nfunction EditAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.asset = null;\\n vm.attributes = {};\\n \\n vm.editAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editAssetFormGroup.markAsPristine();\\n vm.asset.name = vm.editAssetFormGroup.get('assetName').value,\\n vm.asset.type = vm.editAssetFormGroup.get('assetType').value,\\n vm.asset.label = vm.editAssetFormGroup.get('assetLabel').value\\n assetService.saveAsset(vm.asset).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n assetService.getAsset(entityId.id).subscribe(\\n function (asset) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.asset = asset;\\n vm.editAssetFormGroup.patchValue(\\n {\\n assetName: vm.asset.name,\\n assetType: vm.asset.type,\\n assetLabel: vm.asset.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete asset\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\n\\nopenDeleteAssetDialog();\\n\\nfunction openDeleteAssetDialog() {\\n let title = \\\"Are you sure you want to delete the asset \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the asset and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteAsset();\\n }\\n }\\n );\\n}\\n\\nfunction deleteAsset() {\\n assetService.deleteAsset(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" | |
38 | 38 | } |
39 | 39 | } |
40 | 40 | ] |
41 | -} | |
\ No newline at end of file | ||
41 | +} | ... | ... |
... | ... | @@ -244,8 +244,18 @@ class DefaultTbContext implements TbContext { |
244 | 244 | if (nodeCtx.getSelf().isDebugMode()) { |
245 | 245 | mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); |
246 | 246 | } |
247 | + String failureMessage; | |
248 | + if (th != null) { | |
249 | + if (!StringUtils.isEmpty(th.getMessage())) { | |
250 | + failureMessage = th.getMessage(); | |
251 | + } else { | |
252 | + failureMessage = th.getClass().getSimpleName(); | |
253 | + } | |
254 | + } else { | |
255 | + failureMessage = null; | |
256 | + } | |
247 | 257 | nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), |
248 | - msg, th != null ? th.getMessage() : null)); | |
258 | + msg, failureMessage)); | |
249 | 259 | } |
250 | 260 | |
251 | 261 | public void updateSelf(RuleNode self) { | ... | ... |
... | ... | @@ -56,6 +56,7 @@ import java.util.HashMap; |
56 | 56 | import java.util.List; |
57 | 57 | import java.util.Map; |
58 | 58 | import java.util.Set; |
59 | +import java.util.UUID; | |
59 | 60 | import java.util.stream.Collectors; |
60 | 61 | |
61 | 62 | /** |
... | ... | @@ -288,10 +289,10 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
288 | 289 | private void putToQueue(TopicPartitionInfo tpi, TbMsg msg, TbQueueCallback callbackWrapper, EntityId target) { |
289 | 290 | switch (target.getEntityType()) { |
290 | 291 | case RULE_NODE: |
291 | - putToQueue(tpi, msg.copyWithRuleNodeId(entityId, new RuleNodeId(target.getId())), callbackWrapper); | |
292 | + putToQueue(tpi, msg.copyWithRuleNodeId(entityId, new RuleNodeId(target.getId()), UUID.randomUUID()), callbackWrapper); | |
292 | 293 | break; |
293 | 294 | case RULE_CHAIN: |
294 | - putToQueue(tpi, msg.copyWithRuleChainId(new RuleChainId(target.getId())), callbackWrapper); | |
295 | + putToQueue(tpi, msg.copyWithRuleChainId(new RuleChainId(target.getId()), UUID.randomUUID()), callbackWrapper); | |
295 | 296 | break; |
296 | 297 | } |
297 | 298 | } | ... | ... |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.apache.commons.lang3.StringUtils; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | 21 | import org.springframework.http.HttpStatus; |
20 | 22 | import org.springframework.security.access.prepost.PreAuthorize; |
21 | 23 | import org.springframework.web.bind.annotation.PathVariable; |
... | ... | @@ -35,21 +37,30 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; |
35 | 37 | import org.thingsboard.server.common.data.page.PageData; |
36 | 38 | import org.thingsboard.server.common.data.page.PageLink; |
37 | 39 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
40 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
38 | 41 | import org.thingsboard.server.queue.util.TbCoreComponent; |
39 | 42 | import org.thingsboard.server.service.security.permission.Operation; |
40 | 43 | import org.thingsboard.server.service.security.permission.Resource; |
41 | 44 | |
45 | +import java.util.List; | |
46 | +import java.util.UUID; | |
47 | + | |
42 | 48 | @RestController |
43 | 49 | @TbCoreComponent |
44 | 50 | @RequestMapping("/api") |
45 | 51 | @Slf4j |
46 | 52 | public class DeviceProfileController extends BaseController { |
47 | 53 | |
54 | + private static final String DEVICE_PROFILE_ID = "deviceProfileId"; | |
55 | + | |
56 | + @Autowired | |
57 | + private TimeseriesService timeseriesService; | |
58 | + | |
48 | 59 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
49 | 60 | @RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET) |
50 | 61 | @ResponseBody |
51 | - public DeviceProfile getDeviceProfileById(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException { | |
52 | - checkParameter("deviceProfileId", strDeviceProfileId); | |
62 | + public DeviceProfile getDeviceProfileById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { | |
63 | + checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); | |
53 | 64 | try { |
54 | 65 | DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); |
55 | 66 | return checkDeviceProfileId(deviceProfileId, Operation.READ); |
... | ... | @@ -61,8 +72,8 @@ public class DeviceProfileController extends BaseController { |
61 | 72 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
62 | 73 | @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET) |
63 | 74 | @ResponseBody |
64 | - public DeviceProfileInfo getDeviceProfileInfoById(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException { | |
65 | - checkParameter("deviceProfileId", strDeviceProfileId); | |
75 | + public DeviceProfileInfo getDeviceProfileInfoById(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { | |
76 | + checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); | |
66 | 77 | try { |
67 | 78 | DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); |
68 | 79 | return checkNotNull(deviceProfileService.findDeviceProfileInfoById(getTenantId(), deviceProfileId)); |
... | ... | @@ -82,6 +93,46 @@ public class DeviceProfileController extends BaseController { |
82 | 93 | } |
83 | 94 | } |
84 | 95 | |
96 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | |
97 | + @RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET) | |
98 | + @ResponseBody | |
99 | + public List<String> getTimeseriesKeys( | |
100 | + @RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException { | |
101 | + DeviceProfileId deviceProfileId; | |
102 | + if (StringUtils.isNotEmpty(deviceProfileIdStr)) { | |
103 | + deviceProfileId = new DeviceProfileId(UUID.fromString(deviceProfileIdStr)); | |
104 | + checkDeviceProfileId(deviceProfileId, Operation.READ); | |
105 | + } else { | |
106 | + deviceProfileId = null; | |
107 | + } | |
108 | + | |
109 | + try { | |
110 | + return timeseriesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId); | |
111 | + } catch (Exception e) { | |
112 | + throw handleException(e); | |
113 | + } | |
114 | + } | |
115 | + | |
116 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | |
117 | + @RequestMapping(value = "/deviceProfile/devices/keys/attributes", method = RequestMethod.GET) | |
118 | + @ResponseBody | |
119 | + public List<String> getAttributesKeys( | |
120 | + @RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException { | |
121 | + DeviceProfileId deviceProfileId; | |
122 | + if (StringUtils.isNotEmpty(deviceProfileIdStr)) { | |
123 | + deviceProfileId = new DeviceProfileId(UUID.fromString(deviceProfileIdStr)); | |
124 | + checkDeviceProfileId(deviceProfileId, Operation.READ); | |
125 | + } else { | |
126 | + deviceProfileId = null; | |
127 | + } | |
128 | + | |
129 | + try { | |
130 | + return attributesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId); | |
131 | + } catch (Exception e) { | |
132 | + throw handleException(e); | |
133 | + } | |
134 | + } | |
135 | + | |
85 | 136 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
86 | 137 | @RequestMapping(value = "/deviceProfile", method = RequestMethod.POST) |
87 | 138 | @ResponseBody |
... | ... | @@ -113,8 +164,8 @@ public class DeviceProfileController extends BaseController { |
113 | 164 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
114 | 165 | @RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.DELETE) |
115 | 166 | @ResponseStatus(value = HttpStatus.OK) |
116 | - public void deleteDeviceProfile(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException { | |
117 | - checkParameter("deviceProfileId", strDeviceProfileId); | |
167 | + public void deleteDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { | |
168 | + checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); | |
118 | 169 | try { |
119 | 170 | DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); |
120 | 171 | DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE); |
... | ... | @@ -139,8 +190,8 @@ public class DeviceProfileController extends BaseController { |
139 | 190 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
140 | 191 | @RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST) |
141 | 192 | @ResponseBody |
142 | - public DeviceProfile setDefaultDeviceProfile(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException { | |
143 | - checkParameter("deviceProfileId", strDeviceProfileId); | |
193 | + public DeviceProfile setDefaultDeviceProfile(@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException { | |
194 | + checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); | |
144 | 195 | try { |
145 | 196 | DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); |
146 | 197 | DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.WRITE); | ... | ... |
... | ... | @@ -186,6 +186,10 @@ public class ThingsboardInstallService { |
186 | 186 | systemDataLoaderService.updateSystemWidgets(); |
187 | 187 | systemDataLoaderService.createOAuth2Templates(); |
188 | 188 | break; |
189 | + case "3.2.0": | |
190 | + log.info("Upgrading ThingsBoard from version 3.2.0 to 3.2.1 ..."); | |
191 | + databaseEntitiesUpgradeService.upgradeDatabase("3.2.0"); | |
192 | + break; | |
189 | 193 | default: |
190 | 194 | throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion); |
191 | 195 | ... | ... |
... | ... | @@ -181,7 +181,7 @@ public class TenantApiUsageState { |
181 | 181 | long threshold = getProfileThreshold(recordKey); |
182 | 182 | long warnThreshold = getProfileWarnThreshold(recordKey); |
183 | 183 | ApiUsageStateValue tmpValue; |
184 | - if (threshold == 0 || value < warnThreshold) { | |
184 | + if (threshold == 0 || value == 0 || value < warnThreshold) { | |
185 | 185 | tmpValue = ApiUsageStateValue.ENABLED; |
186 | 186 | } else if (value < threshold) { |
187 | 187 | tmpValue = ApiUsageStateValue.WARNING; | ... | ... |
... | ... | @@ -421,6 +421,19 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService |
421 | 421 | log.error("Failed updating schema!!!", e); |
422 | 422 | } |
423 | 423 | break; |
424 | + case "3.2.0": | |
425 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | |
426 | + log.info("Updating schema ..."); | |
427 | + try { | |
428 | + conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_device_device_profile_id ON device(tenant_id, device_profile_id);"); | |
429 | + conn.createStatement().execute("ALTER TABLE dashboard ALTER COLUMN configuration TYPE varchar;"); | |
430 | + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3002001;"); | |
431 | + } catch (Exception e) { | |
432 | + log.error("Failed updating schema!!!", e); | |
433 | + } | |
434 | + log.info("Schema updated."); | |
435 | + } | |
436 | + break; | |
424 | 437 | default: |
425 | 438 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
426 | 439 | } | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.amazonaws.auth.AWSStaticCredentialsProvider; |
20 | 20 | import com.amazonaws.auth.BasicAWSCredentials; |
21 | 21 | import com.amazonaws.services.sns.AmazonSNS; |
22 | 22 | import com.amazonaws.services.sns.AmazonSNSClient; |
23 | +import com.amazonaws.services.sns.model.MessageAttributeValue; | |
23 | 24 | import com.amazonaws.services.sns.model.PublishRequest; |
24 | 25 | import lombok.extern.slf4j.Slf4j; |
25 | 26 | import org.apache.commons.lang3.StringUtils; |
... | ... | @@ -28,9 +29,20 @@ import org.thingsboard.rule.engine.api.sms.exception.SmsException; |
28 | 29 | import org.thingsboard.rule.engine.api.sms.exception.SmsSendException; |
29 | 30 | import org.thingsboard.server.service.sms.AbstractSmsSender; |
30 | 31 | |
32 | +import java.util.HashMap; | |
33 | +import java.util.Map; | |
34 | + | |
31 | 35 | @Slf4j |
32 | 36 | public class AwsSmsSender extends AbstractSmsSender { |
33 | 37 | |
38 | + private static final Map<String, MessageAttributeValue> SMS_ATTRIBUTES = new HashMap<>(); | |
39 | + | |
40 | + static { | |
41 | + SMS_ATTRIBUTES.put("AWS.SNS.SMS.SMSType", new MessageAttributeValue() | |
42 | + .withStringValue("Transactional") | |
43 | + .withDataType("String")); | |
44 | + } | |
45 | + | |
34 | 46 | private AmazonSNS snsClient; |
35 | 47 | |
36 | 48 | public AwsSmsSender(AwsSnsSmsProviderConfiguration config) { |
... | ... | @@ -51,6 +63,7 @@ public class AwsSmsSender extends AbstractSmsSender { |
51 | 63 | message = this.prepareMessage(message); |
52 | 64 | try { |
53 | 65 | PublishRequest publishRequest = new PublishRequest() |
66 | + .withMessageAttributes(SMS_ATTRIBUTES) | |
54 | 67 | .withPhoneNumber(numberTo) |
55 | 68 | .withMessage(message); |
56 | 69 | this.snsClient.publish(publishRequest); | ... | ... |
... | ... | @@ -64,9 +64,9 @@ server: |
64 | 64 | # Minimum value of the server side RPC timeout. May override value provided in the REST API call. |
65 | 65 | # Since 2.5 migration to queues, the RPC delay depends on the size of the pending messages in the queue, |
66 | 66 | # so default UI parameter of 500ms may not be sufficient for loaded environments. |
67 | - min_timeout: "${MIN_SERVER_SIDE_RPC_TIMEOUT:5000}" | |
67 | + min_timeout: "${MIN_SERVER_SIDE_RPC_TIMEOUT:5000}" | |
68 | 68 | # Default value of the server side RPC timeout. |
69 | - default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" | |
69 | + default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" | |
70 | 70 | |
71 | 71 | # Zookeeper connection parameters. Used for service discovery. |
72 | 72 | zk: |
... | ... | @@ -522,7 +522,7 @@ transport: |
522 | 522 | # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) |
523 | 523 | max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" |
524 | 524 | client_side_rpc: |
525 | - timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}" | |
525 | + timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}" | |
526 | 526 | # Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property) |
527 | 527 | api_enabled: "${TB_TRANSPORT_API_ENABLED:true}" |
528 | 528 | # Local HTTP transport parameters |
... | ... | @@ -595,7 +595,7 @@ queue: |
595 | 595 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" |
596 | 596 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" |
597 | 597 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" |
598 | - max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:0}" | |
598 | + max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" | |
599 | 599 | max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" |
600 | 600 | max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" |
601 | 601 | fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" |
... | ... | @@ -695,8 +695,6 @@ queue: |
695 | 695 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
696 | 696 | # JS response poll interval |
697 | 697 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" |
698 | - # JS response auto commit interval | |
699 | - response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | |
700 | 698 | rule-engine: |
701 | 699 | topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" |
702 | 700 | poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.attributes; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
19 | 20 | import org.thingsboard.server.common.data.id.EntityId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
... | ... | @@ -38,4 +39,7 @@ public interface AttributesService { |
38 | 39 | ListenableFuture<List<Void>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes); |
39 | 40 | |
40 | 41 | ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys); |
42 | + | |
43 | + List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); | |
44 | + | |
41 | 45 | } | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.timeseries; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
19 | 20 | import org.thingsboard.server.common.data.id.EntityId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; |
... | ... | @@ -47,4 +48,6 @@ public interface TimeseriesService { |
47 | 48 | ListenableFuture<List<Void>> removeLatest(TenantId tenantId, EntityId entityId, Collection<String> keys); |
48 | 49 | |
49 | 50 | ListenableFuture<Collection<String>> removeAllLatest(TenantId tenantId, EntityId entityId); |
51 | + | |
52 | + List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); | |
50 | 53 | } | ... | ... |
... | ... | @@ -195,11 +195,15 @@ public final class TbMsg implements Serializable { |
195 | 195 | } |
196 | 196 | |
197 | 197 | public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) { |
198 | - return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback); | |
198 | + return copyWithRuleChainId(ruleChainId, this.id); | |
199 | 199 | } |
200 | 200 | |
201 | - public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { | |
202 | - return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback); | |
201 | + public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { | |
202 | + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback); | |
203 | + } | |
204 | + | |
205 | + public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { | |
206 | + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback); | |
203 | 207 | } |
204 | 208 | |
205 | 209 | public TbMsgCallback getCallback() { | ... | ... |
... | ... | @@ -42,7 +42,7 @@ public class TbKafkaAdmin implements TbQueueAdmin { |
42 | 42 | private final short replicationFactor; |
43 | 43 | |
44 | 44 | public TbKafkaAdmin(TbKafkaSettings settings, Map<String, String> topicConfigs) { |
45 | - client = AdminClient.create(settings.toProps()); | |
45 | + client = AdminClient.create(settings.toAdminProps()); | |
46 | 46 | this.topicConfigs = topicConfigs; |
47 | 47 | |
48 | 48 | try { | ... | ... |
... | ... | @@ -45,24 +45,14 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue |
45 | 45 | @Builder |
46 | 46 | private TbKafkaConsumerTemplate(TbKafkaSettings settings, TbKafkaDecoder<T> decoder, |
47 | 47 | String clientId, String groupId, String topic, |
48 | - boolean autoCommit, int autoCommitIntervalMs, | |
49 | 48 | TbQueueAdmin admin) { |
50 | 49 | super(topic); |
51 | - Properties props = settings.toProps(); | |
50 | + Properties props = settings.toConsumerProps(); | |
52 | 51 | props.put(ConsumerConfig.CLIENT_ID_CONFIG, clientId); |
53 | 52 | if (groupId != null) { |
54 | 53 | props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); |
55 | 54 | } |
56 | - if (settings.getMaxPollIntervalMs() > 0) { | |
57 | - props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, settings.getMaxPollIntervalMs()); | |
58 | - } | |
59 | - props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, settings.getMaxPollRecords()); | |
60 | - props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, settings.getMaxPartitionFetchBytes()); | |
61 | - props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, settings.getFetchMaxBytes()); | |
62 | - props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, autoCommit); | |
63 | - props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitIntervalMs); | |
64 | - props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); | |
65 | - props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArrayDeserializer"); | |
55 | + | |
66 | 56 | this.admin = admin; |
67 | 57 | this.consumer = new KafkaConsumer<>(props); |
68 | 58 | this.decoder = decoder; | ... | ... |
... | ... | @@ -55,9 +55,8 @@ public class TbKafkaProducerTemplate<T extends TbQueueMsg> implements TbQueuePro |
55 | 55 | |
56 | 56 | @Builder |
57 | 57 | private TbKafkaProducerTemplate(TbKafkaSettings settings, String defaultTopic, String clientId, TbQueueAdmin admin) { |
58 | - Properties props = settings.toProps(); | |
59 | - props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer"); | |
60 | - props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArraySerializer"); | |
58 | + Properties props = settings.toProducerProps(); | |
59 | + | |
61 | 60 | if (!StringUtils.isEmpty(clientId)) { |
62 | 61 | props.put(ProducerConfig.CLIENT_ID_CONFIG, clientId); |
63 | 62 | } | ... | ... |
... | ... | @@ -19,9 +19,11 @@ import lombok.Getter; |
19 | 19 | import lombok.Setter; |
20 | 20 | import lombok.extern.slf4j.Slf4j; |
21 | 21 | import org.apache.kafka.clients.CommonClientConfigs; |
22 | +import org.apache.kafka.clients.admin.AdminClientConfig; | |
23 | +import org.apache.kafka.clients.consumer.ConsumerConfig; | |
22 | 24 | import org.apache.kafka.clients.producer.ProducerConfig; |
23 | 25 | import org.springframework.beans.factory.annotation.Value; |
24 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | |
26 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
25 | 27 | import org.springframework.boot.context.properties.ConfigurationProperties; |
26 | 28 | import org.springframework.stereotype.Component; |
27 | 29 | |
... | ... | @@ -32,7 +34,7 @@ import java.util.Properties; |
32 | 34 | * Created by ashvayka on 25.09.18. |
33 | 35 | */ |
34 | 36 | @Slf4j |
35 | -@ConditionalOnExpression("'${queue.type:null}'=='kafka'") | |
37 | +@ConditionalOnProperty(prefix = "queue", value = "type", havingValue = "kafka") | |
36 | 38 | @ConfigurationProperties(prefix = "queue.kafka") |
37 | 39 | @Component |
38 | 40 | public class TbKafkaSettings { |
... | ... | @@ -60,19 +62,15 @@ public class TbKafkaSettings { |
60 | 62 | private short replicationFactor; |
61 | 63 | |
62 | 64 | @Value("${queue.kafka.max_poll_records:8192}") |
63 | - @Getter | |
64 | 65 | private int maxPollRecords; |
65 | 66 | |
66 | - @Value("${queue.kafka.max_poll_interval_ms:0}") | |
67 | - @Getter | |
67 | + @Value("${queue.kafka.max_poll_interval_ms:300000}") | |
68 | 68 | private int maxPollIntervalMs; |
69 | 69 | |
70 | 70 | @Value("${queue.kafka.max_partition_fetch_bytes:16777216}") |
71 | - @Getter | |
72 | 71 | private int maxPartitionFetchBytes; |
73 | 72 | |
74 | 73 | @Value("${queue.kafka.fetch_max_bytes:134217728}") |
75 | - @Getter | |
76 | 74 | private int fetchMaxBytes; |
77 | 75 | |
78 | 76 | @Value("${queue.kafka.use_confluent_cloud:false}") |
... | ... | @@ -93,21 +91,48 @@ public class TbKafkaSettings { |
93 | 91 | @Setter |
94 | 92 | private List<TbKafkaProperty> other; |
95 | 93 | |
96 | - public Properties toProps() { | |
97 | - Properties props = new Properties(); | |
94 | + public Properties toAdminProps() { | |
95 | + Properties props = toProps(); | |
96 | + props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, servers); | |
97 | + props.put(AdminClientConfig.RETRIES_CONFIG, retries); | |
98 | + | |
99 | + return props; | |
100 | + } | |
101 | + | |
102 | + public Properties toConsumerProps() { | |
103 | + Properties props = toProps(); | |
104 | + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); | |
105 | + props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords); | |
106 | + props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, maxPartitionFetchBytes); | |
107 | + props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, fetchMaxBytes); | |
108 | + props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, maxPollIntervalMs); | |
109 | + | |
110 | + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); | |
111 | + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArrayDeserializer"); | |
112 | + return props; | |
113 | + } | |
114 | + | |
115 | + public Properties toProducerProps() { | |
116 | + Properties props = toProps(); | |
98 | 117 | props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); |
99 | 118 | props.put(ProducerConfig.RETRIES_CONFIG, retries); |
119 | + props.put(ProducerConfig.ACKS_CONFIG, acks); | |
120 | + props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize); | |
121 | + props.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs); | |
122 | + props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory); | |
123 | + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer"); | |
124 | + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArraySerializer"); | |
125 | + return props; | |
126 | + } | |
127 | + | |
128 | + private Properties toProps() { | |
129 | + Properties props = new Properties(); | |
100 | 130 | |
101 | 131 | if (useConfluent) { |
102 | 132 | props.put("ssl.endpoint.identification.algorithm", sslAlgorithm); |
103 | 133 | props.put("sasl.mechanism", saslMechanism); |
104 | 134 | props.put("sasl.jaas.config", saslConfig); |
105 | 135 | props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, securityProtocol); |
106 | - } else { | |
107 | - props.put(ProducerConfig.ACKS_CONFIG, acks); | |
108 | - props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize); | |
109 | - props.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs); | |
110 | - props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory); | |
111 | 136 | } |
112 | 137 | |
113 | 138 | if (other != null) { | ... | ... |
... | ... | @@ -17,7 +17,7 @@ package org.thingsboard.server.queue.kafka; |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | 19 | import org.springframework.beans.factory.annotation.Value; |
20 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | |
20 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
21 | 21 | import org.springframework.stereotype.Component; |
22 | 22 | |
23 | 23 | import javax.annotation.PostConstruct; |
... | ... | @@ -25,7 +25,7 @@ import java.util.HashMap; |
25 | 25 | import java.util.Map; |
26 | 26 | |
27 | 27 | @Component |
28 | -@ConditionalOnExpression("'${queue.type:null}'=='kafka'") | |
28 | +@ConditionalOnProperty(prefix = "queue", value = "type", havingValue = "kafka") | |
29 | 29 | public class TbKafkaTopicConfigs { |
30 | 30 | @Value("${queue.kafka.topic-properties.core}") |
31 | 31 | private String coreProperties; | ... | ... |
... | ... | @@ -34,9 +34,6 @@ public class TbQueueRemoteJsInvokeSettings { |
34 | 34 | @Value("${queue.js.response_poll_interval}") |
35 | 35 | private int responsePollInterval; |
36 | 36 | |
37 | - @Value("${queue.js.response_auto_commit_interval}") | |
38 | - private int autoCommitInterval; | |
39 | - | |
40 | 37 | @Value("${queue.js.max_requests_timeout}") |
41 | 38 | private long maxRequestsTimeout; |
42 | 39 | } | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.attributes; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
19 | 20 | import org.thingsboard.server.common.data.id.EntityId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
... | ... | @@ -38,4 +39,6 @@ public interface AttributesDao { |
38 | 39 | ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute); |
39 | 40 | |
40 | 41 | ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String attributeType, List<String> keys); |
42 | + | |
43 | + List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); | |
41 | 44 | } | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 22 | import org.springframework.stereotype.Service; |
23 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
23 | 24 | import org.thingsboard.server.common.data.id.EntityId; |
24 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
25 | 26 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
... | ... | @@ -60,6 +61,11 @@ public class BaseAttributesService implements AttributesService { |
60 | 61 | } |
61 | 62 | |
62 | 63 | @Override |
64 | + public List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId) { | |
65 | + return attributesDao.findAllKeysByDeviceProfileId(tenantId, deviceProfileId); | |
66 | + } | |
67 | + | |
68 | + @Override | |
63 | 69 | public ListenableFuture<List<Void>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes) { |
64 | 70 | validate(entityId, scope); |
65 | 71 | attributes.forEach(attribute -> validate(attribute)); | ... | ... |
... | ... | @@ -46,5 +46,15 @@ public interface AttributeKvRepository extends CrudRepository<AttributeKvEntity, |
46 | 46 | @Param("entityId") UUID entityId, |
47 | 47 | @Param("attributeType") String attributeType, |
48 | 48 | @Param("attributeKey") String attributeKey); |
49 | + | |
50 | + @Query(value = "SELECT DISTINCT attribute_key FROM attribute_kv WHERE entity_type = 'DEVICE' " + | |
51 | + "AND entity_id in (SELECT id FROM device WHERE tenant_id = :tenantId and device_profile_id = :deviceProfileId limit 100) ORDER BY attribute_key", nativeQuery = true) | |
52 | + List<String> findAllKeysByDeviceProfileId(@Param("tenantId") UUID tenantId, | |
53 | + @Param("deviceProfileId") UUID deviceProfileId); | |
54 | + | |
55 | + @Query(value = "SELECT DISTINCT attribute_key FROM attribute_kv WHERE entity_type = 'DEVICE' " + | |
56 | + "AND entity_id in (SELECT id FROM device WHERE tenant_id = :tenantId limit 100) ORDER BY attribute_key", nativeQuery = true) | |
57 | + List<String> findAllKeysByTenantId(@Param("tenantId") UUID tenantId); | |
58 | + | |
49 | 59 | } |
50 | 60 | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.beans.factory.annotation.Value; |
24 | 24 | import org.springframework.stereotype.Component; |
25 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
25 | 26 | import org.thingsboard.server.common.data.id.EntityId; |
26 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 28 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
... | ... | @@ -136,6 +137,15 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl |
136 | 137 | } |
137 | 138 | |
138 | 139 | @Override |
140 | + public List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId) { | |
141 | + if (deviceProfileId != null) { | |
142 | + return attributeKvRepository.findAllKeysByDeviceProfileId(tenantId.getId(), deviceProfileId.getId()); | |
143 | + } else { | |
144 | + return attributeKvRepository.findAllKeysByTenantId(tenantId.getId()); | |
145 | + } | |
146 | + } | |
147 | + | |
148 | + @Override | |
139 | 149 | public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute) { |
140 | 150 | AttributeKvEntity entity = new AttributeKvEntity(); |
141 | 151 | entity.setId(new AttributeKvCompositeKey(entityId.getEntityType(), entityId.getId(), attributeType, attribute.getKey())); | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; |
24 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 25 | import org.springframework.beans.factory.annotation.Value; |
26 | 26 | import org.springframework.stereotype.Component; |
27 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
27 | 28 | import org.thingsboard.server.common.data.id.EntityId; |
28 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 30 | import org.thingsboard.server.common.data.kv.Aggregation; |
... | ... | @@ -51,10 +52,15 @@ import org.thingsboard.server.dao.util.SqlTsLatestAnyDao; |
51 | 52 | import javax.annotation.Nullable; |
52 | 53 | import javax.annotation.PostConstruct; |
53 | 54 | import javax.annotation.PreDestroy; |
54 | -import java.util.*; | |
55 | +import java.util.ArrayList; | |
56 | +import java.util.Comparator; | |
57 | +import java.util.HashMap; | |
58 | +import java.util.List; | |
59 | +import java.util.Map; | |
60 | +import java.util.Optional; | |
61 | +import java.util.UUID; | |
55 | 62 | import java.util.concurrent.ExecutionException; |
56 | 63 | import java.util.function.Function; |
57 | -import java.util.stream.Collectors; | |
58 | 64 | |
59 | 65 | @Slf4j |
60 | 66 | @Component |
... | ... | @@ -154,6 +160,15 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme |
154 | 160 | return getFindAllLatestFuture(entityId); |
155 | 161 | } |
156 | 162 | |
163 | + @Override | |
164 | + public List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId) { | |
165 | + if (deviceProfileId != null) { | |
166 | + return tsKvLatestRepository.getKeysByDeviceProfileId(tenantId.getId(), deviceProfileId.getId()); | |
167 | + } else { | |
168 | + return tsKvLatestRepository.getKeysByTenantId(tenantId.getId()); | |
169 | + } | |
170 | + } | |
171 | + | |
157 | 172 | private ListenableFuture<Void> getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { |
158 | 173 | ListenableFuture<List<TsKvEntry>> future = findNewLatestEntryFuture(tenantId, entityId, query); |
159 | 174 | return Futures.transformAsync(future, entryList -> { | ... | ... |
... | ... | @@ -15,10 +15,25 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.sqlts.latest; |
17 | 17 | |
18 | +import org.springframework.data.jpa.repository.Query; | |
18 | 19 | import org.springframework.data.repository.CrudRepository; |
20 | +import org.springframework.data.repository.query.Param; | |
19 | 21 | import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey; |
20 | 22 | import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity; |
21 | 23 | |
24 | +import java.util.List; | |
25 | +import java.util.UUID; | |
26 | + | |
22 | 27 | public interface TsKvLatestRepository extends CrudRepository<TsKvLatestEntity, TsKvLatestCompositeKey> { |
23 | 28 | |
29 | + @Query(value = "SELECT DISTINCT ts_kv_dictionary.key AS strKey FROM ts_kv_latest " + | |
30 | + "INNER JOIN ts_kv_dictionary ON ts_kv_latest.key = ts_kv_dictionary.key_id " + | |
31 | + "WHERE ts_kv_latest.entity_id IN (SELECT id FROM device WHERE device_profile_id = :device_profile_id AND tenant_id = :tenant_id limit 100) ORDER BY ts_kv_dictionary.key", nativeQuery = true) | |
32 | + List<String> getKeysByDeviceProfileId(@Param("tenant_id") UUID tenantId, @Param("device_profile_id") UUID deviceProfileId); | |
33 | + | |
34 | + @Query(value = "SELECT DISTINCT ts_kv_dictionary.key AS strKey FROM ts_kv_latest " + | |
35 | + "INNER JOIN ts_kv_dictionary ON ts_kv_latest.key = ts_kv_dictionary.key_id " + | |
36 | + "WHERE ts_kv_latest.entity_id IN (SELECT id FROM device WHERE tenant_id = :tenant_id limit 100) ORDER BY ts_kv_dictionary.key", nativeQuery = true) | |
37 | + List<String> getKeysByTenantId(@Param("tenant_id") UUID tenantId); | |
38 | + | |
24 | 39 | } | ... | ... |
... | ... | @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value; |
27 | 27 | import org.springframework.stereotype.Service; |
28 | 28 | import org.thingsboard.server.common.data.EntityType; |
29 | 29 | import org.thingsboard.server.common.data.EntityView; |
30 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
30 | 31 | import org.thingsboard.server.common.data.id.EntityId; |
31 | 32 | import org.thingsboard.server.common.data.id.EntityViewId; |
32 | 33 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -40,7 +41,6 @@ import org.thingsboard.server.dao.entityview.EntityViewService; |
40 | 41 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
41 | 42 | import org.thingsboard.server.dao.service.Validator; |
42 | 43 | |
43 | -import java.util.ArrayList; | |
44 | 44 | import java.util.Collection; |
45 | 45 | import java.util.Collections; |
46 | 46 | import java.util.List; |
... | ... | @@ -117,6 +117,11 @@ public class BaseTimeseriesService implements TimeseriesService { |
117 | 117 | } |
118 | 118 | |
119 | 119 | @Override |
120 | + public List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId) { | |
121 | + return timeseriesLatestDao.findAllKeysByDeviceProfileId(tenantId, deviceProfileId); | |
122 | + } | |
123 | + | |
124 | + @Override | |
120 | 125 | public ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { |
121 | 126 | validate(entityId); |
122 | 127 | if (tsKvEntry == null) { | ... | ... |
... | ... | @@ -18,7 +18,6 @@ package org.thingsboard.server.dao.timeseries; |
18 | 18 | import com.datastax.oss.driver.api.core.cql.BoundStatement; |
19 | 19 | import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder; |
20 | 20 | import com.datastax.oss.driver.api.core.cql.PreparedStatement; |
21 | -import com.datastax.oss.driver.api.core.cql.Row; | |
22 | 21 | import com.datastax.oss.driver.api.core.cql.Statement; |
23 | 22 | import com.datastax.oss.driver.api.querybuilder.QueryBuilder; |
24 | 23 | import com.google.common.util.concurrent.FutureCallback; |
... | ... | @@ -28,14 +27,13 @@ import com.google.common.util.concurrent.MoreExecutors; |
28 | 27 | import lombok.extern.slf4j.Slf4j; |
29 | 28 | import org.springframework.beans.factory.annotation.Autowired; |
30 | 29 | import org.springframework.stereotype.Component; |
30 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
31 | 31 | import org.thingsboard.server.common.data.id.EntityId; |
32 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
33 | 33 | import org.thingsboard.server.common.data.kv.Aggregation; |
34 | 34 | import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; |
35 | -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; | |
36 | 35 | import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; |
37 | 36 | import org.thingsboard.server.common.data.kv.ReadTsKvQuery; |
38 | -import org.thingsboard.server.common.data.kv.StringDataEntry; | |
39 | 37 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
40 | 38 | import org.thingsboard.server.dao.model.ModelConstants; |
41 | 39 | import org.thingsboard.server.dao.nosql.TbResultSet; |
... | ... | @@ -43,6 +41,7 @@ import org.thingsboard.server.dao.sqlts.AggregationTimeseriesDao; |
43 | 41 | import org.thingsboard.server.dao.util.NoSqlTsLatestDao; |
44 | 42 | |
45 | 43 | import javax.annotation.Nullable; |
44 | +import java.util.Collections; | |
46 | 45 | import java.util.List; |
47 | 46 | import java.util.Optional; |
48 | 47 | import java.util.concurrent.ExecutionException; |
... | ... | @@ -83,6 +82,11 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes |
83 | 82 | } |
84 | 83 | |
85 | 84 | @Override |
85 | + public List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId) { | |
86 | + return Collections.emptyList(); | |
87 | + } | |
88 | + | |
89 | + @Override | |
86 | 90 | public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { |
87 | 91 | BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getLatestStmt().bind()); |
88 | 92 | stmtBuilder.setString(0, entityId.getEntityType().name()) | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.timeseries; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
19 | 20 | import org.thingsboard.server.common.data.id.EntityId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; |
... | ... | @@ -33,4 +34,5 @@ public interface TimeseriesLatestDao { |
33 | 34 | |
34 | 35 | ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); |
35 | 36 | |
37 | + List<String> findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); | |
36 | 38 | } | ... | ... |
... | ... | @@ -114,7 +114,7 @@ CREATE TABLE IF NOT EXISTS customer ( |
114 | 114 | CREATE TABLE IF NOT EXISTS dashboard ( |
115 | 115 | id uuid NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, |
116 | 116 | created_time bigint NOT NULL, |
117 | - configuration varchar(10000000), | |
117 | + configuration varchar, | |
118 | 118 | assigned_customers varchar(1000000), |
119 | 119 | search_text varchar(255), |
120 | 120 | tenant_id uuid, | ... | ... |
... | ... | @@ -34,6 +34,8 @@ CREATE INDEX IF NOT EXISTS idx_device_customer_id_and_type ON device(tenant_id, |
34 | 34 | |
35 | 35 | CREATE INDEX IF NOT EXISTS idx_device_type ON device(tenant_id, type); |
36 | 36 | |
37 | +CREATE INDEX IF NOT EXISTS idx_device_device_profile_id ON device(tenant_id, device_profile_id); | |
38 | + | |
37 | 39 | CREATE INDEX IF NOT EXISTS idx_asset_customer_id ON asset(tenant_id, customer_id); |
38 | 40 | |
39 | 41 | CREATE INDEX IF NOT EXISTS idx_asset_customer_id_and_type ON asset(tenant_id, customer_id, type); | ... | ... |
... | ... | @@ -132,7 +132,7 @@ CREATE TABLE IF NOT EXISTS customer ( |
132 | 132 | CREATE TABLE IF NOT EXISTS dashboard ( |
133 | 133 | id uuid NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, |
134 | 134 | created_time bigint NOT NULL, |
135 | - configuration varchar(10000000), | |
135 | + configuration varchar, | |
136 | 136 | assigned_customers varchar(1000000), |
137 | 137 | search_text varchar(255), |
138 | 138 | tenant_id uuid, | ... | ... |
... | ... | @@ -1665,10 +1665,10 @@ jws@^4.0.0: |
1665 | 1665 | jwa "^2.0.0" |
1666 | 1666 | safe-buffer "^5.0.1" |
1667 | 1667 | |
1668 | -kafkajs@^1.14.0: | |
1669 | - version "1.14.0" | |
1670 | - resolved "https://registry.yarnpkg.com/kafkajs/-/kafkajs-1.14.0.tgz#3d998a77bfde54dc502e8e88690eedf0b21a1ed6" | |
1671 | - integrity sha512-W+WCekiooY5rJP3Me5N3gWcQ8O6uG6lw0vv9t+sI+WqXKjKwj2+CWIXJy241x+ITE+1M1D19ABSiL2J8lKja5A== | |
1668 | +kafkajs@^1.15.0: | |
1669 | + version "1.15.0" | |
1670 | + resolved "https://registry.yarnpkg.com/kafkajs/-/kafkajs-1.15.0.tgz#a5ada0d933edca2149177393562be6fb0875ec3a" | |
1671 | + integrity sha512-yjPyEnQCkPxAuQLIJnY5dI+xnmmgXmhuOQ1GVxClG5KTOV/rJcW1qA3UfvyEJKTp/RTSqQnUR3HJsKFvHyTpNg== | |
1672 | 1672 | |
1673 | 1673 | keyv@^3.0.0: |
1674 | 1674 | version "3.1.0" | ... | ... |
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 | </sonar.exclusions> |
93 | 93 | <elasticsearch.version>5.0.2</elasticsearch.version> |
94 | 94 | <delight-nashorn-sandbox.version>0.1.14</delight-nashorn-sandbox.version> |
95 | - <kafka.version>2.3.0</kafka.version> | |
95 | + <kafka.version>2.6.0</kafka.version> | |
96 | 96 | <bucket4j.version>4.1.1</bucket4j.version> |
97 | 97 | <fst.version>2.57</fst.version> |
98 | 98 | <antlr.version>2.7.7</antlr.version> |
... | ... | @@ -729,7 +729,8 @@ |
729 | 729 | <exclude>docker/haproxy/**</exclude> |
730 | 730 | <exclude>docker/tb-node/**</exclude> |
731 | 731 | <exclude>ui/**</exclude> |
732 | - <exclude>src/browserslist</exclude> | |
732 | + <exclude>src/.browserslistrc</exclude> | |
733 | + <exclude>**/yarn.lock</exclude> | |
733 | 734 | <exclude>**/*.raw</exclude> |
734 | 735 | <exclude>**/apache/cassandra/io/**</exclude> |
735 | 736 | <exclude>.run/**</exclude> | ... | ... |
... | ... | @@ -160,8 +160,6 @@ queue: |
160 | 160 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
161 | 161 | # JS response poll interval |
162 | 162 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" |
163 | - # JS response auto commit interval | |
164 | - response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | |
165 | 163 | rule-engine: |
166 | 164 | topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" |
167 | 165 | poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" | ... | ... |
... | ... | @@ -153,8 +153,6 @@ queue: |
153 | 153 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
154 | 154 | # JS response poll interval |
155 | 155 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" |
156 | - # JS response auto commit interval | |
157 | - response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | |
158 | 156 | rule-engine: |
159 | 157 | topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" |
160 | 158 | poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" | ... | ... |
... | ... | @@ -182,8 +182,6 @@ queue: |
182 | 182 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
183 | 183 | # JS response poll interval |
184 | 184 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" |
185 | - # JS response auto commit interval | |
186 | - response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" | |
187 | 185 | rule-engine: |
188 | 186 | topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" |
189 | 187 | poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" | ... | ... |
... | ... | @@ -59,6 +59,11 @@ |
59 | 59 | "glob": "marker-shadow.png", |
60 | 60 | "input": "node_modules/leaflet/dist/images/", |
61 | 61 | "output": "/" |
62 | + }, | |
63 | + { | |
64 | + "glob": "**/*", | |
65 | + "input": "node_modules/material-design-icons/iconfont/", | |
66 | + "output": "assets/fonts" | |
62 | 67 | } |
63 | 68 | ], |
64 | 69 | "styles": [ | ... | ... |
... | ... | @@ -69,4 +69,20 @@ export class DeviceProfileService { |
69 | 69 | return this.http.get<PageData<DeviceProfileInfo>>(url, defaultHttpOptionsFromConfig(config)); |
70 | 70 | } |
71 | 71 | |
72 | + public getDeviceProfileDevicesAttributesKeys(deviceProfileId?: string, config?: RequestConfig): Observable<Array<string>> { | |
73 | + let url = `/api/deviceProfile/devices/keys/attributes`; | |
74 | + if (isDefinedAndNotNull(deviceProfileId)) { | |
75 | + url += `?deviceProfileId=${deviceProfileId}`; | |
76 | + } | |
77 | + return this.http.get<Array<string>>(url, defaultHttpOptionsFromConfig(config)); | |
78 | + } | |
79 | + | |
80 | + public getDeviceProfileDevicesTimeseriesKeys(deviceProfileId?: string, config?: RequestConfig): Observable<Array<string>> { | |
81 | + let url = `/api/deviceProfile/devices/keys/timeseries`; | |
82 | + if (isDefinedAndNotNull(deviceProfileId)) { | |
83 | + url += `?deviceProfileId=${deviceProfileId}`; | |
84 | + } | |
85 | + return this.http.get<Array<string>>(url, defaultHttpOptionsFromConfig(config)); | |
86 | + } | |
87 | + | |
72 | 88 | } | ... | ... |
... | ... | @@ -65,6 +65,7 @@ export class TranslateDefaultCompiler extends TranslateMessageFormatCompiler { |
65 | 65 | } catch (e) { |
66 | 66 | console.warn(`Failed to parse source: ${src}`); |
67 | 67 | console.error(e); |
68 | + return false; | |
68 | 69 | } |
69 | 70 | const res = tokens.filter( |
70 | 71 | (value) => typeof value !== 'string' && value.type === 'plural' | ... | ... |
... | ... | @@ -40,11 +40,19 @@ |
40 | 40 | <mat-form-field fxFlex="60" class="mat-block"> |
41 | 41 | <mat-label translate>filter.key-name</mat-label> |
42 | 42 | <input matInput required formControlName="key" |
43 | - [matAutocomplete]="auto" | |
44 | - [matAutocompleteDisabled]="keyFilterFormGroup.get('key.type').value !== entityField"> | |
45 | - <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete"> | |
46 | - <mat-option *ngFor="let option of filteredEntityFields | async" [value]="option"> | |
47 | - {{option}} | |
43 | + #keyNameInput | |
44 | + (focusin)="onFocus()" | |
45 | + [matAutocomplete]="keyName" | |
46 | + [matAutocompleteDisabled]="!showAutocomplete"> | |
47 | + <button *ngIf="keyFilterFormGroup.get('key.key').value && showAutocomplete" | |
48 | + type="button" | |
49 | + matSuffix mat-button mat-icon-button aria-label="Clear" | |
50 | + (click)="clear()"> | |
51 | + <mat-icon class="material-icons">close</mat-icon> | |
52 | + </button> | |
53 | + <mat-autocomplete autoActiveFirstOption #keyName="matAutocomplete"> | |
54 | + <mat-option *ngFor="let keyName of filteredKeysName | async" [value]="keyName"> | |
55 | + <span [innerHTML]="keyName | highlight:searchText"></span> | |
48 | 56 | </mat-option> |
49 | 57 | </mat-autocomplete> |
50 | 58 | <mat-error *ngIf="keyFilterFormGroup.get('key.key').hasError('required')"> | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; | |
17 | +import { Component, ElementRef, Inject, OnDestroy, OnInit, SkipSelf, ViewChild } from '@angular/core'; | |
18 | 18 | import { ErrorStateMatcher } from '@angular/material/core'; |
19 | 19 | import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
20 | 20 | import { Store } from '@ngrx/store'; |
... | ... | @@ -32,9 +32,12 @@ import { |
32 | 32 | } from '@shared/models/query/query.models'; |
33 | 33 | import { DialogService } from '@core/services/dialog.service'; |
34 | 34 | import { TranslateService } from '@ngx-translate/core'; |
35 | -import { EntityField, entityFields } from '@shared/models/entity.models'; | |
36 | -import { Observable } from 'rxjs'; | |
37 | -import { filter, map, startWith } from 'rxjs/operators'; | |
35 | +import { entityFields } from '@shared/models/entity.models'; | |
36 | +import { Observable, of, Subject } from 'rxjs'; | |
37 | +import { filter, map, mergeMap, publishReplay, refCount, startWith, takeUntil } from 'rxjs/operators'; | |
38 | +import { isDefined } from '@core/utils'; | |
39 | +import { EntityId } from '@shared/models/id/entity-id'; | |
40 | +import { DeviceProfileService } from '@core/http/device-profile.service'; | |
38 | 41 | |
39 | 42 | export interface KeyFilterDialogData { |
40 | 43 | keyFilter: KeyFilterInfo; |
... | ... | @@ -43,6 +46,7 @@ export interface KeyFilterDialogData { |
43 | 46 | allowUserDynamicSource: boolean; |
44 | 47 | readonly: boolean; |
45 | 48 | telemetryKeysOnly: boolean; |
49 | + entityId?: EntityId; | |
46 | 50 | } |
47 | 51 | |
48 | 52 | @Component({ |
... | ... | @@ -53,7 +57,13 @@ export interface KeyFilterDialogData { |
53 | 57 | }) |
54 | 58 | export class KeyFilterDialogComponent extends |
55 | 59 | DialogComponent<KeyFilterDialogComponent, KeyFilterInfo> |
56 | - implements OnInit, ErrorStateMatcher { | |
60 | + implements OnInit, OnDestroy, ErrorStateMatcher { | |
61 | + | |
62 | + @ViewChild('keyNameInput', {static: true}) private keyNameInput: ElementRef; | |
63 | + | |
64 | + private dirty = false; | |
65 | + private entityKeysName: Observable<Array<string>>; | |
66 | + private destroy$ = new Subject(); | |
57 | 67 | |
58 | 68 | keyFilterFormGroup: FormGroup; |
59 | 69 | |
... | ... | @@ -72,19 +82,18 @@ export class KeyFilterDialogComponent extends |
72 | 82 | |
73 | 83 | submitted = false; |
74 | 84 | |
75 | - entityFields: { [fieldName: string]: EntityField }; | |
76 | - | |
77 | - entityFieldsList: string[]; | |
85 | + showAutocomplete = false; | |
78 | 86 | |
79 | - readonly entityField = EntityKeyType.ENTITY_FIELD; | |
87 | + filteredKeysName: Observable<Array<string>>; | |
80 | 88 | |
81 | - filteredEntityFields: Observable<string[]>; | |
89 | + searchText = ''; | |
82 | 90 | |
83 | 91 | constructor(protected store: Store<AppState>, |
84 | 92 | protected router: Router, |
85 | 93 | @Inject(MAT_DIALOG_DATA) public data: KeyFilterDialogData, |
86 | 94 | @SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
87 | 95 | public dialogRef: MatDialogRef<KeyFilterDialogComponent, KeyFilterInfo>, |
96 | + private deviceProfileService: DeviceProfileService, | |
88 | 97 | private dialogs: DialogService, |
89 | 98 | private translate: TranslateService, |
90 | 99 | private fb: FormBuilder) { |
... | ... | @@ -104,7 +113,9 @@ export class KeyFilterDialogComponent extends |
104 | 113 | ); |
105 | 114 | |
106 | 115 | if (!this.data.readonly) { |
107 | - this.keyFilterFormGroup.get('valueType').valueChanges.subscribe((valueType: EntityKeyValueType) => { | |
116 | + this.keyFilterFormGroup.get('valueType').valueChanges.pipe( | |
117 | + takeUntil(this.destroy$) | |
118 | + ).subscribe((valueType: EntityKeyValueType) => { | |
108 | 119 | const prevValue: EntityKeyValueType = this.keyFilterFormGroup.value.valueType; |
109 | 120 | const predicates: KeyFilterPredicate[] = this.keyFilterFormGroup.get('predicates').value; |
110 | 121 | if (prevValue && prevValue !== valueType && predicates && predicates.length) { |
... | ... | @@ -121,11 +132,26 @@ export class KeyFilterDialogComponent extends |
121 | 132 | } |
122 | 133 | }); |
123 | 134 | |
135 | + this.keyFilterFormGroup.get('key.type').valueChanges.pipe( | |
136 | + startWith(this.data.keyFilter.key.type), | |
137 | + takeUntil(this.destroy$) | |
138 | + ).subscribe((type: EntityKeyType) => { | |
139 | + if (type === EntityKeyType.ENTITY_FIELD || isDefined(this.data.entityId)) { | |
140 | + this.entityKeysName = null; | |
141 | + this.dirty = false; | |
142 | + this.showAutocomplete = true; | |
143 | + } else { | |
144 | + this.showAutocomplete = false; | |
145 | + } | |
146 | + }); | |
147 | + | |
124 | 148 | this.keyFilterFormGroup.get('key.key').valueChanges.pipe( |
125 | - filter((keyName) => this.keyFilterFormGroup.get('key.type').value === this.entityField && this.entityFields.hasOwnProperty(keyName)) | |
149 | + filter((keyName) => | |
150 | + this.keyFilterFormGroup.get('key.type').value === EntityKeyType.ENTITY_FIELD && entityFields.hasOwnProperty(keyName)), | |
151 | + takeUntil(this.destroy$) | |
126 | 152 | ).subscribe((keyName: string) => { |
127 | 153 | const prevValueType: EntityKeyValueType = this.keyFilterFormGroup.value.valueType; |
128 | - const newValueType = this.entityFields[keyName]?.time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING; | |
154 | + const newValueType = entityFields[keyName]?.time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING; | |
129 | 155 | if (prevValueType !== newValueType) { |
130 | 156 | this.keyFilterFormGroup.get('valueType').patchValue(newValueType, {emitEvent: false}); |
131 | 157 | } |
... | ... | @@ -133,18 +159,20 @@ export class KeyFilterDialogComponent extends |
133 | 159 | } else { |
134 | 160 | this.keyFilterFormGroup.disable({emitEvent: false}); |
135 | 161 | } |
162 | + } | |
136 | 163 | |
137 | - this.entityFields = entityFields; | |
138 | - this.entityFieldsList = Object.values(entityFields).map(entityField => entityField.keyName).sort(); | |
164 | + ngOnInit() { | |
165 | + this.filteredKeysName = this.keyFilterFormGroup.get('key.key').valueChanges | |
166 | + .pipe( | |
167 | + map(value => value ? value : ''), | |
168 | + mergeMap(name => this.fetchEntityName(name)) | |
169 | + ); | |
139 | 170 | } |
140 | 171 | |
141 | - ngOnInit(): void { | |
142 | - this.filteredEntityFields = this.keyFilterFormGroup.get('key.key').valueChanges.pipe( | |
143 | - startWith(''), | |
144 | - map(value => { | |
145 | - return this.entityFieldsList.filter(option => option.startsWith(value)); | |
146 | - }) | |
147 | - ); | |
172 | + ngOnDestroy() { | |
173 | + super.ngOnDestroy(); | |
174 | + this.destroy$.next(); | |
175 | + this.destroy$.complete(); | |
148 | 176 | } |
149 | 177 | |
150 | 178 | isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { |
... | ... | @@ -157,6 +185,21 @@ export class KeyFilterDialogComponent extends |
157 | 185 | this.dialogRef.close(null); |
158 | 186 | } |
159 | 187 | |
188 | + clear() { | |
189 | + this.keyFilterFormGroup.get('key.key').patchValue('', {emitEvent: true}); | |
190 | + setTimeout(() => { | |
191 | + this.keyNameInput.nativeElement.blur(); | |
192 | + this.keyNameInput.nativeElement.focus(); | |
193 | + }, 0); | |
194 | + } | |
195 | + | |
196 | + onFocus() { | |
197 | + if (!this.dirty && this.showAutocomplete) { | |
198 | + this.keyFilterFormGroup.get('key.key').updateValueAndValidity({onlySelf: true, emitEvent: true}); | |
199 | + this.dirty = true; | |
200 | + } | |
201 | + } | |
202 | + | |
160 | 203 | save(): void { |
161 | 204 | this.submitted = true; |
162 | 205 | if (this.keyFilterFormGroup.valid) { |
... | ... | @@ -164,4 +207,41 @@ export class KeyFilterDialogComponent extends |
164 | 207 | this.dialogRef.close(keyFilter); |
165 | 208 | } |
166 | 209 | } |
210 | + | |
211 | + private fetchEntityName(searchText?: string): Observable<Array<string>> { | |
212 | + this.searchText = searchText; | |
213 | + return this.getEntityKeys().pipe( | |
214 | + map(keys => searchText ? keys.filter(key => key.toUpperCase().startsWith(searchText.toUpperCase())) : keys) | |
215 | + ); | |
216 | + } | |
217 | + | |
218 | + private getEntityKeys(): Observable<Array<string>> { | |
219 | + if (!this.entityKeysName) { | |
220 | + let keyNameObservable: Observable<Array<string>>; | |
221 | + switch (this.keyFilterFormGroup.get('key.type').value) { | |
222 | + case EntityKeyType.ENTITY_FIELD: | |
223 | + keyNameObservable = of(Object.values(entityFields).map(entityField => entityField.keyName).sort()); | |
224 | + break; | |
225 | + case EntityKeyType.ATTRIBUTE: | |
226 | + keyNameObservable = this.deviceProfileService.getDeviceProfileDevicesAttributesKeys( | |
227 | + this.data.entityId?.id, | |
228 | + {ignoreLoading: true} | |
229 | + ); | |
230 | + break; | |
231 | + case EntityKeyType.TIME_SERIES: | |
232 | + keyNameObservable = this.deviceProfileService.getDeviceProfileDevicesTimeseriesKeys( | |
233 | + this.data.entityId?.id, | |
234 | + {ignoreLoading: true} | |
235 | + ); | |
236 | + break; | |
237 | + default: | |
238 | + keyNameObservable = of([]); | |
239 | + } | |
240 | + this.entityKeysName = keyNameObservable.pipe( | |
241 | + publishReplay(1), | |
242 | + refCount() | |
243 | + ); | |
244 | + } | |
245 | + return this.entityKeysName; | |
246 | + } | |
167 | 247 | } | ... | ... |
... | ... | @@ -19,7 +19,8 @@ import { |
19 | 19 | AbstractControl, |
20 | 20 | ControlValueAccessor, |
21 | 21 | FormArray, |
22 | - FormBuilder, FormControl, | |
22 | + FormBuilder, | |
23 | + FormControl, | |
23 | 24 | FormGroup, |
24 | 25 | NG_VALUE_ACCESSOR, |
25 | 26 | Validators |
... | ... | @@ -28,12 +29,13 @@ import { Observable, Subscription } from 'rxjs'; |
28 | 29 | import { |
29 | 30 | EntityKeyType, |
30 | 31 | entityKeyTypeTranslationMap, |
31 | - KeyFilter, | |
32 | - KeyFilterInfo, keyFilterInfosToKeyFilters | |
32 | + KeyFilterInfo, | |
33 | + keyFilterInfosToKeyFilters | |
33 | 34 | } from '@shared/models/query/query.models'; |
34 | 35 | import { MatDialog } from '@angular/material/dialog'; |
35 | 36 | import { deepClone } from '@core/utils'; |
36 | 37 | import { KeyFilterDialogComponent, KeyFilterDialogData } from '@home/components/filter/key-filter-dialog.component'; |
38 | +import { EntityId } from '@shared/models/id/entity-id'; | |
37 | 39 | |
38 | 40 | @Component({ |
39 | 41 | selector: 'tb-key-filter-list', |
... | ... | @@ -57,6 +59,8 @@ export class KeyFilterListComponent implements ControlValueAccessor, OnInit { |
57 | 59 | |
58 | 60 | @Input() telemetryKeysOnly = false; |
59 | 61 | |
62 | + @Input() entityId: EntityId; | |
63 | + | |
60 | 64 | keyFilterListFormGroup: FormGroup; |
61 | 65 | |
62 | 66 | entityKeyTypeTranslations = entityKeyTypeTranslationMap; |
... | ... | @@ -170,7 +174,8 @@ export class KeyFilterListComponent implements ControlValueAccessor, OnInit { |
170 | 174 | readonly: this.disabled, |
171 | 175 | displayUserParameters: this.displayUserParameters, |
172 | 176 | allowUserDynamicSource: this.allowUserDynamicSource, |
173 | - telemetryKeysOnly: this.telemetryKeysOnly | |
177 | + telemetryKeysOnly: this.telemetryKeysOnly, | |
178 | + entityId: this.entityId | |
174 | 179 | } |
175 | 180 | }).afterClosed(); |
176 | 181 | } | ... | ... |
... | ... | @@ -96,7 +96,8 @@ |
96 | 96 | {count: alarmRulesFormGroup.get('alarms').value ? |
97 | 97 | alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template> |
98 | 98 | <tb-device-profile-alarms |
99 | - formControlName="alarms"> | |
99 | + formControlName="alarms" | |
100 | + [deviceProfileId]="null"> | |
100 | 101 | </tb-device-profile-alarms> |
101 | 102 | </form> |
102 | 103 | </mat-step> | ... | ... |
... | ... | @@ -22,15 +22,16 @@ import { AppState } from '@core/core.state'; |
22 | 22 | import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; |
23 | 23 | import { Router } from '@angular/router'; |
24 | 24 | import { DialogComponent } from '@app/shared/components/dialog.component'; |
25 | -import { UtilsService } from '@core/services/utils.service'; | |
26 | 25 | import { TranslateService } from '@ngx-translate/core'; |
27 | -import { KeyFilter, keyFilterInfosToKeyFilters, keyFiltersToKeyFilterInfos } from '@shared/models/query/query.models'; | |
26 | +import { keyFilterInfosToKeyFilters, keyFiltersToKeyFilterInfos } from '@shared/models/query/query.models'; | |
28 | 27 | import { AlarmCondition, AlarmConditionType, AlarmConditionTypeTranslationMap } from '@shared/models/device.models'; |
29 | 28 | import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models'; |
29 | +import { EntityId } from '@shared/models/id/entity-id'; | |
30 | 30 | |
31 | 31 | export interface AlarmRuleConditionDialogData { |
32 | 32 | readonly: boolean; |
33 | 33 | condition: AlarmCondition; |
34 | + entityId?: EntityId; | |
34 | 35 | } |
35 | 36 | |
36 | 37 | @Component({ |
... | ... | @@ -50,6 +51,7 @@ export class AlarmRuleConditionDialogComponent extends DialogComponent<AlarmRule |
50 | 51 | |
51 | 52 | readonly = this.data.readonly; |
52 | 53 | condition = this.data.condition; |
54 | + entityId = this.data.entityId; | |
53 | 55 | |
54 | 56 | conditionFormGroup: FormGroup; |
55 | 57 | |
... | ... | @@ -61,7 +63,6 @@ export class AlarmRuleConditionDialogComponent extends DialogComponent<AlarmRule |
61 | 63 | @SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
62 | 64 | public dialogRef: MatDialogRef<AlarmRuleConditionDialogComponent, AlarmCondition>, |
63 | 65 | private fb: FormBuilder, |
64 | - private utils: UtilsService, | |
65 | 66 | public translate: TranslateService) { |
66 | 67 | super(store, router, dialogRef); |
67 | 68 | ... | ... |
... | ... | @@ -33,6 +33,7 @@ import { |
33 | 33 | AlarmRuleConditionDialogData |
34 | 34 | } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component'; |
35 | 35 | import { TimeUnit } from '@shared/models/time/time.models'; |
36 | +import { EntityId } from '@shared/models/id/entity-id'; | |
36 | 37 | |
37 | 38 | @Component({ |
38 | 39 | selector: 'tb-alarm-rule-condition', |
... | ... | @@ -56,6 +57,9 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit |
56 | 57 | @Input() |
57 | 58 | disabled: boolean; |
58 | 59 | |
60 | + @Input() | |
61 | + deviceProfileId: EntityId; | |
62 | + | |
59 | 63 | alarmRuleConditionFormGroup: FormGroup; |
60 | 64 | |
61 | 65 | specText = ''; |
... | ... | @@ -123,7 +127,8 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit |
123 | 127 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
124 | 128 | data: { |
125 | 129 | readonly: this.disabled, |
126 | - condition: this.disabled ? this.modelValue : deepClone(this.modelValue) | |
130 | + condition: this.disabled ? this.modelValue : deepClone(this.modelValue), | |
131 | + entityId: this.deviceProfileId | |
127 | 132 | } |
128 | 133 | }).afterClosed().subscribe((result) => { |
129 | 134 | if (result) { | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <div fxLayout="column" [formGroup]="alarmRuleFormGroup"> |
19 | - <tb-alarm-rule-condition formControlName="condition"> | |
19 | + <tb-alarm-rule-condition formControlName="condition" [deviceProfileId]="deviceProfileId"> | |
20 | 20 | </tb-alarm-rule-condition> |
21 | 21 | <tb-alarm-schedule-info formControlName="schedule"> |
22 | 22 | </tb-alarm-schedule-info> | ... | ... |
... | ... | @@ -33,6 +33,7 @@ import { |
33 | 33 | EditAlarmDetailsDialogComponent, |
34 | 34 | EditAlarmDetailsDialogData |
35 | 35 | } from '@home/components/profile/alarm/edit-alarm-details-dialog.component'; |
36 | +import { EntityId } from '@shared/models/id/entity-id'; | |
36 | 37 | |
37 | 38 | @Component({ |
38 | 39 | selector: 'tb-alarm-rule', |
... | ... | @@ -65,6 +66,9 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat |
65 | 66 | this.requiredValue = coerceBooleanProperty(value); |
66 | 67 | } |
67 | 68 | |
69 | + @Input() | |
70 | + deviceProfileId: EntityId; | |
71 | + | |
68 | 72 | private modelValue: AlarmRule; |
69 | 73 | |
70 | 74 | alarmRuleFormGroup: FormGroup; | ... | ... |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | </mat-error> |
36 | 36 | </mat-form-field> |
37 | 37 | <mat-divider vertical></mat-divider> |
38 | - <tb-alarm-rule formControlName="alarmRule" required fxFlex> | |
38 | + <tb-alarm-rule formControlName="alarmRule" [deviceProfileId]="deviceProfileId" required fxFlex> | |
39 | 39 | </tb-alarm-rule> |
40 | 40 | </div> |
41 | 41 | <button *ngIf="!disabled" | ... | ... |
... | ... | @@ -30,7 +30,8 @@ import { |
30 | 30 | import { AlarmRule, alarmRuleValidator } from '@shared/models/device.models'; |
31 | 31 | import { MatDialog } from '@angular/material/dialog'; |
32 | 32 | import { Subscription } from 'rxjs'; |
33 | -import { AlarmSeverity, alarmSeverityTranslations } from '../../../../../shared/models/alarm.models'; | |
33 | +import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models'; | |
34 | +import { EntityId } from '@shared/models/id/entity-id'; | |
34 | 35 | |
35 | 36 | @Component({ |
36 | 37 | selector: 'tb-create-alarm-rules', |
... | ... | @@ -59,6 +60,9 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit, |
59 | 60 | @Input() |
60 | 61 | disabled: boolean; |
61 | 62 | |
63 | + @Input() | |
64 | + deviceProfileId: EntityId; | |
65 | + | |
62 | 66 | createAlarmRulesFormGroup: FormGroup; |
63 | 67 | |
64 | 68 | private usedSeverities: AlarmSeverity[] = []; | ... | ... |
... | ... | @@ -80,14 +80,16 @@ |
80 | 80 | </mat-expansion-panel> |
81 | 81 | <div fxFlex fxLayout="column"> |
82 | 82 | <div translate class="tb-small" style="padding-bottom: 8px;">device-profile.create-alarm-rules</div> |
83 | - <tb-create-alarm-rules formControlName="createRules" style="padding-bottom: 16px;"> | |
83 | + <tb-create-alarm-rules formControlName="createRules" | |
84 | + style="padding-bottom: 16px;" | |
85 | + [deviceProfileId]="deviceProfileId"> | |
84 | 86 | </tb-create-alarm-rules> |
85 | 87 | <div translate class="tb-small" style="padding-bottom: 8px;">device-profile.clear-alarm-rule</div> |
86 | 88 | <div fxLayout="row" fxLayoutGap="8px;" fxLayoutAlign="start center" |
87 | 89 | [fxShow]="alarmFormGroup.get('clearRule').value" |
88 | 90 | style="padding-bottom: 8px;"> |
89 | 91 | <div class="clear-alarm-rule" fxFlex fxLayout="row"> |
90 | - <tb-alarm-rule formControlName="clearRule" fxFlex> | |
92 | + <tb-alarm-rule formControlName="clearRule" fxFlex [deviceProfileId]="deviceProfileId"> | |
91 | 93 | </tb-alarm-rule> |
92 | 94 | </div> |
93 | 95 | <button *ngIf="!disabled" | ... | ... |
... | ... | @@ -29,6 +29,7 @@ import { AlarmRule, DeviceProfileAlarm, deviceProfileAlarmValidator } from '@sha |
29 | 29 | import { MatDialog } from '@angular/material/dialog'; |
30 | 30 | import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
31 | 31 | import { MatChipInputEvent } from '@angular/material/chips'; |
32 | +import { EntityId } from '@shared/models/id/entity-id'; | |
32 | 33 | |
33 | 34 | @Component({ |
34 | 35 | selector: 'tb-device-profile-alarm', |
... | ... | @@ -60,6 +61,9 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit |
60 | 61 | @Input() |
61 | 62 | expanded = false; |
62 | 63 | |
64 | + @Input() | |
65 | + deviceProfileId: EntityId; | |
66 | + | |
63 | 67 | private modelValue: DeviceProfileAlarm; |
64 | 68 | |
65 | 69 | alarmFormGroup: FormGroup; | ... | ... |
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}"> |
23 | 23 | <tb-device-profile-alarm [formControl]="alarmControl" |
24 | 24 | [expanded]="$index === 0" |
25 | + [deviceProfileId]="deviceProfileId" | |
25 | 26 | (removeAlarm)="removeAlarm($index)"> |
26 | 27 | </tb-device-profile-alarm> |
27 | 28 | </div> | ... | ... |
... | ... | @@ -34,6 +34,7 @@ import { DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/ |
34 | 34 | import { guid } from '@core/utils'; |
35 | 35 | import { Subscription } from 'rxjs'; |
36 | 36 | import { MatDialog } from '@angular/material/dialog'; |
37 | +import { EntityId } from '@shared/models/id/entity-id'; | |
37 | 38 | |
38 | 39 | @Component({ |
39 | 40 | selector: 'tb-device-profile-alarms', |
... | ... | @@ -68,6 +69,9 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni |
68 | 69 | @Input() |
69 | 70 | disabled: boolean; |
70 | 71 | |
72 | + @Input() | |
73 | + deviceProfileId: EntityId; | |
74 | + | |
71 | 75 | private valueChangeSubscription: Subscription = null; |
72 | 76 | |
73 | 77 | private propagateChange = (v: any) => { }; | ... | ... |
... | ... | @@ -116,7 +116,8 @@ |
116 | 116 | </mat-panel-title> |
117 | 117 | </mat-expansion-panel-header> |
118 | 118 | <tb-device-profile-alarms |
119 | - formControlName="alarms"> | |
119 | + formControlName="alarms" | |
120 | + [deviceProfileId]="deviceProfileId"> | |
120 | 121 | </tb-device-profile-alarms> |
121 | 122 | </mat-expansion-panel> |
122 | 123 | <mat-expansion-panel [expanded]="true"> | ... | ... |
... | ... | @@ -39,6 +39,7 @@ import { |
39 | 39 | import { EntityType } from '@shared/models/entity-type.models'; |
40 | 40 | import { RuleChainId } from '@shared/models/id/rule-chain-id'; |
41 | 41 | import { ServiceType } from '@shared/models/queue.models'; |
42 | +import { EntityId } from '@shared/models/id/entity-id'; | |
42 | 43 | |
43 | 44 | @Component({ |
44 | 45 | selector: 'tb-device-profile', |
... | ... | @@ -66,6 +67,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { |
66 | 67 | |
67 | 68 | serviceType = ServiceType.TB_RULE_ENGINE; |
68 | 69 | |
70 | + deviceProfileId: EntityId; | |
71 | + | |
69 | 72 | constructor(protected store: Store<AppState>, |
70 | 73 | protected translate: TranslateService, |
71 | 74 | @Optional() @Inject('entity') protected entityValue: DeviceProfile, |
... | ... | @@ -83,6 +86,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { |
83 | 86 | } |
84 | 87 | |
85 | 88 | buildForm(entity: DeviceProfile): FormGroup { |
89 | + this.deviceProfileId = entity?.id ? entity.id : null; | |
86 | 90 | this.displayProfileConfiguration = entity && entity.type && |
87 | 91 | deviceProfileTypeConfigurationInfoMap.get(entity.type).hasProfileConfiguration; |
88 | 92 | this.displayTransportConfiguration = entity && entity.transportType && |
... | ... | @@ -157,6 +161,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { |
157 | 161 | } |
158 | 162 | |
159 | 163 | updateForm(entity: DeviceProfile) { |
164 | + this.deviceProfileId = entity.id; | |
160 | 165 | this.displayProfileConfiguration = entity.type && |
161 | 166 | deviceProfileTypeConfigurationInfoMap.get(entity.type).hasProfileConfiguration; |
162 | 167 | this.displayTransportConfiguration = entity.transportType && | ... | ... |
... | ... | @@ -178,17 +178,17 @@ |
178 | 178 | <!-- </div>--> |
179 | 179 | <!-- </div>--> |
180 | 180 | <!-- <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">--> |
181 | -<!-- <button mat-button mat-raised-button color="primary"--> | |
182 | -<!-- type="submit"--> | |
183 | -<!-- [disabled]="(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty">--> | |
184 | -<!-- Save--> | |
185 | -<!-- </button>--> | |
186 | 181 | <!-- <button mat-button color="primary"--> |
187 | 182 | <!-- type="button"--> |
188 | 183 | <!-- [disabled]="(isLoading$ | async)"--> |
189 | 184 | <!-- (click)="cancel()" cdkFocusInitial>--> |
190 | 185 | <!-- Cancel--> |
191 | 186 | <!-- </button>--> |
187 | +<!-- <button mat-button mat-raised-button color="primary"--> | |
188 | +<!-- type="submit"--> | |
189 | +<!-- [disabled]="(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty">--> | |
190 | +<!-- Save--> | |
191 | +<!-- </button>--> | |
192 | 192 | <!-- </div>--> |
193 | 193 | <!--</form>--> |
194 | 194 | <!----> |
... | ... | @@ -338,16 +338,16 @@ |
338 | 338 | <!-- </div>--> |
339 | 339 | <!-- </div>--> |
340 | 340 | <!-- <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">--> |
341 | -<!-- <button mat-button mat-raised-button color="primary"--> | |
342 | -<!-- type="submit"--> | |
343 | -<!-- [disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">--> | |
344 | -<!-- Create--> | |
345 | -<!-- </button>--> | |
346 | 341 | <!-- <button mat-button color="primary"--> |
347 | 342 | <!-- type="button"--> |
348 | 343 | <!-- [disabled]="(isLoading$ | async)"--> |
349 | 344 | <!-- (click)="cancel()" cdkFocusInitial>--> |
350 | 345 | <!-- Cancel--> |
351 | 346 | <!-- </button>--> |
347 | +<!-- <button mat-button mat-raised-button color="primary"--> | |
348 | +<!-- type="submit"--> | |
349 | +<!-- [disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">--> | |
350 | +<!-- Create--> | |
351 | +<!-- </button>--> | |
352 | 352 | <!-- </div>--> |
353 | 353 | <!--</form>--> | ... | ... |
... | ... | @@ -283,6 +283,13 @@ export class PhotoCameraInputWidgetComponent extends PageComponent implements On |
283 | 283 | window.navigator.mediaDevices.getUserMedia(videoTrackConstraints).then((stream: MediaStream) => { |
284 | 284 | if (init) { |
285 | 285 | this.isShowCamera = true; |
286 | + if (this.availableVideoInputs.find((device) => device.deviceId === '')) { | |
287 | + PhotoCameraInputWidgetComponent.getAvailableVideoInputs().then((devices) => { | |
288 | + this.singleDevice = devices.length < 2; | |
289 | + this.availableVideoInputs = devices; | |
290 | + this.ctx.detectChanges(); | |
291 | + }); | |
292 | + } | |
286 | 293 | } |
287 | 294 | this.mediaStream = stream; |
288 | 295 | this.videoElement.srcObject = stream; | ... | ... |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 | [required]="!createProfile" |
77 | 77 | [transportType]="deviceWizardFormGroup.get('transportType').value" |
78 | 78 | formControlName="deviceProfileId" |
79 | - [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}" | |
79 | + [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}" | |
80 | 80 | (deviceProfileChanged)="$event?.transportType ? deviceWizardFormGroup.get('transportType').patchValue($event?.transportType) : {}" |
81 | 81 | [addNewProfile]="false" |
82 | 82 | [selectDefaultProfile]="true" |
... | ... | @@ -133,7 +133,8 @@ |
133 | 133 | {count: alarmRulesFormGroup.get('alarms').value ? |
134 | 134 | alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template> |
135 | 135 | <tb-device-profile-alarms |
136 | - formControlName="alarms"> | |
136 | + formControlName="alarms" | |
137 | + [deviceProfileId]="null"> | |
137 | 138 | </tb-device-profile-alarms> |
138 | 139 | </form> |
139 | 140 | </mat-step> | ... | ... |
... | ... | @@ -32,9 +32,11 @@ import { DashboardService } from '@core/http/dashboard.service'; |
32 | 32 | import { UserService } from '@core/http/user.service'; |
33 | 33 | import { AlarmService } from '@core/http/alarm.service'; |
34 | 34 | import { Router } from '@angular/router'; |
35 | +import { BroadcastService } from "@core/services/broadcast.service"; | |
35 | 36 | |
36 | 37 | export const ServicesMap = new Map<string, Type<any>>( |
37 | 38 | [ |
39 | + ['broadcastService', BroadcastService], | |
38 | 40 | ['deviceService', DeviceService], |
39 | 41 | ['alarmService', AlarmService], |
40 | 42 | ['assetService', AssetService], | ... | ... |
... | ... | @@ -46,7 +46,7 @@ |
46 | 46 | }}" #alarmRules="matTab"> |
47 | 47 | <div class="mat-padding" [formGroup]="detailsForm"> |
48 | 48 | <div formGroupName="profileData"> |
49 | - <tb-device-profile-alarms formControlName="alarms"></tb-device-profile-alarms> | |
49 | + <tb-device-profile-alarms formControlName="alarms" [deviceProfileId]="entity.id"></tb-device-profile-alarms> | |
50 | 50 | </div> |
51 | 51 | </div> |
52 | 52 | </mat-tab> | ... | ... |
... | ... | @@ -1937,25 +1937,6 @@ |
1937 | 1937 | } |
1938 | 1938 | }, |
1939 | 1939 | "language": { |
1940 | - "language": "Jazyk", | |
1941 | - "locales": { | |
1942 | - "de_DE": "Deutsch", | |
1943 | - "fr_FR": "Français", | |
1944 | - "zh_CN": "简体中文", | |
1945 | - "zh_TW": "繁體中文", | |
1946 | - "en_US": "English", | |
1947 | - "it_IT": "Italiano", | |
1948 | - "ko_KR": "한글", | |
1949 | - "ru_RU": "Русский", | |
1950 | - "es_ES": "Español", | |
1951 | - "ja_JA": "日本語", | |
1952 | - "tr_TR": "Türkçe", | |
1953 | - "fa_IR": "فارسي", | |
1954 | - "uk_UA": "Українська", | |
1955 | - "cs_CZ": "Česky", | |
1956 | - "el_GR": "Ελληνικά", | |
1957 | - "ro_RO": "Română", | |
1958 | - "lv_LV": "Latviešu" | |
1959 | - } | |
1940 | + "language": "Jazyk" | |
1960 | 1941 | } |
1961 | 1942 | } | ... | ... |
... | ... | @@ -266,7 +266,7 @@ |
266 | 266 | "add-to-dashboard": "대시보드에 추가", |
267 | 267 | "add-widget-to-dashboard": "대시보드에 위젯 추가", |
268 | 268 | "selected-attributes": "{ count, plural, 1 {속성 1개} other {속성 #개} } 선택됨", |
269 | - "selected-telemetry": "{ count, plural, 1 {최근 데이터 1개} other {최근 데이터 #개} } 선택됨" | |
269 | + "selected-telemetry": "{ count, plural, 1 {최근 데이터 1개} other {최근 데이터 #개} } 선택됨", | |
270 | 270 | "no-attributes-text": "아무 속성도 찾을 수 없습니다", |
271 | 271 | "no-telemetry-text": "아무 텔레메트리도 찾을 수 없습니다." |
272 | 272 | }, | ... | ... |
1 | +{ | |
2 | + "access": { | |
3 | + "unauthorized": "Nepooblaščeno", | |
4 | + "unauthorized-access": "Nepooblaščen dostop", | |
5 | + "unauthorized-access-text": "Za dostop do tega vira se morate prijaviti!", | |
6 | + "access-forbidden": "Dostop prepovedan", | |
7 | + "access-forbidden-text": "Nimate pravic dostopa do te lokacije! <br/> Poskusite se prijaviti z drugim uporabnikom, če še vedno želite dostopati do te lokacije.", | |
8 | + "refresh-token-expired": "Seja je potekla", | |
9 | + "refresh-token-failed": "Seje ni mogoče osvežiti", | |
10 | + "permission-denied": "Dovoljenje zavrnjeno", | |
11 | + "permission-denied-text": "Nimate dovoljenja za izvedbo tega dejanja!" | |
12 | + }, | |
13 | + "action": { | |
14 | + "activate": "Aktiviraj", | |
15 | + "suspend": "Začasno ustavi", | |
16 | + "save": "Shrani", | |
17 | + "saveAs": "Shrani kot", | |
18 | + "cancel": "Prekliči", | |
19 | + "ok": "V redu", | |
20 | + "delete": "Izbriši", | |
21 | + "add": "Dodaj", | |
22 | + "yes": "Da", | |
23 | + "no": "Ne", | |
24 | + "update": "Nadgradnja", | |
25 | + "remove": "Odstrani", | |
26 | + "select": "Izberi", | |
27 | + "search": "Iskanje", | |
28 | + "clear-search": "Počisti iskanje", | |
29 | + "assign": "Dodeli", | |
30 | + "unassign": "Preklic dodelitve", | |
31 | + "share": "Deliti", | |
32 | + "make-private": "Naj bo zasebno", | |
33 | + "apply": "Uporabi", | |
34 | + "apply-changes": "Uporabi spremembe", | |
35 | + "edit-mode": "Način urejanja", | |
36 | + "enter-edit-mode": "Vstopi v način urejanja", | |
37 | + "decline-changes": "Zavrni spremembe", | |
38 | + "close": "Zapri", | |
39 | + "back": "Nazaj", | |
40 | + "run": "Zaženi", | |
41 | + "sign-in": "Prijavite se!", | |
42 | + "edit": "Uredi", | |
43 | + "view": "Pogled", | |
44 | + "create": "Ustvari", | |
45 | + "drag": "Povleci", | |
46 | + "refresh": "Osveži", | |
47 | + "undo": "Razveljavi", | |
48 | + "copy": "Kopiraj", | |
49 | + "paste": "Prilepi", | |
50 | + "copy-reference": "Kopiraj sklic", | |
51 | + "paste-reference": "Prilepi sklic", | |
52 | + "import": "Uvozi", | |
53 | + "export": "Izvozi", | |
54 | + "share-via": "Deli prek {{provider}}", | |
55 | + "continue": "Nadaljuj", | |
56 | + "discard-changes": "Zavrzi spremembe", | |
57 | + "download": "Prenesi", | |
58 | + "next-with-label": "Naslednji: {{label}}", | |
59 | + "read-more": "Preberi več", | |
60 | + "hide": "Skrij" | |
61 | + }, | |
62 | + "aggregation": { | |
63 | + "aggregation": "Združevanje", | |
64 | + "function": "Funkcija združevanja podatkov", | |
65 | + "limit": "Največje vrednosti", | |
66 | + "group-interval": "Interval združevanja", | |
67 | + "min": "Min", | |
68 | + "max": "Max", | |
69 | + "avg": "Povprečje", | |
70 | + "sum": "Vsota", | |
71 | + "count": "Štetje", | |
72 | + "none": "Brez" | |
73 | + }, | |
74 | + "admin": { | |
75 | + "general": "Splošno", | |
76 | + "general-settings": "Splošne nastavitve", | |
77 | + "outgoing-mail": "Poštni strežnik", | |
78 | + "outgoing-mail-settings": "Nastavitve strežnika odhodne pošte", | |
79 | + "system-settings": "Sistemske nastavitve", | |
80 | + "test-mail-sent": "Testna pošta je bila uspešno poslana!", | |
81 | + "base-url": "Osnovni URL", | |
82 | + "base-url-required": "Zahtevan je osnovni URL.", | |
83 | + "prohibit-different-url": "Prohibit to use hostname from the client request headers", | |
84 | + "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", | |
85 | + "mail-from": "Pošta od", | |
86 | + "mail-from-required": "Zahtevana je pošta od.", | |
87 | + "smtp-protocol": "Protokol SMTP", | |
88 | + "smtp-host": "SMTP gostitelj", | |
89 | + "smtp-host-required": "Zahtevan je gostitelj SMTP.", | |
90 | + "smtp-port": "Vrata SMTP", | |
91 | + "smtp-port-required": "Navesti morate vrata SMTP.", | |
92 | + "smtp-port-invalid": "To ne izgleda kot veljavna vrata SMTP.", | |
93 | + "timeout-msec": "Časovna omejitev (msec)", | |
94 | + "timeout-required": "Časovna omejitev je potrebna.", | |
95 | + "timeout-invalid": "To ne izgleda kot veljavna časovna omejitev.", | |
96 | + "enable-tls": "Omogoči TLS", | |
97 | + "tls-version": "Različica TLS", | |
98 | + "enable-proxy": "Omogoči proxy", | |
99 | + "proxy-host": "Gostitelj proxy", | |
100 | + "proxy-host-required": "Zahtevan je strežnik proxy.", | |
101 | + "proxy-port": "Proxy vrata", | |
102 | + "proxy-port-required": "Vrata proxy so potrebna.", | |
103 | + "proxy-port-range": "Vrata proxy naj bodo v območju od 1 do 65535.", | |
104 | + "proxy-user": "Uporabnik proxy", | |
105 | + "proxy-password": "Geslo proxy", | |
106 | + "send-test-mail": "Pošlji testno pošto", | |
107 | + "sms-provider": "SMS provider", | |
108 | + "sms-provider-settings": "SMS provider settings", | |
109 | + "sms-provider-type": "SMS provider type", | |
110 | + "sms-provider-type-required": "SMS provider type is required.", | |
111 | + "sms-provider-type-aws-sns": "Amazon SNS", | |
112 | + "sms-provider-type-twilio": "Twilio", | |
113 | + "aws-access-key-id": "AWS Access Key ID", | |
114 | + "aws-access-key-id-required": "AWS Access Key ID is required", | |
115 | + "aws-secret-access-key": "AWS Secret Access Key", | |
116 | + "aws-secret-access-key-required": "AWS Secret Access Key is required", | |
117 | + "aws-region": "AWS Region", | |
118 | + "aws-region-required": "AWS Region is required", | |
119 | + "number-from": "Phone Number From", | |
120 | + "number-from-required": "Phone Number From is required.", | |
121 | + "number-to": "Phone Number To", | |
122 | + "number-to-required": "Phone Number To is required.", | |
123 | + "phone-number-hint": "Phone Number in E.164 format, ex. +19995550123", | |
124 | + "phone-number-pattern": "Invalid phone number. Should be in E.164 format, ex. +19995550123.", | |
125 | + "sms-message": "SMS message", | |
126 | + "sms-message-required": "SMS message is required.", | |
127 | + "sms-message-max-length": "SMS message can't be longer 1600 characters", | |
128 | + "twilio-account-sid": "Twilio Account SID", | |
129 | + "twilio-account-sid-required": "Twilio Account SID is required", | |
130 | + "twilio-account-token": "Twilio Account Token", | |
131 | + "twilio-account-token-required": "Twilio Account Token is required", | |
132 | + "send-test-sms": "Send test SMS", | |
133 | + "test-sms-sent": "Test SMS was successfully sent!", | |
134 | + "security-settings": "Varnostne nastavitve", | |
135 | + "password-policy": "Pravilnik o geslih", | |
136 | + "minimum-password-length": "Najkrajša dolžina gesla", | |
137 | + "minimum-password-length-required": "Zahtevana je najkrajša dolžina gesla", | |
138 | + "minimum-password-length-range": "Minimalna dolžina gesla naj bo v območju od 5 do 50", | |
139 | + "minimum-uppercase-letters": "Najmanjše število velikih črk", | |
140 | + "minimum-uppercase-letters-range": "Najmanjše število velikih črk ne sme biti negativno", | |
141 | + "minimum-lowercase-letters": "Najmanjše število malih črk", | |
142 | + "minimum-lowercase-letters-range": "Najmanjše število malih črk ne sme biti negativno", | |
143 | + "minimum-digits": "Najmanjše število številk", | |
144 | + "minimum-digits-range": "Najmanjše število številk ne sme biti negativno", | |
145 | + "minimum-special-characters": "Najmanjše število posebnih znakov", | |
146 | + "minimum-special-characters-range": "Najmanjše število posebnih znakov ne sme biti negativno", | |
147 | + "password-expiration-period-days": "Obdobje veljavnosti gesla v dneh", | |
148 | + "password-expiration-period-days-range": "Obdobje veljavnosti gesla v dneh ne sme biti negativno", | |
149 | + "password-reuse-frequency-days": "Pogostost ponovne uporabe gesla v dneh", | |
150 | + "password-reuse-frequency-days-range": "Pogostost ponovne uporabe gesla v dneh ne sme biti negativna", | |
151 | + "general-policy": "Splošna politika", | |
152 | + "max-failed-login-attempts": "Največje število neuspelih poskusov prijave, preden se račun zaklene", | |
153 | + "minimum-max-failed-login-attempts-range": "Največje število neuspelih poskusov prijave ne sme biti negativno", | |
154 | + "user-lockout-notification-email": "V primeru zaklepa uporabniškega računa, pošlji obvestilo na e-pošto", | |
155 | + "domain-name": "Domain name", | |
156 | + "domain-name-unique": "Domain name and protocol need to unique.", | |
157 | + "error-verification-url": "A domain name shouldn't contain symbols '/' and ':'. Example: thingsboard.io", | |
158 | + "oauth2": { | |
159 | + "access-token-uri": "Access token URI", | |
160 | + "access-token-uri-required": "Access token URI is required.", | |
161 | + "activate-user": "Activate user", | |
162 | + "add-domain": "Add domain", | |
163 | + "delete-domain": "Delete domain", | |
164 | + "add-provider": "Add provider", | |
165 | + "delete-provider": "Delete provider", | |
166 | + "allow-user-creation": "Allow user creation", | |
167 | + "always-fullscreen": "Always fullscreen", | |
168 | + "authorization-uri": "Authorization URI", | |
169 | + "authorization-uri-required": "Authorization URI is required.", | |
170 | + "client-authentication-method": "Client authentication method", | |
171 | + "client-id": "Client ID", | |
172 | + "client-id-required": "Client ID is required.", | |
173 | + "client-secret": "Client secret", | |
174 | + "client-secret-required": "Client secret is required.", | |
175 | + "custom-setting": "Custom settings", | |
176 | + "customer-name-pattern": "Customer name pattern", | |
177 | + "default-dashboard-name": "Default dashboard name", | |
178 | + "delete-domain-text": "Be careful, after the confirmation a domain and all provider data will be unavailable.", | |
179 | + "delete-domain-title": "Are you sure you want to delete settings the domain '{{domainName}}'?", | |
180 | + "delete-registration-text": "Be careful, after the confirmation a provider data will be unavailable.", | |
181 | + "delete-registration-title": "Are you sure you want to delete the provider '{{name}}'?", | |
182 | + "email-attribute-key": "Email attribute key", | |
183 | + "email-attribute-key-required": "Email attribute key is required.", | |
184 | + "first-name-attribute-key": "First name attribute key", | |
185 | + "general": "General", | |
186 | + "jwk-set-uri": "JSON Web Key URI", | |
187 | + "last-name-attribute-key": "Last name attribute key", | |
188 | + "login-button-icon": "Login button icon", | |
189 | + "login-button-label": "Provider label", | |
190 | + "login-button-label-placeholder": "Login with $(Provider label)", | |
191 | + "login-button-label-required": "Label is required.", | |
192 | + "login-provider": "Login provider", | |
193 | + "mapper": "Mapper", | |
194 | + "new-domain": "New domain", | |
195 | + "oauth2": "OAuth2", | |
196 | + "redirect-uri-template": "Redirect URI template", | |
197 | + "copy-redirect-uri": "Copy redirect URI", | |
198 | + "registration-id": "Registration ID", | |
199 | + "registration-id-required": "Registration ID is required.", | |
200 | + "registration-id-unique": "Registration ID need to unique for the system.", | |
201 | + "scope": "Scope", | |
202 | + "scope-required": "Scope is required.", | |
203 | + "tenant-name-pattern": "Tenant name pattern", | |
204 | + "tenant-name-pattern-required": "Tenant name pattern is required.", | |
205 | + "tenant-name-strategy": "Tenant name strategy", | |
206 | + "type": "Mapper type", | |
207 | + "uri-pattern-error": "Invalid URI format.", | |
208 | + "url": "URL", | |
209 | + "url-pattern": "Invalid URL format.", | |
210 | + "url-required": "URL is required.", | |
211 | + "user-info-uri": "User info URI", | |
212 | + "user-info-uri-required": "User info URI is required.", | |
213 | + "user-name-attribute-name": "User name attribute key", | |
214 | + "user-name-attribute-name-required": "User name attribute key is required", | |
215 | + "protocol": "Protocol", | |
216 | + "domain-schema-http": "HTTP", | |
217 | + "domain-schema-https": "HTTPS", | |
218 | + "domain-schema-mixed": "HTTP+HTTPS", | |
219 | + "enable": "Enable OAuth2 settings" | |
220 | + } | |
221 | + }, | |
222 | + "alarm": { | |
223 | + "alarm": "Alarm", | |
224 | + "alarms": "Alarmi", | |
225 | + "select-alarm": "Izberi alarm", | |
226 | + "no-alarms-matching": "Najdeni niso bili nobeni alarmi, ki se ujemajo z '{{entity}}'.", | |
227 | + "alarm-required": "Potreben je alarm", | |
228 | + "alarm-status": "Stanje alarma", | |
229 | + "alarm-status-list": "Seznam stanja alarma", | |
230 | + "any-status": "Kateri koli status", | |
231 | + "search-status": { | |
232 | + "ANY": "Katerikoli", | |
233 | + "ACTIVE": "Aktivno", | |
234 | + "CLEARED": "Počiščeno", | |
235 | + "ACK": "Potrjeno", | |
236 | + "UNACK": "Nepriznano" | |
237 | + }, | |
238 | + "display-status": { | |
239 | + "ACTIVE_UNACK": "Aktivno nepriznano", | |
240 | + "ACTIVE_ACK": "Aktivno potrjeno", | |
241 | + "CLEARED_UNACK": "Počiščeno nepriznano", | |
242 | + "CLEARED_ACK": "Počiščeno potrjeno" | |
243 | + }, | |
244 | + "no-alarms-prompt": "Ni najdenih alarmov", | |
245 | + "created-time": "Ustvarjeni čas", | |
246 | + "type": "Vrsta", | |
247 | + "severity": "Resnost", | |
248 | + "originator": "Izvirnik", | |
249 | + "originator-type": "Vrsta izvirnika", | |
250 | + "details": "Podrobnosti", | |
251 | + "status": "Stanje", | |
252 | + "alarm-details": "Podrobnosti alarma", | |
253 | + "start-time": "Začetni čas", | |
254 | + "end-time": "Končni čas", | |
255 | + "ack-time": "Priznani čas", | |
256 | + "clear-time": "Očiščen čas", | |
257 | + "alarm-severity-list": "Seznam resnosti alarma", | |
258 | + "any-severity": "Katerakoli resnost", | |
259 | + "severity-critical": "Kritična", | |
260 | + "severity-major": "Visoka", | |
261 | + "severity-minor": "Nizka", | |
262 | + "severity-warning": "Opozorilo", | |
263 | + "severity-indeterminate": "Nedoločeno", | |
264 | + "acknowledge": "Potrdi", | |
265 | + "clear": "Počisti", | |
266 | + "search": "Iskanje alarmov", | |
267 | + "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } izbran", | |
268 | + "no-data": "Ni podatkov za prikaz", | |
269 | + "polling-interval": "Interval iskanja alarmov (s)", | |
270 | + "polling-interval-required": "Zahtevan je interval glasovanja alarmov.", | |
271 | + "min-polling-interval-message": "Dovoljen je vsaj 1-sekundni interval glasovanja.", | |
272 | + "aknowledge-alarms-title": "Potrdite { count, plural, 1 {1 alarm} other {# alarms} }", | |
273 | + "aknowledge-alarms-text": "Ali ste prepričani, da želite potrditi { count, plural, 1 {1 alarm} other {# alarms} }?", | |
274 | + "aknowledge-alarm-title": "Potrdite alarm", | |
275 | + "aknowledge-alarm-text": "Ali ste prepričani, da želite potrditi alarm?", | |
276 | + "clear-alarms-title": "Počisti { count, plural, 1 {1 alarm} other {# alarmi} }", | |
277 | + "clear-alarms-text": "Ali ste prepričani, da želite počistiti { count, plural, 1 {1 alarm} other {# alarme} }?", | |
278 | + "clear-alarm-title": "Počisti alarm", | |
279 | + "clear-alarm-text": "Ali ste prepričani, da želite počistiti alarm?", | |
280 | + "alarm-status-filter": "Filter stanja alarma", | |
281 | + "alarm-filter": "Alarmni filter", | |
282 | + "max-count-load": "Največje število naloženih alarmov (0 - neomejeno)", | |
283 | + "max-count-load-required": "Zahtevano je največje število alarmov za nalaganje.", | |
284 | + "max-count-load-error-min": "Najmanjša vrednost je 0.", | |
285 | + "fetch-size": "Velikost prenosa", | |
286 | + "fetch-size-required": "Zahtevana je velikost prenosa.", | |
287 | + "fetch-size-error-min": "Najmanjša vrednost je 10.", | |
288 | + "alarm-type-list": "Seznam vrst alarmov", | |
289 | + "any-type": "Katerakoli vrsta", | |
290 | + "search-propagated-alarms": "Iskanje razširjenih alarmov" | |
291 | + }, | |
292 | + "alias": { | |
293 | + "add": "Dodaj vzdevek", | |
294 | + "edit": "Uredi vzdevek", | |
295 | + "name": "Ime vzdevka", | |
296 | + "name-required": "Ime vzdevka je obvezno", | |
297 | + "duplicate-alias": "Vzdevek z istim imenom že obstaja.", | |
298 | + "filter-type-single-entity": "Enota", | |
299 | + "filter-type-entity-list": "Seznam entitet", | |
300 | + "filter-type-entity-name": "Ime entitete", | |
301 | + "filter-type-state-entity": "Subjekt iz stanja nadzorne plošče", | |
302 | + "filter-type-state-entity-description": "Entiteta, vzeta iz parametrov stanja nadzorne plošče", | |
303 | + "filter-type-asset-type": "Vrsta sredstva", | |
304 | + "filter-type-asset-type-description": "Sredstva vrste '{{assetType}}'", | |
305 | + "filter-type-asset-type-and-name-description": "Sredstva vrste '{{assetType}}' in z imenom, ki se začne z '{{prefix}}'", | |
306 | + "filter-type-device-type": "Vrsta naprave", | |
307 | + "filter-type-device-type-description": "Naprave tipa '{{deviceType}}'", | |
308 | + "filter-type-device-type-and-name-description": "Naprave vrste '{{deviceType}}' in z imenom, ki se začne z '{{prefix}}'", | |
309 | + "filter-type-entity-view-type": "Vrsta pogleda entitete", | |
310 | + "filter-type-entity-view-type-description": "Pogledi entitet vrste '{{entityView}}'", | |
311 | + "filter-type-entity-view-type-and-name-description": "Pogledi entitet vrste '{{entityView}}' in z imenom, ki se začne z '{{prefix}}'", | |
312 | + "filter-type-relations-query": "Poizvedba odnosov", | |
313 | + "filter-type-relations-query-description": "{{entities}}, ki imajo {{relationType}} relacijo {{direction}} {{rootEntity}}", | |
314 | + "filter-type-asset-search-query": "Iskalna poizvedba sredstva", | |
315 | + "filter-type-asset-search-query-description": "Sredstva s tipi {{assetTypes}}, ki imajo {{relationType}} relacijo {{direction}} {{rootEntity}}", | |
316 | + "filter-type-device-search-query": "Iskalna poizvedba naprave", | |
317 | + "filter-type-device-search-query-description": "Naprave s tipi {{deviceTypes}}, ki imajo {{relationType}} relacijo {{direction}} {{rootEntity}}", | |
318 | + "filter-type-entity-view-search-query": "Iskalna poizvedba pogleda entitete", | |
319 | + "filter-type-entity-view-search-query-description": "Pogledi entitet s tipi {{entityViewTypes}}, ki imajo {{relationType}} relacijo {{direction}} {{rootEntity}}", | |
320 | + "filter-type-apiUsageState": "Api Usage State", | |
321 | + "entity-filter": "Filter entitet", | |
322 | + "resolve-multiple": "Reši kot več entitet", | |
323 | + "filter-type": "Vrsta filtra", | |
324 | + "filter-type-required": "Zahtevana je vrsta filtra.", | |
325 | + "entity-filter-no-entity-matched": "Najdenih ni nobenih entitet, ki se ujemajo z navedenim filtrom.", | |
326 | + "no-entity-filter-specified": "Ni določen noben filter entitete", | |
327 | + "root-state-entity": "Uporabi entiteto stanja na nadzorni plošči kot izvorno", | |
328 | + "last-level-relation": "Pridobi samo razmerje na zadnji ravni", | |
329 | + "root-entity": "Izvorna entiteta", | |
330 | + "state-entity-parameter-name": "Ime parametra državne entitete", | |
331 | + "default-state-entity": "Privzeta državna entiteta", | |
332 | + "default-entity-parameter-name": "Privzeto", | |
333 | + "max-relation-level": "Najvišja stopnja relacije", | |
334 | + "unlimited-level": "Neomejena raven", | |
335 | + "state-entity": "Entiteta stanja nadzorne plošče", | |
336 | + "all-entities": "Vsi subjekti", | |
337 | + "any-relation": "katerikoli" | |
338 | + }, | |
339 | + "asset": { | |
340 | + "asset": "Sredstvo", | |
341 | + "assets": "Sredstva", | |
342 | + "management": "Upravljanje sredstev", | |
343 | + "view-assets": "Ogled sredstev", | |
344 | + "add": "Dodaj sredstvo", | |
345 | + "assign-to-customer": "Dodeli stranki", | |
346 | + "assign-asset-to-customer": "Dodeli sredstva stranki", | |
347 | + "assign-asset-to-customer-text": "Izberite sredstva, ki jih želite dodeliti stranki", | |
348 | + "no-assets-text": "Sredstva ni bilo mogoče najti", | |
349 | + "assign-to-customer-text": "Izberite stranko, ki bo dodelila sredstvo (-a)", | |
350 | + "public": "Javno", | |
351 | + "assignedToCustomer": "Dodeljeno stranki", | |
352 | + "make-public": "Naj bo sredstvo javno", | |
353 | + "make-private": "Naj bo sredstvo zasebno", | |
354 | + "unassign-from-customer": "Odjavi od stranke", | |
355 | + "delete": "Izbriši sredstvo", | |
356 | + "asset-public": "Sredstvo je javno", | |
357 | + "asset-type": "Vrsta sredstva", | |
358 | + "asset-type-required": "Zahtevana je vrsta sredstva.", | |
359 | + "select-asset-type": "Izberite vrsto sredstva", | |
360 | + "enter-asset-type": "Vnesite vrsto sredstva", | |
361 | + "any-asset": "Katerokoli sredstvo", | |
362 | + "no-asset-types-matching": "Najdena ni bila nobena vrsta sredstva, ki se ujema z '{{entitySubtype}}'.", | |
363 | + "asset-type-list-empty": "Izbrana ni nobena vrsta sredstva.", | |
364 | + "asset-types": "Vrste sredstev", | |
365 | + "name": "Ime", | |
366 | + "name-required": "Ime je obvezno.", | |
367 | + "description": "Opis", | |
368 | + "type": "Vrsta", | |
369 | + "type-required": "Tip je obvezen.", | |
370 | + "details": "Podrobnosti", | |
371 | + "events": "Dogodki", | |
372 | + "add-asset-text": "Dodaj novo sredstvo", | |
373 | + "asset-details": "Podrobnosti o sredstvih", | |
374 | + "assign-assets": "Dodelitev sredstev", | |
375 | + "assign-assets-text": "Stranki dodeli { count, plural, 1 {1 sredstvo} other {# assets} }", | |
376 | + "delete-assets": "Izbriši sredstva", | |
377 | + "unassign-assets": "Preklic dodelitve sredstev", | |
378 | + "unassign-assets-action-title": "Stranki ne dodeli { count, plural, 1 {1 sredstvo} other {# assets} }", | |
379 | + "assign-new-asset": "Dodeli novo sredstvo", | |
380 | + "delete-asset-title": "Ali ste prepričani, da želite izbrisati sredstvo '{{assetName}}'?", | |
381 | + "delete-asset-text": "Bodite previdni, po potrditvi bo sredstvo in vsi povezani podatki nepopravljivi.", | |
382 | + "delete-assets-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 sredstvo} other {# assets} }?", | |
383 | + "delete-assets-action-title": "Izbriši { count, plural, 1 {1 sredstvo} other {# assets} }", | |
384 | + "delete-assets-text": "Bodite previdni, po potrditvi bodo vsa izbrana sredstva odstranjena in vsi povezani podatki bodo postali nepopravljivi.", | |
385 | + "make-public-asset-title": "Ali ste prepričani, da želite sredstvo '{{assetName}}' objaviti kot javno?", | |
386 | + "make-public-asset-text": "Po potrditvi bodo sredstvo in vsi njegovi podatki javno dostopni in dostopni drugim.", | |
387 | + "make-private-asset-title": "Ali ste prepričani, da želite sredstvo '{{assetName}}' narediti zasebno?", | |
388 | + "make-private-asset-text": "Po potrditvi bodo sredstvo in vsi njegovi podatki postali zasebni in ne bodo dostopni drugim.", | |
389 | + "unassign-asset-title": "Ali ste prepričani, da želite dodeliti sredstvo '{{assetName}}'?", | |
390 | + "unassign-asset-text": "Po potrditvi sredstvo ne bo dodeljeno in stranka ne bo dostopna.", | |
391 | + "unassign-asset": "Preklic dodelitve sredstva", | |
392 | + "unassign-assets-title": "Ali ste prepričani, da želite odpovedati { count, plural, 1 {1 asset} other {# assets} }?", | |
393 | + "unassign-assets-text": "Po potrditvi vsa izbrana sredstva ne bodo dodeljena in stranka ne bo dostopna do njih.", | |
394 | + "copyId": "Kopiraj ID sredstva", | |
395 | + "idCopiedMessage": "ID sredstva je kopiran v odložišče", | |
396 | + "select-asset": "Izberi sredstvo", | |
397 | + "no-assets-matching": "Nobeno sredstvo, ki se ujema z '{{entity}}', ni bilo mogoče najti.", | |
398 | + "asset-required": "Zahtevano je sredstvo", | |
399 | + "name-starts-with": "Ime sredstva se začne z", | |
400 | + "import": "Uvozi sredstva", | |
401 | + "asset-file": "Datoteka sredstva", | |
402 | + "search": "Išči sredstva", | |
403 | + "selected-assets": "{ count, plural, 1 {1 asset} other {# assets} } izbrano", | |
404 | + "label": "Oznaka" | |
405 | + }, | |
406 | + "attribute": { | |
407 | + "attributes": "Lastnosti", | |
408 | + "latest-telemetry": "Najnovejša telemetrija", | |
409 | + "attributes-scope": "Obseg atributov entitete", | |
410 | + "scope-latest-telemetry": "Najnovejša telemetrija", | |
411 | + "scope-client": "Atributi odjemalca", | |
412 | + "scope-server": "Atributi strežnika", | |
413 | + "scope-shared": "Skupni atributi", | |
414 | + "add": "Dodaj atribut", | |
415 | + "key": "Ključ", | |
416 | + "last-update-time": "Čas zadnje posodobitve", | |
417 | + "key-required": "Potreben je ključ atributa.", | |
418 | + "value": "Vrednost", | |
419 | + "value-required": "Vrednost atributa je obvezna.", | |
420 | + "delete-attributes-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 attribute} other {# attributes} }?", | |
421 | + "delete-attributes-text": "Bodite previdni, po potrditvi bodo odstranjeni vsi izbrani atributi.", | |
422 | + "delete-attributes": "Izbriši atribute", | |
423 | + "enter-attribute-value": "Vnesite vrednost atributa", | |
424 | + "show-on-widget": "Pokaži na pripomočku", | |
425 | + "widget-mode": "Način pripomočka", | |
426 | + "next-widget": "Naslednji pripomoček", | |
427 | + "prev-widget": "Prejšnji pripomoček", | |
428 | + "add-to-dashboard": "Dodaj na nadzorno ploščo", | |
429 | + "add-widget-to-dashboard": "Dodaj pripomoček na nadzorno ploščo", | |
430 | + "selected-attributes": "{ count, plural, 1 {1 attribute} other {# attributes} } izbrano", | |
431 | + "selected-telemetry": "{ count, plural, 1 {1 telemetry unit} other {# telemetry units} } izbran", | |
432 | + "no-attributes-text": "Ni najdenih atributov", | |
433 | + "no-telemetry-text": "Telemetrija ni najdena" | |
434 | + }, | |
435 | + "api-usage": { | |
436 | + "api-usage": "Api Usage", | |
437 | + "data-points": "Data points", | |
438 | + "data-points-storage-days": "Data points storage days", | |
439 | + "email": "Email", | |
440 | + "email-messages": "Email messages", | |
441 | + "email-messages-daily-activity": "Email messages daily activity", | |
442 | + "email-messages-hourly-activity": "Email messages hourly activity", | |
443 | + "email-messages-monthly-activity": "Email messages monthly activity", | |
444 | + "exceptions": "Exceptions", | |
445 | + "executions": "Executions", | |
446 | + "javascript": "JavaScript", | |
447 | + "javascript-executions": "JavaScript executions", | |
448 | + "javascript-functions": "JavaScript functions", | |
449 | + "javascript-functions-daily-activity": "JavaScript functions daily activity", | |
450 | + "javascript-functions-hourly-activity": "JavaScript functions hourly activity", | |
451 | + "javascript-functions-monthly-activity": "JavaScript functions monthly activity", | |
452 | + "latest-error": "Latest Error", | |
453 | + "messages": "Messages", | |
454 | + "permanent-failures": "${entityName} Permanent Failures", | |
455 | + "permanent-timeouts": "${entityName} Permanent Timeouts", | |
456 | + "processing-failures": "${entityName} Processing Failures", | |
457 | + "processing-failures-and-timeouts": "Processing Failures and Timeouts", | |
458 | + "processing-timeouts": "${entityName} Processing Timeouts", | |
459 | + "queue-stats": "Queue Stats", | |
460 | + "rule-chain": "Rule Chain", | |
461 | + "rule-engine": "Rule Engine", | |
462 | + "rule-engine-daily-activity": "Rule Engine daily activity", | |
463 | + "rule-engine-executions": "Rule Engine executions", | |
464 | + "rule-engine-hourly-activity": "Rule Engine hourly activity", | |
465 | + "rule-engine-monthly-activity": "Rule Engine monthly activity", | |
466 | + "rule-engine-statistics": "Rule Engine Statistics", | |
467 | + "rule-node": "Rule Node", | |
468 | + "sms": "SMS", | |
469 | + "sms-messages": "SMS messages", | |
470 | + "sms-messages-daily-activity": "SMS messages daily activity", | |
471 | + "sms-messages-hourly-activity": "SMS messages hourly activity", | |
472 | + "sms-messages-monthly-activity": "SMS messages monthly activity", | |
473 | + "successful": "${entityName} Successful", | |
474 | + "telemetry": "Telemetry", | |
475 | + "telemetry-persistence": "Telemetry persistence", | |
476 | + "telemetry-persistence-daily-activity": "Telemetry persistence daily activity", | |
477 | + "telemetry-persistence-hourly-activity": "Telemetry persistence hourly activity", | |
478 | + "telemetry-persistence-monthly-activity": "Telemetry persistence monthly activity", | |
479 | + "transport": "Transport", | |
480 | + "transport-daily-activity": "Transport daily activity", | |
481 | + "transport-data-points": "Transport data points", | |
482 | + "transport-hourly-activity": "Transport hourly activity", | |
483 | + "transport-messages": "Transport messages", | |
484 | + "transport-monthly-activity": "Transport monthly activity", | |
485 | + "view-details": "View details", | |
486 | + "view-statistics": "View statistics" | |
487 | + }, | |
488 | + "audit-log": { | |
489 | + "audit": "Revizija", | |
490 | + "audit-logs": "Revizijski dnevniki", | |
491 | + "timestamp": "Časovni žig", | |
492 | + "entity-type": "Vrsta entitete", | |
493 | + "entity-name": "Ime entitete", | |
494 | + "user": "Uporabnik", | |
495 | + "type": "Vrsta", | |
496 | + "status": "Stanje", | |
497 | + "details": "Podrobnosti", | |
498 | + "type-added": "Dodano", | |
499 | + "type-deleted": "Izbrisano", | |
500 | + "type-updated": "Posodobljeno", | |
501 | + "type-attributes-updated": "Atributi posodobljeni", | |
502 | + "type-attributes-deleted": "Atributi izbrisani", | |
503 | + "type-rpc-call": "Klic RPC", | |
504 | + "type-credentials-updated": "Poverilnice posodobljene", | |
505 | + "type-assigned-to-customer": "Dodeljeno kupcu", | |
506 | + "type-unassigned-from-customer": "Odstop od stranke", | |
507 | + "type-activated": "Aktivirano", | |
508 | + "type-suspended": "Suspendirano", | |
509 | + "type-credentials-read": "Poverilnice prebrane", | |
510 | + "type-attributes-read": "Atributi prebrani", | |
511 | + "type-relation-add-or-update": "Razmerje posodobljeno", | |
512 | + "type-relation-delete": "Razmerje izbrisano", | |
513 | + "type-relations-delete": "Vse povezave izbrisane", | |
514 | + "type-alarm-ack": "Potrjeno", | |
515 | + "type-alarm-clear": "Počiščeno", | |
516 | + "type-login": "Vpiši se", | |
517 | + "type-logout": "Odjava", | |
518 | + "type-lockout": "Izključitev", | |
519 | + "status-success": "Uspeh", | |
520 | + "status-failure": "Neuspeh", | |
521 | + "audit-log-details": "Podrobnosti dnevnika revizije", | |
522 | + "no-audit-logs-prompt": "Ni najdenih dnevnikov", | |
523 | + "action-data": "Podatki o dejanju", | |
524 | + "failure-details": "Podrobnosti o napaki", | |
525 | + "search": "Išči dnevnike revizije", | |
526 | + "clear-search": "Počisti iskanje", | |
527 | + "type-assigned-from-tenant": "Dodeljeno od najemnika", | |
528 | + "type-assigned-to-tenant": "Dodeljeno najemniku", | |
529 | + "type-provision-success": "Device provisioned", | |
530 | + "type-provision-failure": "Device provisioning was failed" | |
531 | + }, | |
532 | + "confirm-on-exit": { | |
533 | + "message": "Imate neshranjene spremembe. Ali ste prepričani, da želite zapustiti to stran?", | |
534 | + "html-message": "Imate neshranjene spremembe. <br/> Ali ste prepričani, da želite zapustiti to stran?", | |
535 | + "title": "Neshranjene spremembe" | |
536 | + }, | |
537 | + "contact": { | |
538 | + "country": "Država", | |
539 | + "city": "Mesto", | |
540 | + "state": "Država / Regija", | |
541 | + "postal-code": "Poštna številka", | |
542 | + "postal-code-invalid": "Neveljavna oblika poštne številke.", | |
543 | + "address": "Naslov", | |
544 | + "address2": "Naslov 2", | |
545 | + "phone": "Telefon", | |
546 | + "email": "E-naslov", | |
547 | + "no-address": "Brez naslova" | |
548 | + }, | |
549 | + "common": { | |
550 | + "username": "Uporabniško ime", | |
551 | + "password": "Geslo", | |
552 | + "enter-username": "Vnesite uporabniško ime", | |
553 | + "enter-password": "Vnesite geslo", | |
554 | + "enter-search": "Vnesite iskanje", | |
555 | + "created-time": "Ustvarjeni čas", | |
556 | + "loading": "Nalaganje..." | |
557 | + }, | |
558 | + "content-type": { | |
559 | + "json": "Json", | |
560 | + "text": "Besedilo", | |
561 | + "binary": "Binarni (Base64)" | |
562 | + }, | |
563 | + "customer": { | |
564 | + "customer": "Stranka", | |
565 | + "customers": "Stranke", | |
566 | + "management": "Upravljanje strank", | |
567 | + "dashboard": "Nadzorna plošča stranke", | |
568 | + "dashboards": "Nadzorne plošče strank", | |
569 | + "devices": "Naprave za stranke", | |
570 | + "entity-views": "Pogledi stranke", | |
571 | + "assets": "Sredstva strank", | |
572 | + "public-dashboards": "Javne nadzorne plošče", | |
573 | + "public-devices": "Javne naprave", | |
574 | + "public-assets": "Javno sredstvo", | |
575 | + "public-entity-views": "Pogledi javnih subjektov", | |
576 | + "add": "Dodaj stranko", | |
577 | + "delete": "Izbriši stranko", | |
578 | + "manage-customer-users": "Upravljanje uporabniških strank", | |
579 | + "manage-customer-devices": "Upravljanje naprav strank", | |
580 | + "manage-customer-dashboards": "Upravljanje nadzornih plošč za stranke", | |
581 | + "manage-public-devices": "Upravljanje javnih naprav", | |
582 | + "manage-public-dashboards": "Upravljanje javnih nadzornih plošč", | |
583 | + "manage-customer-assets": "Upravljanje sredstev strank", | |
584 | + "manage-public-assets": "Upravljanje javnih sredstev", | |
585 | + "add-customer-text": "Dodaj novo stranko", | |
586 | + "no-customers-text": "Nobena stranka ni najdena", | |
587 | + "customer-details": "Podrobnosti o stranki", | |
588 | + "delete-customer-title": "Ali ste prepričani, da želite izbrisati stranko '{{customerTitle}}'?", | |
589 | + "delete-customer-text": "Previdno, po potrditvi bo stranka in vsi povezani podatki postali nepopravljivi.", | |
590 | + "delete-customers-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 customer} other {# customers} }?", | |
591 | + "delete-customers-action-title": "Izbriši { count, plural, 1 {1 customer} other {# customers} }", | |
592 | + "delete-customers-text": "Bodite previdni, po potrditvi bodo vse izbrane stranke odstranjene in vsi povezani podatki bodo postali nepopravljivi.", | |
593 | + "manage-users": "Upravljanje uporabnikov", | |
594 | + "manage-assets": "Upravljanje sredstev", | |
595 | + "manage-devices": "Upravljanje naprav", | |
596 | + "manage-dashboards": "Upravljanje nadzornih plošč", | |
597 | + "title": "Naslov", | |
598 | + "title-required": "Naslov je obvezen.", | |
599 | + "description": "Opis", | |
600 | + "details": "Podrobnosti", | |
601 | + "events": "Dogodki", | |
602 | + "copyId": "Kopiraj ID stranke", | |
603 | + "idCopiedMessage": "Id stranke je kopiran v odložišče", | |
604 | + "select-customer": "Izberi stranko", | |
605 | + "no-customers-matching": "Najdena ni bila nobena stranka, ki se ujema z '{{entity}}'.", | |
606 | + "customer-required": "Stranka je obvezna", | |
607 | + "select-default-customer": "Izberi privzeto stranko", | |
608 | + "default-customer": "Privzeta stranka", | |
609 | + "default-customer-required": "Za razhroščevanje nadzorne plošče na ravni najemnika je potrebna privzeta stranka", | |
610 | + "search": "Iskanje strank", | |
611 | + "selected-customers": "{ count, plural, 1 {1 customer} other {# customers} } izbrano" | |
612 | + }, | |
613 | + "datetime": { | |
614 | + "date-from": "Datum, od", | |
615 | + "time-from": "Čas od", | |
616 | + "date-to": "Datum do", | |
617 | + "time-to": "Čas do" | |
618 | + }, | |
619 | + "dashboard": { | |
620 | + "dashboard": "Nadzorna plošča", | |
621 | + "dashboards": "Nadzorne plošče", | |
622 | + "management": "Upravljanje z nadzorno ploščo", | |
623 | + "view-dashboards": "Ogled nadzornih plošč", | |
624 | + "add": "Dodaj nadzorno ploščo", | |
625 | + "assign-dashboard-to-customer": "Dodeli nadzorne plošče strankam", | |
626 | + "assign-dashboard-to-customer-text": "Izberite nadzorne plošče, ki jih želite dodeliti stranki", | |
627 | + "assign-to-customer-text": "Izberite stranko, ki bo dodelila nadzorno ploščo (-e)", | |
628 | + "assign-to-customer": "Dodeli stranki", | |
629 | + "unassign-from-customer": "Odvzemi stranki", | |
630 | + "make-public": "Naredi nadzorno ploščo javno", | |
631 | + "make-private": "Naj nadzorna plošča postane zasebna", | |
632 | + "manage-assigned-customers": "Upravljanje dodeljenih strank", | |
633 | + "assigned-customers": "Dodeljene stranke", | |
634 | + "assign-to-customers": "Dodeli nadzorne plošče strankam", | |
635 | + "assign-to-customers-text": "Izberite stranke, ki bodo dodelile nadzorno ploščo (-e)", | |
636 | + "unassign-from-customers": "Odstrani nadzorne plošče strankam", | |
637 | + "unassign-from-customers-text": "Na nadzorni plošči izberite stranke, ki jih želite odjaviti", | |
638 | + "no-dashboards-text": "Ni najdenih nadzornih plošč", | |
639 | + "no-widgets": "Pripomočki niso nastavljeni", | |
640 | + "add-widget": "Dodaj nov pripomoček", | |
641 | + "title": "Naslov", | |
642 | + "select-widget-title": "Izberi pripomoček", | |
643 | + "select-widget-subtitle": "Seznam razpoložljivih vrst gradnikov", | |
644 | + "delete": "Izbriši nadzorno ploščo", | |
645 | + "title-required": "Naslov je obvezen.", | |
646 | + "description": "Opis", | |
647 | + "details": "Podrobnosti", | |
648 | + "dashboard-details": "Podrobnosti o nadzorni plošči", | |
649 | + "add-dashboard-text": "Dodaj novo nadzorno ploščo", | |
650 | + "assign-dashboards": "Dodeli nadzorne plošče", | |
651 | + "assign-new-dashboard": "Dodeli novo nadzorno ploščo", | |
652 | + "assign-dashboards-text": "Strankam dodeli { count, plural, 1 {1 dashboard} other {# dashboards} }", | |
653 | + "unassign-dashboards-action-text": "Strankam ne dodeli { count, plural, 1 {1 dashboard} other {# dashboards} }", | |
654 | + "delete-dashboards": "Izbriši nadzorne plošče", | |
655 | + "unassign-dashboards": "Preklic dodelitve nadzornih plošč", | |
656 | + "unassign-dashboards-action-title": "Stranki odstrani { count, plural, 1 {1 dashboard} other {# dashboards} }", | |
657 | + "delete-dashboard-title": "Ali ste prepričani, da želite izbrisati nadzorno ploščo '{{dashboardTitle}}'?", | |
658 | + "delete-dashboard-text": "Previdno, po potrditvi bodo armaturna plošča in vsi povezani podatki nepopravljivi.", | |
659 | + "delete-dashboards-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 dashboard} other {# dashboards} }?", | |
660 | + "delete-dashboards-action-title": "Izbriši { count, plural, 1 {1 dashboard} other {# dashboards} }", | |
661 | + "delete-dashboards-text": "Bodite previdni, po potrditvi bodo vse izbrane nadzorne plošče odstranjene in vsi povezani podatki bodo postali nepopravljivi.", | |
662 | + "unassign-dashboard-title": "Ali ste prepričani, da želite odstraniti nadzorno ploščo '{{dashboardTitle}}'?", | |
663 | + "unassign-dashboard-text": "Po potrditvi bo nadzorna plošča odstranjena in nedostopna stranki.", | |
664 | + "unassign-dashboard": "Preklic dodelitve nadzorne plošče", | |
665 | + "unassign-dashboards-title": "Ali ste prepričani, da želite odstraniti { count, plural, 1 {1 dashboard} other {# dashboards} }?", | |
666 | + "unassign-dashboards-text": "Po potrditvi bodo vse izbrane nadzorne plošče odstranjene in nedostopne stranki.", | |
667 | + "public-dashboard-title": "Nadzorna plošča je zdaj javna", | |
668 | + "public-dashboard-text": "Vaša nadzorna plošča <b>{{dashboardTitle}}</b> je zdaj javna in dostopna prek naslednje javne <a href='{{publicLink}}' target='_blank'>povezave</a>", | |
669 | + "public-dashboard-notice": "<b>Opomba:</b> Ne pozabite objaviti sorodnih naprav za dostop do njihovih podatkov.", | |
670 | + "make-private-dashboard-title": "Ali ste prepričani, da želite nadzorno ploščo '{{dashboardTitle}}' narediti zasebno?", | |
671 | + "make-private-dashboard-text": "Po potrditvi bo nadzorna plošča postala zasebna in ne bo dostopna drugim.", | |
672 | + "make-private-dashboard": "Naj nadzorna plošča postane zasebna", | |
673 | + "socialshare-text": "'{{dashboardTitle}}' poganja ThingsBoard", | |
674 | + "socialshare-title": "'{{dashboardTitle}}' poganja ThingsBoard", | |
675 | + "select-dashboard": "Izberi nadzorno ploščo", | |
676 | + "no-dashboards-matching": "Najdena ni bila nobena nadzorna plošča, ki se ujema z '{{entity}}'.", | |
677 | + "dashboard-required": "Potrebna je nadzorna plošča.", | |
678 | + "select-existing": "Izberi obstoječo nadzorno ploščo", | |
679 | + "create-new": "Ustvari novo nadzorno ploščo", | |
680 | + "new-dashboard-title": "Nov naslov nadzorne plošče", | |
681 | + "open-dashboard": "Odpri nadzorno ploščo", | |
682 | + "set-background": "Nastavi ozadje", | |
683 | + "background-color": "Barva ozadja", | |
684 | + "background-image": "Slika ozadja", | |
685 | + "background-size-mode": "Način velikosti ozadja", | |
686 | + "no-image": "Izbrana ni nobena slika", | |
687 | + "drop-image": "Spustite sliko ali kliknite, da izberete datoteko za nalaganje.", | |
688 | + "settings": "Nastavitve", | |
689 | + "columns-count": "Število stolpcev", | |
690 | + "columns-count-required": "Število stolpcev je obvezno.", | |
691 | + "min-columns-count-message": "Dovoljeno je samo 10 najmanjših števcev stolpcev.", | |
692 | + "max-columns-count-message": "Dovoljeno je samo 1000 največje število stolpcev.", | |
693 | + "widgets-margins": "Razmik med pripomočki", | |
694 | + "margin-required": "Zahtevana je vrednost razmika.", | |
695 | + "min-margin-message": "Najmanjša dovoljena vrednost razmika je 0.", | |
696 | + "max-margin-message": "Največja dovoljena vrednost razmika je 50.", | |
697 | + "horizontal-margin": "Vodoravni razmik", | |
698 | + "horizontal-margin-required": "Zahtevana je horizontalna vrednost razmika.", | |
699 | + "min-horizontal-margin-message": "Najmanjša dovoljena vrednost vodoravnega razmika je 0.", | |
700 | + "max-horizontal-margin-message": "Največja dovoljena vrednost vodoravnega razmika je 50.", | |
701 | + "vertical-margin": "Navpični razmik", | |
702 | + "vertical-margin-required": "Zahtevana je navpična vrednost razmika.", | |
703 | + "min-vertical-margin-message": "Najmanjša dovoljena vrednost navpičnega razmika je 0.", | |
704 | + "max-vertical-margin-message": "Največja dovoljena vrednost navpičnega razmika je 50.", | |
705 | + "autofill-height": "Samodejno polnjenje višine postavitve", | |
706 | + "mobile-layout": "Nastavitve mobilne postavitve", | |
707 | + "mobile-row-height": "Višina mobilne vrstice, px", | |
708 | + "mobile-row-height-required": "Vrednost višine mobilne vrstice je obvezna.", | |
709 | + "min-mobile-row-height-message": "Najmanjša dovoljena vrednost višine mobilne vrstice je 5 slikovnih pik.", | |
710 | + "max-mobile-row-height-message": "Največja dovoljena vrednost višine mobilne vrstice je 200 slikovnih pik.", | |
711 | + "display-title": "Prikaži naslov nadzorne plošče", | |
712 | + "toolbar-always-open": "Orodna vrstica naj bo odprta", | |
713 | + "title-color": "Barva naslova", | |
714 | + "display-dashboards-selection": "Prikaži izbiro nadzornih plošč", | |
715 | + "display-entities-selection": "Prikaži izbor entitet", | |
716 | + "display-filters": "Prikaži filtre", | |
717 | + "display-dashboard-timewindow": "Prikaži časovno okno", | |
718 | + "display-dashboard-export": "Prikaži izvoz", | |
719 | + "import": "Uvozi nadzorno ploščo", | |
720 | + "export": "Izvozi nadzorno ploščo", | |
721 | + "export-failed-error": "Nadzorne plošče ni mogoče izvoziti: {{error}}", | |
722 | + "create-new-dashboard": "Ustvari novo nadzorno ploščo", | |
723 | + "dashboard-file": "Datoteka nadzorne plošče", | |
724 | + "invalid-dashboard-file-error": "Nadzorne plošče ni mogoče uvoziti: neveljavna struktura podatkov na nadzorni plošči.", | |
725 | + "dashboard-import-missing-aliases-title": "Konfiguriranje vzdevkov, ki jih uporablja uvožena nadzorna plošča", | |
726 | + "create-new-widget": "Ustvari nov pripomoček", | |
727 | + "import-widget": "Uvozi pripomoček", | |
728 | + "widget-file": "Datoteka pripomočka", | |
729 | + "invalid-widget-file-error": "Pripomočka ni mogoče uvoziti: neveljavna struktura podatkov pripomočka.", | |
730 | + "widget-import-missing-aliases-title": "Konfiguriranje vzdevkov, ki jih uporablja uvoženi gradnik", | |
731 | + "open-toolbar": "Odpri orodno vrstico armaturne plošče", | |
732 | + "close-toolbar": "Zapri orodno vrstico", | |
733 | + "configuration-error": "Napaka v konfiguraciji", | |
734 | + "alias-resolution-error-title": "Napaka pri konfiguraciji vzdevkov na nadzorni plošči", | |
735 | + "invalid-aliases-config": "Ni mogoče najti nobene naprave, ki se ujema z nekaterimi filtri vzdevkov. <br/> Prosimo, obrnite se na skrbnika, da odpravite to težavo.", | |
736 | + "select-devices": "Izberi naprave", | |
737 | + "assignedToCustomer": "Dodeljeno stranki", | |
738 | + "assignedToCustomers": "Dodeljeno strankam", | |
739 | + "public": "Javno", | |
740 | + "public-link": "Javna povezava", | |
741 | + "copy-public-link": "Kopiraj javno povezavo", | |
742 | + "public-link-copied-message": "Javna povezava na nadzorni plošči je bila kopirana v odložišče", | |
743 | + "manage-states": "Upravljanje stanj nadzorne plošče", | |
744 | + "states": "Stanja na nadzorni plošči", | |
745 | + "search-states": "Išči stanja na nadzorni plošči", | |
746 | + "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard state} } izbrano", | |
747 | + "edit-state": "Uredi stanje nadzorne plošče", | |
748 | + "delete-state": "Izbriši stanje armaturne plošče", | |
749 | + "add-state": "Dodaj stanje nadzorne plošče", | |
750 | + "no-states-text": "Ni nobene države", | |
751 | + "state": "Stanje nadzorne plošče", | |
752 | + "state-name": "Ime", | |
753 | + "state-name-required": "Ime stanja nadzorne plošče je obvezno.", | |
754 | + "state-id": "ID države", | |
755 | + "state-id-required": "ID stanja nadzorne plošče je obvezen.", | |
756 | + "state-id-exists": "Stanje nadzorne plošče z istim ID že obstaja.", | |
757 | + "is-root-state": "Izvorno stanje", | |
758 | + "delete-state-title": "Izbriši stanje nadzorne plošče", | |
759 | + "delete-state-text": "Ali ste prepričani, da želite izbrisati stanje nadzorne plošče z imenom '{{stateName}}'?", | |
760 | + "show-details": "Pokaži podrobnosti", | |
761 | + "hide-details": "Skrij podrobnosti", | |
762 | + "select-state": "Izberi ciljno stanje", | |
763 | + "state-controller": "Državni nadzornik", | |
764 | + "search": "Iskanje po nadzornih ploščah", | |
765 | + "selected-dashboards": "{ count, plural, 1 {1 dashboard} other {# dashboards} } izbrano" | |
766 | + }, | |
767 | + "datakey": { | |
768 | + "settings": "Nastavitve", | |
769 | + "advanced": "Napredno", | |
770 | + "label": "Oznaka", | |
771 | + "color": "Barva", | |
772 | + "units": "Poseben simbol za prikaz poleg vrednosti", | |
773 | + "decimals": "Število števk po plavajoči vejici", | |
774 | + "data-generation-func": "Funkcija ustvarjanja podatkov", | |
775 | + "use-data-post-processing-func": "Uporabi funkcijo naknadne obdelave podatkov", | |
776 | + "configuration": "Konfiguracija podatkovnega ključa", | |
777 | + "timeseries": "Časovne serije", | |
778 | + "attributes": "Lastnosti", | |
779 | + "entity-field": "Polje entitete", | |
780 | + "alarm": "Polja alarma", | |
781 | + "timeseries-required": "Potrebni so časovni nizi entitet.", | |
782 | + "timeseries-or-attributes-required": "Potrebni so časovni nizi / atributi entitet.", | |
783 | + "alarm-fields-timeseries-or-attributes-required": "Polja alarma ali časovni nizi / atributi entitet so obvezni.", | |
784 | + "maximum-timeseries-or-attributes": "Največ { count, plural, 1 {1 timeseries / attribute is allowed.} other {# timeseries / attributes are allowed} }", | |
785 | + "alarm-fields-required": "Polja alarma so obvezna.", | |
786 | + "function-types": "Vrste funkcij", | |
787 | + "function-types-required": "Zahtevane so vrste funkcij.", | |
788 | + "maximum-function-types": "Največ dovoljeno je { count, plural, 1 {1 type of function.} other {# vrste funkcij so dovoljene} }", | |
789 | + "time-description": "časovni žig trenutne vrednosti;", | |
790 | + "value-description": "trenutna vrednost;", | |
791 | + "prev-value-description": "rezultat prejšnjega klica funkcije;", | |
792 | + "time-prev-description": "časovni žig prejšnje vrednosti;", | |
793 | + "prev-orig-value-description": "prvotna prejšnja vrednost;" | |
794 | + }, | |
795 | + "datasource": { | |
796 | + "type": "Vrsta vira podatkov", | |
797 | + "name": "Ime", | |
798 | + "add-datasource-prompt": "Prosimo, dodajte vir podatkov" | |
799 | + }, | |
800 | + "details": { | |
801 | + "details": "Podrobnosti", | |
802 | + "edit-mode": "Način urejanja", | |
803 | + "edit-json": "Uredi JSON", | |
804 | + "toggle-edit-mode": "Preklopi način urejanja" | |
805 | + }, | |
806 | + "device": { | |
807 | + "device": "Naprava", | |
808 | + "device-required": "Naprava je potrebna.", | |
809 | + "devices": "Naprave", | |
810 | + "management": "Upravljanje naprav", | |
811 | + "view-devices": "Ogled naprav", | |
812 | + "device-alias": "Vzdevek naprave", | |
813 | + "aliases": "Vzdevki naprav", | |
814 | + "no-alias-matching": "'{{alias}}' ni mogoče najti.", | |
815 | + "no-aliases-found": "Vzdevkov ni bilo mogoče najti.", | |
816 | + "no-key-matching": "'{{key}}' ni mogoče najti.", | |
817 | + "no-keys-found": "Ključev ni bilo mogoče najti.", | |
818 | + "create-new-alias": "Ustvari novega!", | |
819 | + "create-new-key": "Ustvari novega!", | |
820 | + "duplicate-alias-error": "Najden je podvojen vzdevek '{{alias}}'. <br> Vzdevki naprav morajo biti na nadzorni plošči edinstveni.", | |
821 | + "configure-alias": "Konfiguriraj vzdevek '{{alias}}'", | |
822 | + "no-devices-matching": "Najdena ni bila nobena naprava, ki se ujema z '{{entity}}'.", | |
823 | + "alias": "Vzdevek", | |
824 | + "alias-required": "Vzdevek naprave je obvezen.", | |
825 | + "remove-alias": "Odstrani vzdevek naprave", | |
826 | + "add-alias": "Dodaj vzdevek naprave", | |
827 | + "name-starts-with": "Ime naprave se začne z", | |
828 | + "device-list": "Seznam naprav", | |
829 | + "use-device-name-filter": "Uporabi filter", | |
830 | + "device-list-empty": "Izbrana ni nobena naprava.", | |
831 | + "device-name-filter-required": "Potreben je filter imena naprave.", | |
832 | + "device-name-filter-no-device-matched": "Najdena ni bila nobena naprava, ki se začne z '{{device}}'.", | |
833 | + "add": "Dodaj napravo", | |
834 | + "assign-to-customer": "Dodeli stranki", | |
835 | + "assign-device-to-customer": "Dodeli naprave strankam", | |
836 | + "assign-device-to-customer-text": "Izberite naprave, ki jih želite dodeliti stranki", | |
837 | + "make-public": "Naredi napravo javno", | |
838 | + "make-private": "Naj bo naprava zasebna", | |
839 | + "no-devices-text": "Naprave ni bilo mogoče najti", | |
840 | + "assign-to-customer-text": "Prosimo, izberite stranko, ki bo dodelila naprave (-e)", | |
841 | + "device-details": "Podrobnosti o napravi", | |
842 | + "add-device-text": "Dodaj novo napravo", | |
843 | + "credentials": "Poverilnice", | |
844 | + "manage-credentials": "Upravljanje poverilnic", | |
845 | + "delete": "Izbriši napravo", | |
846 | + "assign-devices": "Dodeli naprave", | |
847 | + "assign-devices-text": "Kupcu dodeli { count, plural, 1 {1 device} other {# devices} }", | |
848 | + "delete-devices": "Izbriši naprave", | |
849 | + "unassign-from-customer": "Odjavi od stranke", | |
850 | + "unassign-devices": "Odjavi naprave", | |
851 | + "unassign-devices-action-title": "Odstrani { count, plural, 1 {1 device} other {# devices} } od stranke", | |
852 | + "assign-new-device": "Dodeli novo napravo", | |
853 | + "make-public-device-title": "Ali ste prepričani, da želite napravo '{{deviceName}}' narediti javno?", | |
854 | + "make-public-device-text": "Po potrditvi bo naprava in vsi njeni podatki javno dostopni drugim.", | |
855 | + "make-private-device-title": "Ali ste prepričani, da želite napravo '{{deviceName}}' narediti zasebno?", | |
856 | + "make-private-device-text": "Po potrditvi bo naprava in vsi njeni podatki postali zasebni in nedostopni drugim.", | |
857 | + "view-credentials": "Ogled poverilnic", | |
858 | + "delete-device-title": "Ali ste prepričani, da želite izbrisati napravo '{{deviceName}}'?", | |
859 | + "delete-device-text": "Previdno, po potrditvi naprava in vsi povezani podatki postanejo nepopravljivi.", | |
860 | + "delete-devices-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 device} other {# naprav} }?", | |
861 | + "delete-devices-action-title": "Izbriši { count, plural, 1 {1 device} other {# devices} }", | |
862 | + "delete-devices-text": "Bodite previdni, po potrditvi bodo vse izbrane naprave odstranjene in vsi povezani podatki nepopravljivi.", | |
863 | + "unassign-device-title": "Ali ste prepričani, da želite odstraniti napravo '{{deviceName}}'?", | |
864 | + "unassign-device-text": "Po potrditvi naprava ne bo dodeljena in nedostopna stranki.", | |
865 | + "unassign-device": "Preklic dodelitve naprave", | |
866 | + "unassign-devices-title": "Ali ste prepričani, da želite odstraniti { count, plural, 1 {1 device} other {# naprave} }?", | |
867 | + "unassign-devices-text": "Po potrditvi bodo vse izbrane naprave nedodeljene in nedostopne stranki.", | |
868 | + "device-credentials": "Poverilnice naprave", | |
869 | + "credentials-type": "Vrsta poverilnic", | |
870 | + "access-token": "Dostopni žeton", | |
871 | + "access-token-required": "Zahtevan je žeton za dostop.", | |
872 | + "access-token-invalid": "Dolžina žetona za dostop mora biti od 1 do 20 znakov.", | |
873 | + "rsa-key": "Javni ključ RSA", | |
874 | + "rsa-key-required": "Potreben je javni ključ RSA.", | |
875 | + "client-id": "Client ID", | |
876 | + "client-id-pattern": "Contains invalid character.", | |
877 | + "user-name": "User Name", | |
878 | + "user-name-required": "User Name is required.", | |
879 | + "client-id-or-user-name-necessary": "Client ID and/or User Name are necessary", | |
880 | + "password": "Password", | |
881 | + "secret": "Skrivnost", | |
882 | + "secret-required": "Potrebna je skrivnost.", | |
883 | + "device-type": "Vrsta naprave", | |
884 | + "device-type-required": "Zahtevana je vrsta naprave.", | |
885 | + "select-device-type": "Izberite vrsto naprave", | |
886 | + "enter-device-type": "Vnesite vrsto naprave", | |
887 | + "any-device": "Katerakoli naprava", | |
888 | + "no-device-types-matching": "Najdena ni bila nobena vrsta naprave, ki se ujema z '{{entitySubtype}}'.", | |
889 | + "device-type-list-empty": "Izbrana ni nobena vrsta naprave.", | |
890 | + "device-types": "Vrste naprav", | |
891 | + "name": "Ime", | |
892 | + "name-required": "Ime je obvezno.", | |
893 | + "description": "Opis", | |
894 | + "label": "Oznaka", | |
895 | + "events": "Dogodki", | |
896 | + "details": "Podrobnosti", | |
897 | + "copyId": "Kopiraj ID naprave", | |
898 | + "copyAccessToken": "Kopiraj žeton za dostop", | |
899 | + "copy-mqtt-authentication": "Copy MQTT credentials", | |
900 | + "idCopiedMessage": "ID naprave je bil kopiran v odložišče", | |
901 | + "accessTokenCopiedMessage": "Žeton za dostop do naprave je bil kopiran v odložišče", | |
902 | + "mqtt-authentication-copied-message": "Device MQTT authentication has been copied to clipboard", | |
903 | + "assignedToCustomer": "Dodeljeno stranki", | |
904 | + "unable-delete-device-alias-title": "Vzdevka naprave ni mogoče izbrisati", | |
905 | + "unable-delete-device-alias-text": "Vzdevka naprave '{{deviceAlias}}' ni mogoče izbrisati, saj ga uporabljajo naslednji pripomočki: <br/> {{widgetsList}}", | |
906 | + "is-gateway": "Je prehod", | |
907 | + "public": "Javno", | |
908 | + "device-public": "Naprava je javna", | |
909 | + "select-device": "Izberi napravo", | |
910 | + "import": "Uvozi napravo", | |
911 | + "device-file": "Datoteka naprave", | |
912 | + "search": "Iskalne naprave", | |
913 | + "selected-devices": "{ count, plural, 1 {1 device} other {# devices} } izbrano", | |
914 | + "device-configuration": "Device configuration", | |
915 | + "transport-configuration": "Transport configuration", | |
916 | + "wizard": { | |
917 | + "device-wizard": "Device Wizard", | |
918 | + "device-details": "Device details", | |
919 | + "new-device-profile": "Create new device profile", | |
920 | + "existing-device-profile": "Select existing device profile", | |
921 | + "specific-configuration": "Specific configuration", | |
922 | + "customer-to-assign-device": "Customer to assign the device", | |
923 | + "add-credential": "Add credential" | |
924 | + } | |
925 | + }, | |
926 | + "device-profile": { | |
927 | + "device-profile": "Device profile", | |
928 | + "device-profiles": "Device profiles", | |
929 | + "all-device-profiles": "All", | |
930 | + "add": "Add device profile", | |
931 | + "edit": "Edit device profile", | |
932 | + "device-profile-details": "Device profile details", | |
933 | + "no-device-profiles-text": "No device profiles found", | |
934 | + "search": "Search device profiles", | |
935 | + "selected-device-profiles": "{ count, plural, 1 {1 device profile} other {# device profiles} } selected", | |
936 | + "no-device-profiles-matching": "No device profile matching '{{entity}}' were found.", | |
937 | + "device-profile-required": "Device profile is required", | |
938 | + "idCopiedMessage": "Device profile Id has been copied to clipboard", | |
939 | + "set-default": "Make device profile default", | |
940 | + "delete": "Delete device profile", | |
941 | + "copyId": "Copy device profile Id", | |
942 | + "new-device-profile-name": "Device profile name", | |
943 | + "new-device-profile-name-required": "Device profile name is required.", | |
944 | + "name": "Name", | |
945 | + "name-required": "Name is required.", | |
946 | + "type": "Profile type", | |
947 | + "type-required": "Profile type is required.", | |
948 | + "type-default": "Default", | |
949 | + "transport-type": "Transport type", | |
950 | + "transport-type-required": "Transport type is required.", | |
951 | + "transport-type-default": "Default", | |
952 | + "transport-type-default-hint": "Supports basic MQTT, HTTP and CoAP transport", | |
953 | + "transport-type-mqtt": "MQTT", | |
954 | + "transport-type-mqtt-hint": "Enables advanced MQTT transport settings", | |
955 | + "transport-type-lwm2m": "LWM2M", | |
956 | + "transport-type-lwm2m-hint": "LWM2M transport type", | |
957 | + "description": "Description", | |
958 | + "default": "Default", | |
959 | + "profile-configuration": "Profile configuration", | |
960 | + "transport-configuration": "Transport configuration", | |
961 | + "default-rule-chain": "Default rule chain", | |
962 | + "select-queue-hint": "Select from a drop-down list or add a custom name.", | |
963 | + "delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?", | |
964 | + "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.", | |
965 | + "delete-device-profiles-title": "Are you sure you want to delete { count, plural, 1 {1 device profile} other {# device profiles} }?", | |
966 | + "delete-device-profiles-text": "Be careful, after the confirmation all selected device profiles will be removed and all related data will become unrecoverable.", | |
967 | + "set-default-device-profile-title": "Are you sure you want to make the device profile '{{deviceProfileName}}' default?", | |
968 | + "set-default-device-profile-text": "After the confirmation the device profile will be marked as default and will be used for new devices with no profile specified.", | |
969 | + "no-device-profiles-found": "No device profiles found.", | |
970 | + "create-new-device-profile": "Create a new one!", | |
971 | + "mqtt-device-topic-filters": "MQTT device topic filters", | |
972 | + "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.", | |
973 | + "mqtt-device-payload-type": "MQTT device payload", | |
974 | + "mqtt-device-payload-type-json": "JSON", | |
975 | + "mqtt-device-payload-type-proto": "Protobuf", | |
976 | + "mqtt-payload-type-required": "Payload type is required.", | |
977 | + "support-level-wildcards": "Single <code>[+]</code> and multi-level <code>[#]</code> wildcards supported.", | |
978 | + "telemetry-topic-filter": "Telemetry topic filter", | |
979 | + "telemetry-topic-filter-required": "Telemetry topic filter is required.", | |
980 | + "attributes-topic-filter": "Attributes topic filter", | |
981 | + "attributes-topic-filter-required": "Attributes topic filter is required.", | |
982 | + "telemetry-proto-schema": "Telemetry proto schema", | |
983 | + "telemetry-proto-schema-required": "Telemetry proto schema is required.", | |
984 | + "attributes-proto-schema": "Attributes proto schema", | |
985 | + "attributes-proto-schema-required": "Attributes proto schema is required.", | |
986 | + "rpc-response-topic-filter": "RPC response topic filter", | |
987 | + "rpc-response-topic-filter-required": "RPC response topic filter is required.", | |
988 | + "not-valid-pattern-topic-filter": "Not valid pattern topic filter", | |
989 | + "not-valid-single-character": "Invalid use of a single-level wildcard character", | |
990 | + "not-valid-multi-character": "Invalid use of a multi-level wildcard character", | |
991 | + "single-level-wildcards-hint": "<code>[+]</code> is suitable for any topic filter level. Ex.: <b>v1/devices/+/telemetry</b> or <b>+/devices/+/attributes</b>.", | |
992 | + "multi-level-wildcards-hint": "<code>[#]</code> can replace the topic filter itself and must be the last symbol of the topic. Ex.: <b>#</b> or <b>v1/devices/me/#</b>.", | |
993 | + "alarm-rules": "Alarm rules", | |
994 | + "alarm-rules-with-count": "Alarm rules ({{count}})", | |
995 | + "no-alarm-rules": "No alarm rules configured", | |
996 | + "add-alarm-rule": "Add alarm rule", | |
997 | + "edit-alarm-rule": "Edit alarm rule", | |
998 | + "alarm-type": "Alarm type", | |
999 | + "alarm-type-required": "Alarm type is required.", | |
1000 | + "alarm-type-unique": "Alarm type must be unique within the device profile alarm rules.", | |
1001 | + "create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm", | |
1002 | + "create-alarm-rules": "Create alarm rules", | |
1003 | + "no-create-alarm-rules": "No create conditions configured", | |
1004 | + "add-create-alarm-rule-prompt": "Please add create alarm rule", | |
1005 | + "clear-alarm-rule": "Clear alarm rule", | |
1006 | + "no-clear-alarm-rule": "No clear condition configured", | |
1007 | + "add-create-alarm-rule": "Add create condition", | |
1008 | + "add-clear-alarm-rule": "Add clear condition", | |
1009 | + "select-alarm-severity": "Select alarm severity", | |
1010 | + "alarm-severity-required": "Alarm severity is required.", | |
1011 | + "condition-duration": "Condition duration", | |
1012 | + "condition-duration-value": "Duration value", | |
1013 | + "condition-duration-time-unit": "Time unit", | |
1014 | + "condition-duration-value-range": "Duration value should be in a range from 1 to 2147483647.", | |
1015 | + "condition-duration-value-pattern": "Duration value should be integers.", | |
1016 | + "condition-duration-value-required": "Duration value is required.", | |
1017 | + "condition-duration-time-unit-required": "Time unit is required.", | |
1018 | + "advanced-settings": "Advanced settings", | |
1019 | + "alarm-rule-details": "Details", | |
1020 | + "add-alarm-rule-details": "Add details", | |
1021 | + "propagate-alarm": "Propagate alarm", | |
1022 | + "alarm-rule-relation-types-list": "Relation types to propagate", | |
1023 | + "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", | |
1024 | + "alarm-details": "Alarm details", | |
1025 | + "alarm-rule-condition": "Alarm rule condition", | |
1026 | + "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", | |
1027 | + "edit-alarm-rule-condition": "Edit alarm rule condition", | |
1028 | + "device-provisioning": "Device provisioning", | |
1029 | + "provision-strategy": "Provision strategy", | |
1030 | + "provision-strategy-required": "Provision strategy is required.", | |
1031 | + "provision-strategy-disabled": "Disabled", | |
1032 | + "provision-strategy-created-new": "Allow to create new devices", | |
1033 | + "provision-strategy-check-pre-provisioned": "Check for pre-provisioned devices", | |
1034 | + "provision-device-key": "Provision device key", | |
1035 | + "provision-device-key-required": "Provision device key is required.", | |
1036 | + "copy-provision-key": "Copy provision key", | |
1037 | + "provision-key-copied-message": "Provision key has been copied to clipboard", | |
1038 | + "provision-device-secret": "Provision device secret", | |
1039 | + "provision-device-secret-required": "Provision device secret is required.", | |
1040 | + "copy-provision-secret": "Copy provision secret", | |
1041 | + "provision-secret-copied-message": "Provision secret has been copied to clipboard", | |
1042 | + "condition": "Condition", | |
1043 | + "condition-type": "Condition type", | |
1044 | + "condition-type-simple": "Simple", | |
1045 | + "condition-type-duration": "Duration", | |
1046 | + "condition-during": "During {{during}}", | |
1047 | + "condition-type-repeating": "Repeating", | |
1048 | + "condition-type-required": "Condition type is required.", | |
1049 | + "condition-repeating-value": "Count of events", | |
1050 | + "condition-repeating-value-range": "Count of events should be in a range from 1 to 2147483647.", | |
1051 | + "condition-repeating-value-pattern": "Count of events should be integers.", | |
1052 | + "condition-repeating-value-required": "Count of events is required.", | |
1053 | + "condition-repeat-times": "Repeats { count, plural, 1 {1 time} other {# times} }", | |
1054 | + "schedule-type": "Scheduler type", | |
1055 | + "schedule-type-required": "Scheduler type is required.", | |
1056 | + "schedule": "Schedule", | |
1057 | + "edit-schedule": "Edit alarm schedule", | |
1058 | + "schedule-any-time": "Active all the time", | |
1059 | + "schedule-specific-time": "Active at a specific time", | |
1060 | + "schedule-custom": "Custom", | |
1061 | + "schedule-day": { | |
1062 | + "monday": "Monday", | |
1063 | + "tuesday": "Tuesday", | |
1064 | + "wednesday": "Wednesday", | |
1065 | + "thursday": "Thursday", | |
1066 | + "friday": "Friday", | |
1067 | + "saturday": "Saturday", | |
1068 | + "sunday": "Sunday" | |
1069 | + }, | |
1070 | + "schedule-days": "Days", | |
1071 | + "schedule-time": "Time", | |
1072 | + "schedule-time-from": "From", | |
1073 | + "schedule-time-to": "To", | |
1074 | + "schedule-days-of-week-required": "At least one day of week should be selected." | |
1075 | + }, | |
1076 | + "dialog": { | |
1077 | + "close": "Zapri pogovorno okno" | |
1078 | + }, | |
1079 | + "direction": { | |
1080 | + "column": "Stolpec", | |
1081 | + "row": "Vrstica" | |
1082 | + }, | |
1083 | + "error": { | |
1084 | + "unable-to-connect": "Povezave s strežnikom ni mogoče vzpostaviti! Preverite internetno povezavo.", | |
1085 | + "unhandled-error-code": "Neobdelana koda napake: {{errorCode}}", | |
1086 | + "unknown-error": "Neznana napaka" | |
1087 | + }, | |
1088 | + "entity": { | |
1089 | + "entity": "Entiteta", | |
1090 | + "entities": "Subjekti", | |
1091 | + "aliases": "Vzdevki entitet", | |
1092 | + "entity-alias": "Vzdevek entitete", | |
1093 | + "unable-delete-entity-alias-title": "Vzdevka entitete ni mogoče izbrisati", | |
1094 | + "unable-delete-entity-alias-text": "Vzdevka entitete '{{entityAlias}}' ni mogoče izbrisati, ker ga uporabljajo naslednji pripomočki: <br/> {{widgetsList}}", | |
1095 | + "duplicate-alias-error": "Najden je podvojen vzdevek '{{alias}}'. <br> Vzdevki entitet morajo biti na nadzorni plošči edinstveni.", | |
1096 | + "missing-entity-filter-error": "Za vzdevek '{{alias}}' manjka filter.", | |
1097 | + "configure-alias": "Konfiguriraj vzdevek '{{alias}}'", | |
1098 | + "alias": "Vzdevek", | |
1099 | + "alias-required": "Zahtevan je vzdevek entitete.", | |
1100 | + "remove-alias": "Odstrani vzdevek entitete", | |
1101 | + "add-alias": "Dodaj vzdevek entitete", | |
1102 | + "entity-list": "Seznam entitet", | |
1103 | + "entity-type": "Vrsta entitete", | |
1104 | + "entity-types": "Vrste entitet", | |
1105 | + "entity-type-list": "Seznam entitet", | |
1106 | + "any-entity": "Katerikoli subjekt", | |
1107 | + "enter-entity-type": "Vnesite vrsto entitete", | |
1108 | + "no-entities-matching": "Najdena ni bila nobena enota, ki se ujema z '{{entity}}'.", | |
1109 | + "no-entity-types-matching": "Najdena ni bila nobena vrsta entitete, ki se ujema z '{{entityType}}'.", | |
1110 | + "name-starts-with": "Ime se začne z", | |
1111 | + "use-entity-name-filter": "Uporabi filter", | |
1112 | + "entity-list-empty": "Nobena entiteta ni izbrana.", | |
1113 | + "entity-type-list-empty": "Izbrana ni nobena vrsta entitete.", | |
1114 | + "entity-name-filter-required": "Potreben je filter imena entitete.", | |
1115 | + "entity-name-filter-no-entity-matched": "Najti ni bilo nobene entitete, ki se začne z '{{entity}}'.", | |
1116 | + "all-subtypes": "Vse", | |
1117 | + "select-entities": "Izberi entitete", | |
1118 | + "no-aliases-found": "Vzdevkov ni bilo mogoče najti.", | |
1119 | + "no-alias-matching": "'{{alias}}' ni mogoče najti.", | |
1120 | + "create-new-alias": "Ustvari novega!", | |
1121 | + "key": "Ključ", | |
1122 | + "key-name": "Ime ključa", | |
1123 | + "no-keys-found": "Ključev ni bilo mogoče najti.", | |
1124 | + "no-key-matching": "'{{key}}' ni mogoče najti.", | |
1125 | + "create-new-key": "Ustvari novega!", | |
1126 | + "type": "Vrsta", | |
1127 | + "type-required": "Zahteva se vrsta entitete.", | |
1128 | + "type-device": "Naprava", | |
1129 | + "type-devices": "Naprave", | |
1130 | + "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", | |
1131 | + "device-name-starts-with": "Naprave, katerih imena se začnejo z '{{prefix}}'", | |
1132 | + "type-device-profile": "Device profile", | |
1133 | + "type-device-profiles": "Device profiles", | |
1134 | + "list-of-device-profiles": "{ count, plural, 1 {One device profile} other {List of # device profiles} }", | |
1135 | + "device-profile-name-starts-with": "Device profiles whose names start with '{{prefix}}'", | |
1136 | + "type-asset": "Sredstvo", | |
1137 | + "type-assets": "Sredstva", | |
1138 | + "list-of-assets": "{ count, plural, 1 {One asset} other {Seznam # sredstev} }", | |
1139 | + "asset-name-starts-with": "Sredstva, katerih imena se začnejo z '{{prefix}}'", | |
1140 | + "type-entity-view": "Pogled entitete", | |
1141 | + "type-entity-views": "Pogledi entitet", | |
1142 | + "list-of-entity-views": "{ count, plural, 1 {One entity view} other {Seznam # pogledov entitet} }", | |
1143 | + "entity-view-name-starts-with": "Pogledi entitet, katerih imena se začnejo z '{{prefix}}'", | |
1144 | + "type-rule": "Pravilo", | |
1145 | + "type-rules": "Pravila", | |
1146 | + "list-of-rules": "{ count, plural, 1 {One rule} other {Seznam # pravil} }", | |
1147 | + "rule-name-starts-with": "Pravila, katerih imena se začnejo z '{{prefix}}'", | |
1148 | + "type-plugin": "Vključiti", | |
1149 | + "type-plugins": "Vtičniki", | |
1150 | + "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }", | |
1151 | + "plugin-name-starts-with": "Vtičniki, katerih imena se začnejo z '{{prefix}}'", | |
1152 | + "type-tenant": "Najemnik", | |
1153 | + "type-tenants": "Najemniki", | |
1154 | + "list-of-tenants": "{ count, plural, 1 {One najemnik} other {Seznam # najemnikov} }", | |
1155 | + "tenant-name-starts-with": "Najemniki, katerih imena se začnejo z '{{prefix}}'", | |
1156 | + "type-tenant-profile": "Tenant profile", | |
1157 | + "type-tenant-profiles": "Tenant profiles", | |
1158 | + "list-of-tenant-profiles": "{ count, plural, 1 {One tenant profile} other {List of # tenant profiles} }", | |
1159 | + "tenant-profile-name-starts-with": "Tenant profiles whose names start with '{{prefix}}'", | |
1160 | + "type-customer": "Stranka", | |
1161 | + "type-customers": "Stranke", | |
1162 | + "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", | |
1163 | + "customer-name-starts-with": "Stranke, katerih imena se začnejo z '{{prefix}}'", | |
1164 | + "type-user": "Uporabnik", | |
1165 | + "type-users": "Uporabniki", | |
1166 | + "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }", | |
1167 | + "user-name-starts-with": "Uporabniki, katerih imena se začnejo z '{{prefix}}'", | |
1168 | + "type-dashboard": "Nadzorna plošča", | |
1169 | + "type-dashboards": "Nadzorne plošče", | |
1170 | + "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }", | |
1171 | + "dashboard-name-starts-with": "Nadzorne plošče, katerih imena se začnejo z '{{prefix}}'", | |
1172 | + "type-alarm": "Alarm", | |
1173 | + "type-alarms": "Alarmi", | |
1174 | + "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", | |
1175 | + "alarm-name-starts-with": "Alarmi, katerih imena se začnejo z '{{prefix}}'", | |
1176 | + "type-rulechain": "Veriga pravil", | |
1177 | + "type-rulechains": "Pravila", | |
1178 | + "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", | |
1179 | + "rulechain-name-starts-with": "Verige pravil, katerih imena se začnejo z '{{prefix}}'", | |
1180 | + "type-rulenode": "Vozlišče pravila", | |
1181 | + "type-rulenodes": "Vozlišča pravil", | |
1182 | + "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }", | |
1183 | + "rulenode-name-starts-with": "Vozlišča pravil, katerih imena se začnejo z '{{prefix}}'", | |
1184 | + "type-current-customer": "Trenutna stranka", | |
1185 | + "type-current-tenant": "Trenutni najemnik", | |
1186 | + "type-current-user": "Trenutni uporabnik", | |
1187 | + "type-current-user-owner": "Trenutni lastnik uporabnika", | |
1188 | + "search": "Iskanje entitet", | |
1189 | + "selected-entities": "{ count, plural, 1 {1 entity} other {# entitet} } izbranih", | |
1190 | + "entity-name": "Ime entitete", | |
1191 | + "entity-label": "Oznaka entitete", | |
1192 | + "details": "Podrobnosti o entiteti", | |
1193 | + "no-entities-prompt": "Ni entitet", | |
1194 | + "no-data": "Ni podatkov za prikaz", | |
1195 | + "columns-to-display": "Stolpci za prikaz", | |
1196 | + "type-api-usage-state": "Api Usage State" | |
1197 | + }, | |
1198 | + "entity-field": { | |
1199 | + "created-time": "Čas ustvaritve", | |
1200 | + "name": "Ime", | |
1201 | + "type": "Vrsta", | |
1202 | + "first-name": "Ime", | |
1203 | + "last-name": "Priimek", | |
1204 | + "email": "E-naslov", | |
1205 | + "title": "Naziv", | |
1206 | + "country": "Država", | |
1207 | + "state": "Država", | |
1208 | + "city": "Mesto", | |
1209 | + "address": "Naslov", | |
1210 | + "address2": "Naslov 2", | |
1211 | + "zip": "Poštna številka", | |
1212 | + "phone": "Telefon", | |
1213 | + "label": "Oznaka" | |
1214 | + }, | |
1215 | + "entity-view": { | |
1216 | + "entity-view": "Pogled entitete", | |
1217 | + "entity-view-required": "Zahtevan je pogled entitete.", | |
1218 | + "entity-views": "Pogledi entitet", | |
1219 | + "management": "Upravljanje entitetnega pogleda", | |
1220 | + "view-entity-views": "Ogled pogledov entitete", | |
1221 | + "entity-view-alias": "Vzdevek entitetnega pogleda", | |
1222 | + "aliases": "Vzdevki entitetnega pogleda", | |
1223 | + "no-alias-matching": "'{{alias}}' ni mogoče najti.", | |
1224 | + "no-aliases-found": "Vzdevkov ni bilo mogoče najti.", | |
1225 | + "no-key-matching": "'{{key}}' ni mogoče najti.", | |
1226 | + "no-keys-found": "Ključev ni bilo mogoče najti.", | |
1227 | + "create-new-alias": "Ustvari novega!", | |
1228 | + "create-new-key": "Ustvari novega!", | |
1229 | + "duplicate-alias-error": "Najden je podvojen vzdevek '{{alias}}'. <br> Vzdevki entitetnega pogleda na nadzorni plošči morajo biti edinstveni.", | |
1230 | + "configure-alias": "Konfiguriraj vzdevek '{{alias}}'", | |
1231 | + "no-entity-views-matching": "Najden ni bil noben pogled entitete, ki se ujema z '{{entity}}'.", | |
1232 | + "public": "Javno", | |
1233 | + "alias": "Vzdevek", | |
1234 | + "alias-required": "Zahtevan je vzdevek pogleda entitete.", | |
1235 | + "remove-alias": "Odstrani vzdevek pogleda entitete", | |
1236 | + "add-alias": "Dodaj vzdevek pogleda entitete", | |
1237 | + "name-starts-with": "Ime entitete se začne z", | |
1238 | + "entity-view-list": "Seznam entitetnega pogleda", | |
1239 | + "use-entity-view-name-filter": "Uporabi filter", | |
1240 | + "entity-view-list-empty": "Izbran ni noben pogled entitete.", | |
1241 | + "entity-view-name-filter-required": "Potreben je filter imena pogleda entitete.", | |
1242 | + "entity-view-name-filter-no-entity-view-matched": "Najden ni bil noben pogled entitete, ki se začne z '{{entityView}}'.", | |
1243 | + "add": "Dodaj pogled entitete", | |
1244 | + "entity-view-public": "Pogled entitete je javen", | |
1245 | + "assign-to-customer": "Dodeli stranki", | |
1246 | + "assign-entity-view-to-customer": "Dodelitev pogledov entitet strankam", | |
1247 | + "assign-entity-view-to-customer-text": "Izberite poglede entitet, ki jih želite dodeliti stranki", | |
1248 | + "no-entity-views-text": "Ni najden noben pogled entitete", | |
1249 | + "assign-to-customer-text": "Izberite stranko, ki bo dodelila poglede entitet", | |
1250 | + "entity-view-details": "Podrobnosti o pogledu entitete", | |
1251 | + "add-entity-view-text": "Dodaj nov pogled entitete", | |
1252 | + "delete": "Izbriši pogled entitete", | |
1253 | + "assign-entity-views": "Dodelitev pogledov entitete", | |
1254 | + "assign-entity-views-text": "Stranki dodeli { count, plural, 1 {1 entity view} other {# entity views} }", | |
1255 | + "delete-entity-views": "Izbriši poglede entitet", | |
1256 | + "unassign-from-customer": "Odstrani od stranke", | |
1257 | + "unassign-entity-views": "Odstrani poglede entitete", | |
1258 | + "unassign-entity-views-action-title": "Od stranke odstrani { count, plural, 1 {1 entity view} other {# entity views} }", | |
1259 | + "assign-new-entity-view": "Dodeli nov pogled entitete", | |
1260 | + "delete-entity-view-title": "Ali ste prepričani, da želite izbrisati pogled entitete '{{entityViewName}}'?", | |
1261 | + "delete-entity-view-text": "Bodite previdni, po potrditvi bodo pogled entitete in vsi povezani podatki nepopravljivi.", | |
1262 | + "delete-entity-views-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 entity view} other {# entity views} }?", | |
1263 | + "delete-entity-views-action-title": "Izbriši { count, plural, 1 {1 entity view} other {# entity views} }", | |
1264 | + "delete-entity-views-text": "Bodite previdni, po potrditvi bodo odstranjeni vsi pogledi izbranih entitet in vsi povezani podatki bodo postali nepopravljivi.", | |
1265 | + "unassign-entity-view-title": "Ali ste prepričani, da želite odstraniti pogled entitete '{{entityViewName}}?", | |
1266 | + "unassign-entity-view-text": "Po potrditvi bo pogled entitete odstranjen in nedostopen stranki.", | |
1267 | + "unassign-entity-view": "Odstrani pogled entitete", | |
1268 | + "unassign-entity-views-title": "Ali ste prepričani, da želite odstraniti { count, plural, 1 {1 entity view} other {# entity views} }?", | |
1269 | + "unassign-entity-views-text": "Po potrditvi bodo vsi pogledi izbranih entitet odstranjeni in stranki nedostopni.", | |
1270 | + "entity-view-type": "Vrsta pogleda entitete", | |
1271 | + "entity-view-type-required": "Zahteva se vrsta pogleda entitete.", | |
1272 | + "select-entity-view-type": "Izberi vrsto pogleda entitete", | |
1273 | + "enter-entity-view-type": "Vnesite vrsto pogleda entitete", | |
1274 | + "any-entity-view": "Katerikoli pogled entitete", | |
1275 | + "no-entity-view-types-matching": "Najdena ni bila nobena vrsta pogleda entitete, ki se ujema z '{{entitySubtype}}'.", | |
1276 | + "entity-view-type-list-empty": "Izbrana ni nobena vrsta pogleda entitete.", | |
1277 | + "entity-view-types": "Vrste pogleda entitete", | |
1278 | + "created-time": "Ustvarjeni čas", | |
1279 | + "name": "Ime", | |
1280 | + "name-required": "Ime je obvezno.", | |
1281 | + "description": "Opis", | |
1282 | + "events": "Dogodki", | |
1283 | + "details": "Podrobnosti", | |
1284 | + "copyId": "Kopiraj ID pogleda entitete", | |
1285 | + "idCopiedMessage": "ID entitete je kopiran v odložišče", | |
1286 | + "assignedToCustomer": "Dodeljeno stranki", | |
1287 | + "unable-entity-view-device-alias-title": "Ni mogoče izbrisati vzdevka pogleda entitete", | |
1288 | + "unable-entity-view-device-alias-text": "Vzdevka naprave '{{entityViewAlias}}' ni mogoče izbrisati, saj ga uporabljajo naslednji pripomočki: <br/> {{widgetsList}}", | |
1289 | + "select-entity-view": "Izberi pogled entitete", | |
1290 | + "make-public": "Naj bo pogled entitete javen", | |
1291 | + "make-private": "Naj bo pogled entitete zaseben", | |
1292 | + "start-date": "Začetni datum", | |
1293 | + "start-ts": "Začetni čas", | |
1294 | + "end-date": "Končni datum", | |
1295 | + "end-ts": "Končni čas", | |
1296 | + "date-limits": "Datumske omejitve", | |
1297 | + "client-attributes": "Atributi odjemalca", | |
1298 | + "shared-attributes": "Skupni atributi", | |
1299 | + "server-attributes": "Atributi strežnika", | |
1300 | + "timeseries": "Časovne serije", | |
1301 | + "client-attributes-placeholder": "Atributi odjemalca", | |
1302 | + "shared-attributes-placeholder": "Skupni atributi", | |
1303 | + "server-attributes-placeholder": "Atributi strežnika", | |
1304 | + "timeseries-placeholder": "Časovne serije", | |
1305 | + "target-entity": "Ciljna entiteta", | |
1306 | + "attributes-propagation": "Propragacija atributov", | |
1307 | + "attributes-propagation-hint": "Pogled entitete bo samodejno kopiral določene atribute iz ciljne entitete vsakič, ko shranite ali posodobite ta pogled entitete. Zaradi učinkovitosti se atributi ciljne entitete ne propagirajo v pogled entitete pri vsaki spremembi atributa. Samodejno propagacijo lahko omogočite tako, da konfigurirate \" kopiraj v ogled\" vozlišče pravila v verigi pravil in povezovanje sporočil \"Objavi atribute\" in \"Atributi posodobljeni\" na novo vozlišče pravila.", | |
1308 | + "timeseries-data": "Podatki časovnih serij", | |
1309 | + "timeseries-data-hint": "Konfigurirajte podatkovne ključe časovnih serij ciljne entitete, ki bodo dostopne pogledu entitete. Ti podatki časovnih serij so samo za branje.", | |
1310 | + "make-public-entity-view-title": "Ali ste prepričani, da želite pogled entitete '{{entityViewName}}' narediti javen?", | |
1311 | + "make-public-entity-view-text": "Po potrditvi bodo pogled entitete in vsi njegovi podatki javni in dostopni drugim.", | |
1312 | + "make-private-entity-view-title": "Ali ste prepričani, da želite pogled entitete '{{entityViewName}}' narediti zaseben?", | |
1313 | + "make-private-entity-view-text": "Po potrditvi bodo pogled entitete in vsi njegovi podatki postali zasebni in drugim nedostopni.", | |
1314 | + "search": "Išči poglede entitet", | |
1315 | + "selected-entity-views": "{ count, plural, 1 {1 entity view} other {# entity views} } izbranih" | |
1316 | + }, | |
1317 | + "event": { | |
1318 | + "event-type": "Vrsta dogodka", | |
1319 | + "type-error": "Napaka", | |
1320 | + "type-lc-event": "Dogodek življenjskega cikla", | |
1321 | + "type-stats": "Statistika", | |
1322 | + "type-debug-rule-node": "Odpravljanje napak", | |
1323 | + "type-debug-rule-chain": "Odpravljanje napak", | |
1324 | + "no-events-prompt": "Ni dogodkov", | |
1325 | + "error": "Napaka", | |
1326 | + "alarm": "Alarm", | |
1327 | + "event-time": "Čas dogodka", | |
1328 | + "server": "Strežnik", | |
1329 | + "body": "Vsebina", | |
1330 | + "method": "Metoda", | |
1331 | + "type": "Vrsta", | |
1332 | + "entity": "Entiteta", | |
1333 | + "message-id": "ID sporočila", | |
1334 | + "message-type": "Vrsta sporočila", | |
1335 | + "data-type": "Vrsta podatkov", | |
1336 | + "relation-type": "Vrsta povezave", | |
1337 | + "metadata": "Metapodatki", | |
1338 | + "data": "Podatki", | |
1339 | + "event": "Dogodek", | |
1340 | + "status": "Stanje", | |
1341 | + "success": "Uspeh", | |
1342 | + "failed": "Ni uspelo", | |
1343 | + "messages-processed": "Obdelana sporočila", | |
1344 | + "errors-occurred": "Prišlo je do napak" | |
1345 | + }, | |
1346 | + "extension": { | |
1347 | + "extensions": "Razširitve", | |
1348 | + "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} } izbrano", | |
1349 | + "type": "Vrsta", | |
1350 | + "key": "Ključ", | |
1351 | + "value": "Vrednost", | |
1352 | + "id": "ID", | |
1353 | + "extension-id": "ID razširitve", | |
1354 | + "extension-type": "Vrsta razširitve", | |
1355 | + "transformer-json": "JSON *", | |
1356 | + "unique-id-required": "Trenutni ID razširitve že obstaja.", | |
1357 | + "delete": "Izbriši razširitev", | |
1358 | + "add": "Dodaj razširitev", | |
1359 | + "edit": "Uredi razširitev", | |
1360 | + "delete-extension-title": "Ali ste prepričani, da želite izbrisati razširitev '{{extensionId}}'?", | |
1361 | + "delete-extension-text": "Bodite previdni, po potrditvi podaljšanje in vsi povezani podatki ne bodo več obnovljivi.", | |
1362 | + "delete-extensions-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 extension} other {# extensions} }?", | |
1363 | + "delete-extensions-text": "Previdno, po potrditvi bodo odstranjene vse izbrane razširitve.", | |
1364 | + "converters": "Pretvorniki", | |
1365 | + "converter-id": "ID pretvornika", | |
1366 | + "configuration": "Konfiguracija", | |
1367 | + "converter-configurations": "Konfiguracije pretvornika", | |
1368 | + "token": "Varnostni žeton", | |
1369 | + "add-converter": "Dodaj pretvornik", | |
1370 | + "add-config": "Dodaj konfiguracijo pretvornika", | |
1371 | + "device-name-expression": "Izraz imena naprave", | |
1372 | + "device-type-expression": "Izraz vrste naprave", | |
1373 | + "custom": "Po meri", | |
1374 | + "to-double": "Podvojiti", | |
1375 | + "transformer": "Transformator", | |
1376 | + "json-required": "Transformator json je potreben.", | |
1377 | + "json-parse": "Ni mogoče razčleniti transformatorja json.", | |
1378 | + "attributes": "Lastnosti", | |
1379 | + "add-attribute": "Dodaj atribut", | |
1380 | + "add-map": "Dodaj element preslikave", | |
1381 | + "timeseries": "Časovne serije", | |
1382 | + "add-timeseries": "Dodaj časovne vrste", | |
1383 | + "field-required": "Polje je obvezno", | |
1384 | + "brokers": "Posredniki", | |
1385 | + "add-broker": "Dodaj posrednika", | |
1386 | + "host": "Gostitelj", | |
1387 | + "port": "Pristanišče", | |
1388 | + "port-range": "Vrata naj bodo v območju od 1 do 65535.", | |
1389 | + "ssl": "SSL", | |
1390 | + "credentials": "Poverilnice", | |
1391 | + "username": "Uporabniško ime", | |
1392 | + "password": "Geslo", | |
1393 | + "retry-interval": "Interval ponovitve v milisekundah", | |
1394 | + "anonymous": "Anonimno", | |
1395 | + "basic": "Osnovno", | |
1396 | + "pem": "PEM", | |
1397 | + "ca-cert": "Datoteka potrdila CA *", | |
1398 | + "private-key": "Datoteka z zasebnim ključem *", | |
1399 | + "cert": "Datoteka s potrdilom *", | |
1400 | + "no-file": "Izbrana ni nobena datoteka.", | |
1401 | + "drop-file": "Spustite datoteko ali kliknite, da izberete datoteko za nalaganje.", | |
1402 | + "mapping": "Preslikava", | |
1403 | + "topic-filter": "Glavni filter", | |
1404 | + "converter-type": "Vrsta pretvornika", | |
1405 | + "converter-json": "Json", | |
1406 | + "json-name-expression": "Izraz json imena naprave", | |
1407 | + "topic-name-expression": "Izraz teme imena naprave", | |
1408 | + "json-type-expression": "Tip naprave json izraz", | |
1409 | + "topic-type-expression": "Izraz teme naprave", | |
1410 | + "attribute-key-expression": "Izraz ključnega atributa", | |
1411 | + "attr-json-key-expression": "Izraz json ključa atributa", | |
1412 | + "attr-topic-key-expression": "Atribut ključne besede izraza", | |
1413 | + "request-id-expression": "Zahtevaj izraz za id", | |
1414 | + "request-id-json-expression": "Zahtevaj izraz json id", | |
1415 | + "request-id-topic-expression": "Zahtevaj izraz teme za id", | |
1416 | + "response-topic-expression": "Izraz teme odziva", | |
1417 | + "value-expression": "Vrednostni izraz", | |
1418 | + "topic": "Tema", | |
1419 | + "timeout": "Časovna omejitev v milisekundah", | |
1420 | + "converter-json-required": "Potreben je pretvornik json.", | |
1421 | + "converter-json-parse": "Ni mogoče razčleniti pretvornika json.", | |
1422 | + "filter-expression": "Filtriraj izraz", | |
1423 | + "connect-requests": "Zahteve za povezovanje", | |
1424 | + "add-connect-request": "Dodaj zahtevo za povezavo", | |
1425 | + "disconnect-requests": "Prekini zahteve", | |
1426 | + "add-disconnect-request": "Dodaj zahtevo za prekinitev povezave", | |
1427 | + "attribute-requests": "Zahteve za atribute", | |
1428 | + "add-attribute-request": "Dodaj zahtevo za atribut", | |
1429 | + "attribute-updates": "Posodobitve atributov", | |
1430 | + "add-attribute-update": "Dodaj posodobitev atributa", | |
1431 | + "server-side-rpc": "RPC na strežniški strani", | |
1432 | + "add-server-side-rpc-request": "Dodaj zahtevo RPC na strani strežnika", | |
1433 | + "device-name-filter": "Filter imena naprave", | |
1434 | + "attribute-filter": "Filter atributov", | |
1435 | + "method-filter": "Filter metode", | |
1436 | + "request-topic-expression": "Zahtevaj izraz teme", | |
1437 | + "response-timeout": "Časovna omejitev odziva v milisekundah", | |
1438 | + "topic-expression": "Izraz teme", | |
1439 | + "client-scope": "Obseg stranke", | |
1440 | + "add-device": "Dodaj napravo", | |
1441 | + "opc-server": "Strežniki", | |
1442 | + "opc-add-server": "Dodaj strežnik", | |
1443 | + "opc-add-server-prompt": "Prosimo, dodajte strežnik", | |
1444 | + "opc-application-name": "Ime aplikacije", | |
1445 | + "opc-application-uri": "Uri aplikacije", | |
1446 | + "opc-scan-period-in-seconds": "Obdobje skeniranja v sekundah", | |
1447 | + "opc-security": "Varnost", | |
1448 | + "opc-identity": "Identiteta", | |
1449 | + "opc-keystore": "Trgovina s ključi", | |
1450 | + "opc-type": "Vrsta", | |
1451 | + "opc-keystore-type": "Vrsta", | |
1452 | + "opc-keystore-location": "Lokacija *", | |
1453 | + "opc-keystore-password": "Geslo", | |
1454 | + "opc-keystore-alias": "Vzdevek", | |
1455 | + "opc-keystore-key-password": "Ključno geslo", | |
1456 | + "opc-device-node-pattern": "Vzorec vozlišča naprave", | |
1457 | + "opc-device-name-pattern": "Vzorec imena naprave", | |
1458 | + "modbus-server": "Strežniki / podrejeni", | |
1459 | + "modbus-add-server": "Dodaj strežnik / podrejen", | |
1460 | + "modbus-add-server-prompt": "Prosimo, dodajte strežnik / podrejen", | |
1461 | + "modbus-transport": "Prenos", | |
1462 | + "modbus-tcp-reconnect": "Samodejno ponovno vzpostavi povezavo", | |
1463 | + "modbus-rtu-over-tcp": "RTU prek TCP", | |
1464 | + "modbus-port-name": "Ime serijskih vrat", | |
1465 | + "modbus-encoding": "Kodiranje", | |
1466 | + "modbus-parity": "Parnost", | |
1467 | + "modbus-baudrate": "Hitrost prenosa", | |
1468 | + "modbus-databits": "Podatkovni bit", | |
1469 | + "modbus-stopbits": "Stop bits", | |
1470 | + "modbus-databits-range": "Podatkovni bit mora biti v območju od 7 do 8.", | |
1471 | + "modbus-stopbits-range": "Stop bitov mora biti v območju od 1 do 2.", | |
1472 | + "modbus-unit-id": "ID enote", | |
1473 | + "modbus-unit-id-range": "ID enote mora biti v območju od 1 do 247.", | |
1474 | + "modbus-device-name": "Ime naprave", | |
1475 | + "modbus-poll-period": "Obdobje ankete (ms)", | |
1476 | + "modbus-attributes-poll-period": "Obdobje ankete atributov (ms)", | |
1477 | + "modbus-timeseries-poll-period": "Obdobje ankete časovnih serij (ms)", | |
1478 | + "modbus-poll-period-range": "Obdobje ankete mora imeti pozitivno vrednost.", | |
1479 | + "modbus-tag": "Oznaka", | |
1480 | + "modbus-function": "Funkcija", | |
1481 | + "modbus-register-address": "Registrski naslov", | |
1482 | + "modbus-register-address-range": "Naslov registra mora biti v območju od 0 do 65535.", | |
1483 | + "modbus-register-bit-index": "Bitni indeks", | |
1484 | + "modbus-register-bit-index-range": "Bitni indeks naj bo v območju od 0 do 15.", | |
1485 | + "modbus-register-count": "Število registra", | |
1486 | + "modbus-register-count-range": "Število registra mora biti pozitivna vrednost.", | |
1487 | + "modbus-byte-order": "Vrstni red bajtov", | |
1488 | + "sync": { | |
1489 | + "status": "Stanje", | |
1490 | + "sync": "Sinhronizacija", | |
1491 | + "not-sync": "Ni sinhronizacija", | |
1492 | + "last-sync-time": "Čas zadnje sinhronizacije", | |
1493 | + "not-available": "Ni na voljo" | |
1494 | + }, | |
1495 | + "export-extensions-configuration": "Izvozi konfiguracijo razširitev", | |
1496 | + "import-extensions-configuration": "Uvozi konfiguracijo razširitev", | |
1497 | + "import-extensions": "Uvozi razširitve", | |
1498 | + "import-extension": "Uvozi razširitev", | |
1499 | + "export-extension": "Razširitev izvoza", | |
1500 | + "file": "Razširitvena datoteka", | |
1501 | + "invalid-file-error": "Neveljavna datoteka razširitve" | |
1502 | + }, | |
1503 | + "filter": { | |
1504 | + "add": "Dodaj filter", | |
1505 | + "edit": "Uredi filter", | |
1506 | + "name": "Ime filtra", | |
1507 | + "name-required": "Ime filtra je obvezno.", | |
1508 | + "duplicate-filter": "Filter z istim imenom že obstaja.", | |
1509 | + "filters": "Filtri", | |
1510 | + "unable-delete-filter-title": "Filtra ni mogoče izbrisati", | |
1511 | + "unable-delete-filter-text": "Filtra '{{filter}}' ni mogoče izbrisati, kot ga uporabljajo naslednji pripomočki:<br/>{{widgetsList}}", | |
1512 | + "duplicate-filter-error": "Najden je podvojen filter '{{filter}}'.<br>Filtri morajo biti na nadzorni plošči edinstveni.", | |
1513 | + "missing-key-filters-error": "Za filter '{{filter}}' manjkajo ključni filtri.", | |
1514 | + "filter": "Filter", | |
1515 | + "editable": "Urejanje", | |
1516 | + "no-filters-found": "Ni najden noben filter.", | |
1517 | + "no-filter-text": "No filter specified", | |
1518 | + "add-filter-prompt": "Please add filter", | |
1519 | + "no-filter-matching": "'{{filter}}' ni mogoče najti.", | |
1520 | + "create-new-filter": "Ustvari novega!", | |
1521 | + "filter-required": "Potreben je filter.", | |
1522 | + "operation": { | |
1523 | + "operation": "Dejanje", | |
1524 | + "equal": "enako", | |
1525 | + "not-equal": "ni enako", | |
1526 | + "starts-with": "začne se z", | |
1527 | + "ends-with": "konča se z", | |
1528 | + "contains": "vsebuje", | |
1529 | + "not-contains": "ne vsebuje", | |
1530 | + "greater": "večji kot", | |
1531 | + "less": "manj kot", | |
1532 | + "greater-or-equal": "večje ali enako", | |
1533 | + "less-or-equal": "manjše ali enako", | |
1534 | + "and": "in", | |
1535 | + "or": "ali" | |
1536 | + }, | |
1537 | + "ignore-case": "Prezri črko", | |
1538 | + "value": "Vrednost", | |
1539 | + "remove-filter": "Odstrani filter", | |
1540 | + "preview": "Predogled filtra", | |
1541 | + "no-filters": "Ni nastavljenih filtrov", | |
1542 | + "add-filter": "Dodaj filter", | |
1543 | + "add-complex-filter": "Dodaj kompleksni filter", | |
1544 | + "add-complex": "Dodaj kompleks", | |
1545 | + "complex-filter": "Kompleksni filter", | |
1546 | + "edit-complex-filter": "Uredi kompleksni filter", | |
1547 | + "edit-filter-user-params": "Uredi uporabniške parametre predikata filtra", | |
1548 | + "filter-user-params": "Filter predicate user parameters", | |
1549 | + "user-parameters": "Uporabniški parametri", | |
1550 | + "display-label": "Oznaka za prikaz", | |
1551 | + "autogenerated-label": "Samodejno ustvari oznako", | |
1552 | + "order-priority": "Prednostni vrstni red", | |
1553 | + "key-filter": "Ključni filter", | |
1554 | + "key-filters": "Ključni filtri", | |
1555 | + "key-name": "Ime ključa", | |
1556 | + "key-name-required": "Ime ključa je obvezno.", | |
1557 | + "key-type": { | |
1558 | + "key-type": "Tip ključa", | |
1559 | + "attribute": "Atribut", | |
1560 | + "timeseries": "Časovne serije", | |
1561 | + "entity-field": "Polje entitete" | |
1562 | + }, | |
1563 | + "value-type": { | |
1564 | + "value-type": "Vrsta vrednosti", | |
1565 | + "string": "Niz", | |
1566 | + "numeric": "Številska", | |
1567 | + "boolean": "Logična", | |
1568 | + "date-time": "Datum in čas" | |
1569 | + }, | |
1570 | + "value-type-required": "Zahtevana je vrsta vrednosti ključa.", | |
1571 | + "key-value-type-change-title": "Ali ste prepričani, da želite spremeniti vrsto vrednosti ključa?", | |
1572 | + "key-value-type-change-message": "Če potrdite novo vrsto vrednosti, bodo odstranjeni vsi vneseni filtri ključev.", | |
1573 | + "no-key-filters": "Noben ključni filter ni konfiguriran", | |
1574 | + "add-key-filter": "Dodaj ključni filter", | |
1575 | + "remove-key-filter": "Odstrani filter ključev", | |
1576 | + "edit-key-filter": "Uredi filter ključev", | |
1577 | + "date": "Datum", | |
1578 | + "time": "Čas", | |
1579 | + "current-tenant": "Trenutni najemnik", | |
1580 | + "current-customer": "Trenutna stranka", | |
1581 | + "current-user": "Trenutni uporabnik", | |
1582 | + "current-device": "Current device", | |
1583 | + "default-value": "Privzeta vrednost", | |
1584 | + "dynamic-source-type": "Dinamična vrsta vira", | |
1585 | + "no-dynamic-value": "Ni dinamične vrednosti", | |
1586 | + "source-attribute": "Izvorni atribut", | |
1587 | + "switch-to-dynamic-value": "Preklopi na dinamično vrednost", | |
1588 | + "switch-to-default-value": "Preklopi na privzeto vrednost" | |
1589 | + }, | |
1590 | + "fullscreen": { | |
1591 | + "expand": "Razširi na celozaslonski način", | |
1592 | + "exit": "Izhod iz celozaslonskega načina", | |
1593 | + "toggle": "Preklopi na celozaslonski način", | |
1594 | + "fullscreen": "Celozaslonski način" | |
1595 | + }, | |
1596 | + "function": { | |
1597 | + "function": "Funkcija" | |
1598 | + }, | |
1599 | + "gateway": { | |
1600 | + "add-entry": "Dodaj konfiguracijo", | |
1601 | + "connector-add": "Dodaj nov priključek", | |
1602 | + "connector-enabled": "Omogoči priključek", | |
1603 | + "connector-name": "Ime priključka", | |
1604 | + "connector-name-required": "Ime priključka je obvezno.", | |
1605 | + "connector-type": "Vrsta priključka", | |
1606 | + "connector-type-required": "Zahteva se vrsta priključka.", | |
1607 | + "connectors": "Konfiguracija priključkov", | |
1608 | + "create-new-gateway": "Ustvari nov prehod", | |
1609 | + "create-new-gateway-text": "Ali ste prepričani, da želite ustvariti nov prehod z imenom: '{{gatewayName}}'?", | |
1610 | + "delete": "Izbriši konfiguracijo", | |
1611 | + "download-tip": "Prenos konfiguracijske datoteke", | |
1612 | + "gateway": "Prehod", | |
1613 | + "gateway-exists": "Naprava z istim imenom že obstaja.", | |
1614 | + "gateway-name": "Ime prehoda", | |
1615 | + "gateway-name-required": "Ime prehoda je obvezno.", | |
1616 | + "gateway-saved": "Konfiguracija prehoda je uspešno shranjena.", | |
1617 | + "json-parse": "Neveljaven JSON.", | |
1618 | + "json-required": "Polje ne sme biti prazno.", | |
1619 | + "no-connectors": "Ni priključkov", | |
1620 | + "no-data": "Brez konfiguracij", | |
1621 | + "no-gateway-found": "Prehod ni najden.", | |
1622 | + "no-gateway-matching": " '{{item}}' ni mogoče najti.", | |
1623 | + "path-logs": "Pot do dnevniških datotek", | |
1624 | + "path-logs-required": "Pot je obvezna.", | |
1625 | + "remote": "Oddaljena konfiguracija", | |
1626 | + "remote-logging-level": "Raven beleženja", | |
1627 | + "remove-entry": "Odstrani konfiguracijo", | |
1628 | + "save-tip": "Shrani konfiguracijsko datoteko", | |
1629 | + "security-type": "Vrsta zaščite", | |
1630 | + "security-types": { | |
1631 | + "access-token": "Dostopni žeton", | |
1632 | + "tls": "TLS" | |
1633 | + }, | |
1634 | + "storage": "Shramba", | |
1635 | + "storage-max-file-records": "Največ zapisov v datoteki", | |
1636 | + "storage-max-files": "Največje število datotek", | |
1637 | + "storage-max-files-min": "Najmanjše število je 1.", | |
1638 | + "storage-max-files-pattern": "Številka ni veljavna.", | |
1639 | + "storage-max-files-required": "Številka je obvezna.", | |
1640 | + "storage-max-records": "Največ zapisov v pomnilniku", | |
1641 | + "storage-max-records-min": "Najmanjše število zapisov je 1.", | |
1642 | + "storage-max-records-pattern": "Številka ni veljavna.", | |
1643 | + "storage-max-records-required": "Zahtevan je največ zapisov.", | |
1644 | + "storage-pack-size": "Največja velikost paketa dogodkov", | |
1645 | + "storage-pack-size-min": "Najmanjše število je 1.", | |
1646 | + "storage-pack-size-pattern": "Številka ni veljavna.", | |
1647 | + "storage-pack-size-required": "Zahtevana je največja velikost paketa dogodkov.", | |
1648 | + "storage-path": "Pot pomnilnika", | |
1649 | + "storage-path-required": "Zahtevana je pot do pomnilnika.", | |
1650 | + "storage-type": "Vrsta pomnilnika", | |
1651 | + "storage-types": { | |
1652 | + "file-storage": "Shramba datotek", | |
1653 | + "memory-storage": "Spomin pomnilnika" | |
1654 | + }, | |
1655 | + "thingsboard": "ThingsBoard", | |
1656 | + "thingsboard-host": "Gostitelj ThingsBoard", | |
1657 | + "thingsboard-host-required": "Potreben je gostitelj.", | |
1658 | + "thingsboard-port": "Vrata ThingsBoard", | |
1659 | + "thingsboard-port-max": "Največja številka vrat je 65535.", | |
1660 | + "thingsboard-port-min": "Najmanjša številka vrat je 1.", | |
1661 | + "thingsboard-port-pattern": "Vrata niso veljavna.", | |
1662 | + "thingsboard-port-required": "Potrebna so vrata.", | |
1663 | + "tidy": "Urejeno", | |
1664 | + "tidy-tip": "Urejena konfiguracija JSON", | |
1665 | + "title-connectors-json": "Konfiguracija konektorja {{typeName}}", | |
1666 | + "tls-path-ca-certificate": "Pot do potrdila CA na prehodu", | |
1667 | + "tls-path-client-certificate": "Pot do potrdila stranke na prehodu", | |
1668 | + "tls-path-private-key": "Pot do zasebnega ključa na prehodu", | |
1669 | + "toggle-fullscreen": "Preklop na celozaslonski način", | |
1670 | + "transformer-json-config": "Konfiguracija JSON *", | |
1671 | + "update-config": "Dodaj / posodobi konfiguracijo JSON" | |
1672 | + }, | |
1673 | + "grid": { | |
1674 | + "delete-item-title": "Ali ste prepričani, da želite izbrisati ta element?", | |
1675 | + "delete-item-text": "Bodite previdni, po potrditvi bodo ta element in vsi povezani podatki nepopravljivi.", | |
1676 | + "delete-items-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 item} other {# items} }?", | |
1677 | + "delete-items-action-title": "Izbriši { count, plural, 1 {1 item} other {# items} }", | |
1678 | + "delete-items-text": "Bodite previdni, po potrditvi bodo vsi izbrani elementi odstranjeni in vsi povezani podatki nepopravljivi.", | |
1679 | + "add-item-text": "Dodaj novo postavko", | |
1680 | + "no-items-text": "Ni najdenih postavk", | |
1681 | + "item-details": "Podrobnosti o postavki", | |
1682 | + "delete-item": "Izbriši postavko", | |
1683 | + "delete-items": "Izbriši postavke", | |
1684 | + "scroll-to-top": "Pomakni se na vrh" | |
1685 | + }, | |
1686 | + "help": { | |
1687 | + "goto-help-page": "Pojdi na stran s pomočjo" | |
1688 | + }, | |
1689 | + "home": { | |
1690 | + "home": "Domov", | |
1691 | + "profile": "Profil", | |
1692 | + "logout": "Odjava", | |
1693 | + "menu": "Meni", | |
1694 | + "avatar": "Avatar", | |
1695 | + "open-user-menu": "Odpri uporabniški meni" | |
1696 | + }, | |
1697 | + "import": { | |
1698 | + "no-file": "Izbrana ni nobena datoteka", | |
1699 | + "drop-file": "Spustite datoteko JSON ali kliknite, da izberete datoteko za nalaganje.", | |
1700 | + "drop-file-csv": "Spustite datoteko CSV ali kliknite, da izberete datoteko za nalaganje.", | |
1701 | + "column-value": "Vrednost", | |
1702 | + "column-title": "Naslov", | |
1703 | + "column-example": "Primer vrednosti podatkov", | |
1704 | + "column-key": "Atribut / ključ telemetrije", | |
1705 | + "csv-delimiter": "Ločilo CSV", | |
1706 | + "csv-first-line-header": "Prva vrstica vsebuje imena stolpcev", | |
1707 | + "csv-update-data": "Posodobi atribute / telemetrijo", | |
1708 | + "import-csv-number-columns-error": "Datoteka mora vsebovati vsaj dva stolpca", | |
1709 | + "import-csv-invalid-format-error": "Neveljavna oblika datoteke. Vrstica: '{{line}}'", | |
1710 | + "column-type": { | |
1711 | + "name": "Ime", | |
1712 | + "type": "Vrsta", | |
1713 | + "label": "Oznaka", | |
1714 | + "column-type": "Vrsta stolpca", | |
1715 | + "client-attribute": "Atribut odjemalca", | |
1716 | + "shared-attribute": "Skupni atribut", | |
1717 | + "server-attribute": "Atribut strežnika", | |
1718 | + "timeseries": "Časovne serije", | |
1719 | + "entity-field": "Polje entitete", | |
1720 | + "access-token": "Dostopni žeton", | |
1721 | + "isgateway": "Je prehod", | |
1722 | + "description": "Opis" | |
1723 | + }, | |
1724 | + "stepper-text": { | |
1725 | + "select-file": "Izberi datoteko", | |
1726 | + "configuration": "Uvozi konfiguracijo", | |
1727 | + "column-type": "Izberi vrsto stolpca", | |
1728 | + "creat-entities": "Ustvarjanje novih entitet", | |
1729 | + "done": "Končano" | |
1730 | + }, | |
1731 | + "message": { | |
1732 | + "create-entities": "{{count}} novih entitet je bilo uspešno ustvarjenih.", | |
1733 | + "update-entities": "{{count}} entitet je bilo uspešno posodobljenih.", | |
1734 | + "error-entities": "Prišlo je do napake pri ustvarjanju {{count}} entitet." | |
1735 | + } | |
1736 | + }, | |
1737 | + "item": { | |
1738 | + "selected": "Izbrano" | |
1739 | + }, | |
1740 | + "js-func": { | |
1741 | + "no-return-error": "Funkcija mora vrniti vrednost!", | |
1742 | + "return-type-mismatch": "Funkcija mora vrniti vrednost vrste '{{type}}'!", | |
1743 | + "tidy": "Urejeno", | |
1744 | + "mini": "Mini" | |
1745 | + }, | |
1746 | + "key-val": { | |
1747 | + "key": "Ključ", | |
1748 | + "value": "Vrednost", | |
1749 | + "remove-entry": "Odstrani vnos", | |
1750 | + "add-entry": "Dodaj vnos", | |
1751 | + "no-data": "Ni vnosov" | |
1752 | + }, | |
1753 | + "layout": { | |
1754 | + "layout": "Postavitev", | |
1755 | + "manage": "Upravljanje postavitev", | |
1756 | + "settings": "Nastavitve postavitve", | |
1757 | + "color": "Barva", | |
1758 | + "main": "Glavni", | |
1759 | + "right": "Pravi", | |
1760 | + "select": "Izberi ciljno postavitev" | |
1761 | + }, | |
1762 | + "legend": { | |
1763 | + "direction": "Smer legende", | |
1764 | + "position": "Položaj legende", | |
1765 | + "sort-legend": "Sort datakeys in legend", | |
1766 | + "show-max": "Prikaži največjo vrednost", | |
1767 | + "show-min": "Pokaži najmanjšo vrednost", | |
1768 | + "show-avg": "Prikaži povprečno vrednost", | |
1769 | + "show-total": "Prikaži skupno vrednost", | |
1770 | + "settings": "Nastavitve legende", | |
1771 | + "min": "najmanj", | |
1772 | + "max": "največ", | |
1773 | + "avg": "povprečno", | |
1774 | + "total": "skupaj", | |
1775 | + "comparison-time-ago": { | |
1776 | + "days": "(pretekli dan)", | |
1777 | + "weeks": "(pretekli teden)", | |
1778 | + "months": "(pretekli mesec)", | |
1779 | + "years": "(preteklo leto)" | |
1780 | + } | |
1781 | + }, | |
1782 | + "login": { | |
1783 | + "login": "Vpiši se", | |
1784 | + "request-password-reset": "Zahtevaj ponastavitev gesla", | |
1785 | + "reset-password": "Ponastavitev gesla", | |
1786 | + "create-password": "Ustvari geslo", | |
1787 | + "passwords-mismatch-error": "Vnesena gesla morajo biti enaka!", | |
1788 | + "password-again": "Ponovi geslo", | |
1789 | + "sign-in": "Prosimo, prijavite se", | |
1790 | + "username": "Uporabniško ime (e-pošta)", | |
1791 | + "remember-me": "Zapomni si me", | |
1792 | + "forgot-password": "Ste pozabili geslo?", | |
1793 | + "password-reset": "Resetiranje gesla", | |
1794 | + "expired-password-reset-message": "Vaše poverilnice so potekle! Ustvarite novo geslo.", | |
1795 | + "new-password": "Novo geslo", | |
1796 | + "new-password-again": "Ponovi novo geslo", | |
1797 | + "password-link-sent-message": "Povezava za ponastavitev gesla je bila uspešno poslana!", | |
1798 | + "email": "E-naslov", | |
1799 | + "login-with": "Prijava z {{name}}", | |
1800 | + "or": "ali", | |
1801 | + "error": "Napaka pri prijavi" | |
1802 | + }, | |
1803 | + "position": { | |
1804 | + "top": "Zgoraj", | |
1805 | + "bottom": "Spodaj", | |
1806 | + "left": "Levo", | |
1807 | + "right": "Desno" | |
1808 | + }, | |
1809 | + "profile": { | |
1810 | + "profile": "Profil", | |
1811 | + "last-login-time": "Zadnja prijava", | |
1812 | + "change-password": "Spremeni geslo", | |
1813 | + "current-password": "Trenutno geslo" | |
1814 | + }, | |
1815 | + "relation": { | |
1816 | + "relations": "Odnosi", | |
1817 | + "direction": "Smer", | |
1818 | + "search-direction": { | |
1819 | + "FROM": "Od", | |
1820 | + "TO": "Za" | |
1821 | + }, | |
1822 | + "direction-type": { | |
1823 | + "FROM": "od", | |
1824 | + "TO": "za" | |
1825 | + }, | |
1826 | + "from-relations": "Odhodna razmerja", | |
1827 | + "to-relations": "Vhodna razmerja", | |
1828 | + "selected-relations": "{ count, plural, 1 {1 relationship} other {# Relations} } izbran", | |
1829 | + "type": "Vrsta", | |
1830 | + "to-entity-type": "Za vrsto entitete", | |
1831 | + "to-entity-name": "Za ime entitete", | |
1832 | + "from-entity-type": "Od vrste entitete", | |
1833 | + "from-entity-name": "Od imena entitete", | |
1834 | + "to-entity": "Za entiteto", | |
1835 | + "from-entity": "Od entitete", | |
1836 | + "delete": "Izbriši relacijo", | |
1837 | + "relation-type": "Vrsta relacije", | |
1838 | + "relation-type-required": "Vrsta relacije je obvezna.", | |
1839 | + "any-relation-type": "Katerakoli vrsta", | |
1840 | + "add": "Dodaj relacijo", | |
1841 | + "edit": "Uredi relacijo", | |
1842 | + "delete-to-relation-title": "Ali ste prepričani, da želite izbrisati relacijo z entiteto '{{entityName}}'?", | |
1843 | + "delete-to-relation-text": "Previdno, po potrditvi entiteta '{{entityName}}' ne bo v relaciji s trenutno entiteto.", | |
1844 | + "delete-to-relations-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 relacijo} other {# relacije} }?", | |
1845 | + "delete-to-relations-text": "Bodite previdni, po potrditvi bodo vse izbrane relacije odstranjene in entitete ne bodo povezane med sabo.", | |
1846 | + "delete-from-relation-title": "Ali ste prepričani, da želite izbrisati relacijo iz entitete '{{entityName}}'?", | |
1847 | + "delete-from-relation-text": "Bodite previdni, po potrditvi trenutna entiteta ne bo v relacijii z entiteto '{{entityName}}'.", | |
1848 | + "delete-from-relations-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 relacija} other {# odnosi} }?", | |
1849 | + "delete-from-relations-text": "Bodite previdni, po potrditvi bodo odstranjene vse izbrane relacije in trenutna entiteta ne bo v relaciji z omenjenimi entitetami.", | |
1850 | + "remove-relation-filter": "Odstrani relacijski filter", | |
1851 | + "add-relation-filter": "Dodaj relacijski filter", | |
1852 | + "any-relation": "Kakršnakoli relacija", | |
1853 | + "relation-filters": "Relacijski filtri", | |
1854 | + "additional-info": "Dodatne informacije (JSON)", | |
1855 | + "invalid-additional-info": "Dodatnih informacij json ni mogoče razčleniti.", | |
1856 | + "no-relations-text": "Ni najdenih relacij" | |
1857 | + }, | |
1858 | + "rulechain": { | |
1859 | + "rulechain": "Veriga pravil", | |
1860 | + "rulechains": "Pravila", | |
1861 | + "root": "Izvor", | |
1862 | + "delete": "Izbriši verigo pravil", | |
1863 | + "name": "Ime", | |
1864 | + "name-required": "Ime je obvezno.", | |
1865 | + "description": "Opis", | |
1866 | + "add": "Dodaj verigo pravil", | |
1867 | + "set-root": "Ustvari izvor verige pravil", | |
1868 | + "set-root-rulechain-title": "Ali ste prepričani, da želite narediti izvorno verigo pravil '{{ruleChainName}}'?", | |
1869 | + "set-root-rulechain-text": "Po potrditvi bo veriga pravil postala izvorna in bo obravnavala vsa dohodna prometna sporočila.", | |
1870 | + "delete-rulechain-title": "Ali ste prepričani, da želite izbrisati verigo pravil '{{ruleChainName}}'?", | |
1871 | + "delete-rulechain-text": "Bodite previdni, po potrditvi bodo veriga pravil in vsi povezani podatki nepopravljivi.", | |
1872 | + "delete-rulechains-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 rule chain} other {# rule chains} }?", | |
1873 | + "delete-rulechains-action-title": "Izbriši { count, plural, 1 {1 rule chain} other {# rule chains} }", | |
1874 | + "delete-rulechains-text": "Bodite previdni, po potrditvi bodo odstranjene vse izbrane verige pravil in vsi povezani podatki bodo postali nepopravljivi.", | |
1875 | + "add-rulechain-text": "Dodaj novo verigo pravil", | |
1876 | + "no-rulechains-text": "Nobena veriga pravil ni najdena", | |
1877 | + "rulechain-details": "Podrobnosti o verigi pravil", | |
1878 | + "details": "Podrobnosti", | |
1879 | + "events": "Dogodki", | |
1880 | + "system": "Sistem", | |
1881 | + "import": "Uvozi verigo pravil", | |
1882 | + "export": "Izvozi verigo pravil", | |
1883 | + "export-failed-error": "Verige pravil ni mogoče izvoziti: {{error}}", | |
1884 | + "create-new-rulechain": "Ustvari novo verigo pravil", | |
1885 | + "rulechain-file": "Datoteka verige pravil", | |
1886 | + "invalid-rulechain-file-error": "Ni mogoče uvoziti verige pravil: neveljavna struktura podatkov verige pravil.", | |
1887 | + "copyId": "Kopiraj ID verige pravil", | |
1888 | + "idCopiedMessage": "ID verige pravil je kopiran v odložišče", | |
1889 | + "select-rulechain": "Izberi verigo pravil", | |
1890 | + "no-rulechains-matching": "Najdena ni bila nobena veriga pravil, ki se ujema z '{{entity}}'.", | |
1891 | + "rulechain-required": "Zahtevana je veriga pravil", | |
1892 | + "management": "Upravljanje pravil", | |
1893 | + "debug-mode": "Način za odpravljanje napak", | |
1894 | + "search": "Iskanje verig pravil", | |
1895 | + "selected-rulechains": "{ count, plural, 1 {1 rule chain} other {# rule chains} } izbrano", | |
1896 | + "open-rulechain": "Odprta veriga pravil" | |
1897 | + }, | |
1898 | + "rulenode": { | |
1899 | + "details": "Podrobnosti", | |
1900 | + "events": "Dogodki", | |
1901 | + "search": "Iskanje vozlišč", | |
1902 | + "open-node-library": "Odpri knjižnico vozlišč", | |
1903 | + "add": "Dodaj vozlišče pravila", | |
1904 | + "name": "Ime", | |
1905 | + "name-required": "Ime je obvezno.", | |
1906 | + "type": "Vrsta", | |
1907 | + "description": "Opis", | |
1908 | + "delete": "Izbriši vozlišče pravila", | |
1909 | + "select-all-objects": "Izberi vsa vozlišča in povezave", | |
1910 | + "deselect-all-objects": "Prekliči izbiro vseh vozlišč in povezav", | |
1911 | + "delete-selected-objects": "Izbriši izbrana vozlišča in povezave", | |
1912 | + "delete-selected": "Izbriši izbrano", | |
1913 | + "select-all": "Izberi vse", | |
1914 | + "copy-selected": "Kopiraj izbrano", | |
1915 | + "deselect-all": "Prekliči izbor", | |
1916 | + "rulenode-details": "Podrobnosti vozlišča pravila", | |
1917 | + "debug-mode": "Način za odpravljanje napak", | |
1918 | + "configuration": "Konfiguracija", | |
1919 | + "link": "Povezava", | |
1920 | + "link-details": "Podrobnosti povezave vozlišča pravila", | |
1921 | + "add-link": "Dodaj povezavo", | |
1922 | + "link-label": "Oznaka povezave", | |
1923 | + "link-label-required": "Oznaka povezave je obvezna.", | |
1924 | + "custom-link-label": "Oznaka povezave po meri", | |
1925 | + "custom-link-label-required": "Zahtevana je oznaka povezave po meri.", | |
1926 | + "link-labels": "Oznake povezav", | |
1927 | + "link-labels-required": "Oznake povezav so obvezne.", | |
1928 | + "no-link-labels-found": "Oznak povezav ni bilo mogoče najti", | |
1929 | + "no-link-label-matching": "'{{label}}' ni mogoče najti.", | |
1930 | + "create-new-link-label": "Ustvari novega!", | |
1931 | + "type-filter": "Filter", | |
1932 | + "type-filter-details": "Filtriraj dohodna sporočila s konfiguriranimi pogoji", | |
1933 | + "type-enrichment": "Obogatitev", | |
1934 | + "type-enrichment-details": "Dodaj dodatne informacije v metapodatke sporočila", | |
1935 | + "type-transformation": "Preobrazba", | |
1936 | + "type-transformation-details": "Spremeni koristni tovor sporočila in metapodatke", | |
1937 | + "type-action": "Dejanje", | |
1938 | + "type-action-details": "Izvedite posebno dejanje", | |
1939 | + "type-external": "Zunanji", | |
1940 | + "type-external-details": "Interakcija z zunanjim sistemom", | |
1941 | + "type-rule-chain": "Veriga pravil", | |
1942 | + "type-rule-chain-details": "Posredovanje dohodnih sporočil določeni verigi pravil", | |
1943 | + "type-input": "Vnos", | |
1944 | + "type-input-details": "Logični vnos verige pravil, posreduje dohodna sporočila naslednjemu povezanemu vozlišču pravila", | |
1945 | + "type-unknown": "Neznano", | |
1946 | + "type-unknown-details": "Nerazrešeno vozlišče pravila", | |
1947 | + "directive-is-not-loaded": "Določena konfiguracijska direktiva '{{DirectiveName}}' ni na voljo.", | |
1948 | + "ui-resources-load-error": "Napajanje virov uporabniškega vmesnika ni uspelo.", | |
1949 | + "invalid-target-rulechain": "Ni mogoče razrešiti ciljne verige pravil!", | |
1950 | + "test-script-function": "Preizkusi funkcijo skripte", | |
1951 | + "message": "Sporočilo", | |
1952 | + "message-type": "Vrsta sporočila", | |
1953 | + "select-message-type": "Izberi vrsto sporočila", | |
1954 | + "message-type-required": "Zahtevana je vrsta sporočila", | |
1955 | + "metadata": "Metapodatki", | |
1956 | + "metadata-required": "Vnosi metapodatkov ne smejo biti prazni.", | |
1957 | + "output": "Izdelek", | |
1958 | + "test": "Test", | |
1959 | + "help": "Pomoč", | |
1960 | + "reset-debug-mode": "Ponastavi način za odpravljanje napak v vseh vozliščih" | |
1961 | + }, | |
1962 | + "timezone": { | |
1963 | + "timezone": "Časovni pas", | |
1964 | + "select-timezone": "Izberite časovni pas", | |
1965 | + "no-timezones-matching": "Časovnih pasov, ki se ujemajo z '{{timezone}}', ni bilo mogoče najti.", | |
1966 | + "timezone-required": "Časovni pas je obvezen." | |
1967 | + }, | |
1968 | + "queue": { | |
1969 | + "select_name": "Izberi ime čakalne vrste", | |
1970 | + "name": "Ime čakalne vrste", | |
1971 | + "name_required": "Ime čakalne vrste je obvezno!" | |
1972 | + }, | |
1973 | + "tenant": { | |
1974 | + "tenant": "Najemnik", | |
1975 | + "tenants": "Najemniki", | |
1976 | + "management": "Upravljanje najemnikov", | |
1977 | + "add": "Dodaj najemnika", | |
1978 | + "admins": "Skrbniki", | |
1979 | + "manage-tenant-admins": "Upravljanje skrbnikov najemnikov", | |
1980 | + "delete": "Izbriši najemnika", | |
1981 | + "add-tenant-text": "Dodaj novega najemnika", | |
1982 | + "no-tenants-text": "Najemnikov ni bilo mogoče najti", | |
1983 | + "tenant-details": "Podrobnosti o najemniku", | |
1984 | + "delete-tenant-title": "Ali ste prepričani, da želite izbrisati najemnika '{{tenantTitle}}'?", | |
1985 | + "delete-tenant-text": "Previdno, po potrditvi bodo najemnik in vsi povezani podatki postali nepopravljivi.", | |
1986 | + "delete-tenants-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 tenant} other {# tenants} }?", | |
1987 | + "delete-tenants-action-title": "Izbriši { count, plural, 1 {1 tenant} other {# tenants} }", | |
1988 | + "delete-tenants-text": "Bodite previdni, po potrditvi bodo vsi izbrani najemniki odstranjeni in vsi povezani podatki nepopravljivi.", | |
1989 | + "title": "Naslov", | |
1990 | + "title-required": "Naslov je obvezen.", | |
1991 | + "description": "Opis", | |
1992 | + "details": "Podrobnosti", | |
1993 | + "events": "Dogodki", | |
1994 | + "copyId": "Kopiraj ID najemnika", | |
1995 | + "idCopiedMessage": "ID najemnika je kopiran v odložišče", | |
1996 | + "select-tenant": "Izberi najemnika", | |
1997 | + "no-tenants-matching": "Najden ni bil noben najemnik, ki se ujema z '{{entity}}'.", | |
1998 | + "tenant-required": "Najemnik je obvezen", | |
1999 | + "search": "Iskanje najemnikov", | |
2000 | + "selected-tenants": "{ count, plural, 1 {1 tenant} other {# tenants} } izbran", | |
2001 | + "isolated-tb-core": "Obdelava v izoliranem odlagališču ThingsBoard Core", | |
2002 | + "isolated-tb-rule-engine": "Obdelava v izoliranem odlagališču ThingsBoard Rule Engine", | |
2003 | + "isolated-tb-core-details": "Zahteva ločene mikro storitve na izoliranega najemnika", | |
2004 | + "isolated-tb-rule-engine-details": "Zahteva ločene mikro storitve na izoliranega najemnika" | |
2005 | + }, | |
2006 | + "tenant-profile": { | |
2007 | + "tenant-profile": "Tenant profile", | |
2008 | + "tenant-profiles": "Tenant profiles", | |
2009 | + "add": "Add tenant profile", | |
2010 | + "edit": "Edit tenant profile", | |
2011 | + "tenant-profile-details": "Tenant profile details", | |
2012 | + "no-tenant-profiles-text": "No tenant profiles found", | |
2013 | + "search": "Search tenant profiles", | |
2014 | + "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected", | |
2015 | + "no-tenant-profiles-matching": "No tenant profile matching '{{entity}}' were found.", | |
2016 | + "tenant-profile-required": "Tenant profile is required", | |
2017 | + "idCopiedMessage": "Tenant profile Id has been copied to clipboard", | |
2018 | + "set-default": "Make tenant profile default", | |
2019 | + "delete": "Delete tenant profile", | |
2020 | + "copyId": "Copy tenant profile Id", | |
2021 | + "name": "Name", | |
2022 | + "name-required": "Name is required.", | |
2023 | + "data": "Profile data", | |
2024 | + "profile-configuration": "Profile configuration", | |
2025 | + "description": "Description", | |
2026 | + "default": "Default", | |
2027 | + "delete-tenant-profile-title": "Are you sure you want to delete the tenant profile '{{tenantProfileName}}'?", | |
2028 | + "delete-tenant-profile-text": "Be careful, after the confirmation the tenant profile and all related data will become unrecoverable.", | |
2029 | + "delete-tenant-profiles-title": "Are you sure you want to delete { count, plural, 1 {1 tenant profile} other {# tenant profiles} }?", | |
2030 | + "delete-tenant-profiles-text": "Be careful, after the confirmation all selected tenant profiles will be removed and all related data will become unrecoverable.", | |
2031 | + "set-default-tenant-profile-title": "Are you sure you want to make the tenant profile '{{tenantProfileName}}' default?", | |
2032 | + "set-default-tenant-profile-text": "After the confirmation the tenant profile will be marked as default and will be used for new tenants with no profile specified.", | |
2033 | + "no-tenant-profiles-found": "No tenant profiles found.", | |
2034 | + "create-new-tenant-profile": "Create a new one!", | |
2035 | + "maximum-devices": "Maximum number of devices (0 - unlimited)", | |
2036 | + "maximum-devices-required": "Maximum number of devices is required.", | |
2037 | + "maximum-devices-range": "Minimum number of devices can't be negative", | |
2038 | + "maximum-assets": "Maximum number of assets (0 - unlimited)", | |
2039 | + "maximum-assets-required": "Maximum number of assets is required.", | |
2040 | + "maximum-assets-range": "Maximum number of assets can't be negative", | |
2041 | + "maximum-customers": "Maximum number of customers (0 - unlimited)", | |
2042 | + "maximum-customers-required": "Maximum number of customers is required.", | |
2043 | + "maximum-customers-range": "Maximum number of customers can't be negative", | |
2044 | + "maximum-users": "Maximum number of users (0 - unlimited)", | |
2045 | + "maximum-users-required": "Maximum number of users is required.", | |
2046 | + "maximum-users-range": "Maximum number of users can't be negative", | |
2047 | + "maximum-dashboards": "Maximum number of dashboards (0 - unlimited)", | |
2048 | + "maximum-dashboards-required": "Maximum number of dashboards is required.", | |
2049 | + "maximum-dashboards-range": "Maximum number of dashboards can't be negative", | |
2050 | + "maximum-rule-chains": "Maximum number of rule chains (0 - unlimited)", | |
2051 | + "maximum-rule-chains-required": "Maximum number of rule chains is required.", | |
2052 | + "maximum-rule-chains-range": "Maximum number of rule chains can't be negative", | |
2053 | + "transport-tenant-msg-rate-limit": "Transport tenant messages rate limit.", | |
2054 | + "transport-tenant-telemetry-msg-rate-limit": "Transport tenant telemetry messages rate limit.", | |
2055 | + "transport-tenant-telemetry-data-points-rate-limit": "Transport tenant telemetry data points rate limit.", | |
2056 | + "transport-device-msg-rate-limit": "Transport device messages rate limit.", | |
2057 | + "transport-device-telemetry-msg-rate-limit": "Transport device telemetry messages rate limit.", | |
2058 | + "transport-device-telemetry-data-points-rate-limit": "Transport device telemetry data points rate limit.", | |
2059 | + "max-transport-messages": "Maximum number of transport messages (0 - unlimited)", | |
2060 | + "max-transport-messages-required": "Maximum number of transport messages is required.", | |
2061 | + "max-transport-messages-range": "Maximum number of transport messages can't be negative", | |
2062 | + "max-transport-data-points": "Maximum number of transport data points (0 - unlimited)", | |
2063 | + "max-transport-data-points-required": "Maximum number of transport data points is required.", | |
2064 | + "max-transport-data-points-range": "Maximum number of transport data points can't be negative", | |
2065 | + "max-r-e-executions": "Maximum number of Rule Engine executions (0 - unlimited)", | |
2066 | + "max-r-e-executions-required": "Maximum number of Rule Engine executions is required.", | |
2067 | + "max-r-e-executions-range": "Maximum number of Rule Engine executions can't be negative", | |
2068 | + "max-j-s-executions": "Maximum number of JavaScript executions (0 - unlimited)", | |
2069 | + "max-j-s-executions-required": "Maximum number of JavaScript executions is required.", | |
2070 | + "max-j-s-executions-range": "Maximum number of JavaScript executions can't be negative", | |
2071 | + "max-d-p-storage-days": "Maximum number of data points storage days (0 - unlimited)", | |
2072 | + "max-d-p-storage-days-required": "Maximum number of data points storage days is required.", | |
2073 | + "max-d-p-storage-days-range": "Maximum number of data points storage days can't be negative", | |
2074 | + "default-storage-ttl-days": "Default storage TTL days (0 - unlimited)", | |
2075 | + "default-storage-ttl-days-required": "Default storage TTL days is required.", | |
2076 | + "default-storage-ttl-days-range": "Default storage TTL days can't be negative", | |
2077 | + "max-rule-node-executions-per-message": "Maximum number of rule node executions per message (0 - unlimited)", | |
2078 | + "max-rule-node-executions-per-message-required": "Maximum number of rule node executions per message is required.", | |
2079 | + "max-rule-node-executions-per-message-range": "Maximum number of rule node executions per message can't be negative", | |
2080 | + "max-emails": "Maximum number of emails sent (0 - unlimited)", | |
2081 | + "max-emails-required": "Maximum number of emails sent is required.", | |
2082 | + "max-emails-range": "Maximum number of emails sent can't be negative", | |
2083 | + "max-sms": "Maximum number of SMS sent (0 - unlimited)", | |
2084 | + "max-sms-required": "Maximum number of SMS sent is required.", | |
2085 | + "max-sms-range": "Maximum number of SMS sent can't be negative" | |
2086 | + }, | |
2087 | + "timeinterval": { | |
2088 | + "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", | |
2089 | + "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", | |
2090 | + "hours-interval": "{ hours, plural, 1 {1 hour} other {# hours} }", | |
2091 | + "days-interval": "{ days, plural, 1 {1 day} other {# days} }", | |
2092 | + "days": "Dnevi", | |
2093 | + "hours": "Ure", | |
2094 | + "minutes": "Minute", | |
2095 | + "seconds": "Sekunde", | |
2096 | + "advanced": "Napredno" | |
2097 | + }, | |
2098 | + "timeunit": { | |
2099 | + "seconds": "Seconds", | |
2100 | + "minutes": "Minutes", | |
2101 | + "hours": "Hours", | |
2102 | + "days": "Days" | |
2103 | + }, | |
2104 | + "timewindow": { | |
2105 | + "days": "{ days, plural, 1 {dan} other {# dni} }", | |
2106 | + "hours": "{ hours, plural, 0 {hour} 1 {1 hour} other {# hours} }", | |
2107 | + "minutes": "{ minute, plural, 0 {minute} 1 {1 minuta} other {# minut} }", | |
2108 | + "seconds": "{ seconds, plural, 0 {second} 1 {1 second} other {# seconds} }", | |
2109 | + "realtime": "V realnem času", | |
2110 | + "history": "Zgodovina", | |
2111 | + "last-prefix": "zadnji", | |
2112 | + "period": "od {{ startTime }} do {{ endTime }}", | |
2113 | + "edit": "Uredi časovno okno", | |
2114 | + "date-range": "Časovno obdobje", | |
2115 | + "last": "Zadnji", | |
2116 | + "time-period": "Časovno obdobje", | |
2117 | + "hide": "Skrij" | |
2118 | + }, | |
2119 | + "user": { | |
2120 | + "user": "Uporabnik", | |
2121 | + "users": "Uporabniki", | |
2122 | + "customer-users": "Uporabniki kupcev", | |
2123 | + "tenant-admins": "Skrbniki najemnikov", | |
2124 | + "sys-admin": "Sistemski administrator", | |
2125 | + "tenant-admin": "Skrbnik najemnika", | |
2126 | + "customer": "Stranka", | |
2127 | + "anonymous": "Anonimno", | |
2128 | + "add": "Dodaj uporabnika", | |
2129 | + "delete": "Izbriši uporabnika", | |
2130 | + "add-user-text": "Dodaj novega uporabnika", | |
2131 | + "no-users-text": "Uporabnikov ni bilo mogoče najti", | |
2132 | + "user-details": "Podrobnosti o uporabniku", | |
2133 | + "delete-user-title": "Ali ste prepričani, da želite izbrisati uporabnika '{{userEmail}}'?", | |
2134 | + "delete-user-text": "Previdno, po potrditvi bodo uporabnik in vsi povezani podatki nepopravljivi.", | |
2135 | + "delete-users-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 user} other {# users} }?", | |
2136 | + "delete-users-action-title": "Izbriši { count, plural, 1 {1 user} other {# users} }", | |
2137 | + "delete-users-text": "Previdno, po potrditvi bodo vsi izbrani uporabniki odstranjeni in vsi povezani podatki nepopravljivi.", | |
2138 | + "activation-email-sent-message": "Aktivacijsko e-poštno sporočilo je bilo uspešno poslano!", | |
2139 | + "resend-activation": "Znova pošlji aktivacijo", | |
2140 | + "email": "E-pošta", | |
2141 | + "email-required": "E-pošta je obvezna.", | |
2142 | + "invalid-email-format": "Neveljavna oblika e-pošte.", | |
2143 | + "first-name": "Ime", | |
2144 | + "last-name": "Priimek", | |
2145 | + "description": "Opis", | |
2146 | + "default-dashboard": "Privzeta nadzorna plošča", | |
2147 | + "always-fullscreen": "Vedno v celozaslonskem načinu", | |
2148 | + "select-user": "Izberi uporabnika", | |
2149 | + "no-users-matching": "Najti ni bilo mogoče nobenega uporabnika, ki se ujema z '{{entity}}'.", | |
2150 | + "user-required": "Uporabnik je potreben", | |
2151 | + "activation-method": "Način aktiviranja", | |
2152 | + "display-activation-link": "Prikaži aktivacijsko povezavo", | |
2153 | + "send-activation-mail": "Pošlji aktivacijsko pošto", | |
2154 | + "activation-link": "Povezava za aktiviranje uporabnika", | |
2155 | + "activation-link-text": "Če želite uporabnika aktivirati, uporabite naslednjo <a href='{{activationLink}}' target='_blank'>aktivacijsko povezavo</a> :", | |
2156 | + "copy-activation-link": "Kopiraj aktivacijsko povezavo", | |
2157 | + "activation-link-copied-message": "Povezava za aktiviranje uporabnika je bila kopirana v odložišče", | |
2158 | + "details": "Podrobnosti", | |
2159 | + "login-as-tenant-admin": "Prijava kot skrbnik najemnika", | |
2160 | + "login-as-customer-user": "Prijavi se kot uporabnik stranke", | |
2161 | + "search": "Iskanje uporabnikov", | |
2162 | + "selected-users": "{ count, plural, 1 {1 user} other {# users} } izbranih", | |
2163 | + "disable-account": "Onemogoči uporabniški račun", | |
2164 | + "enable-account": "Omogoči uporabniški račun", | |
2165 | + "enable-account-message": "Uporabniški račun je bil uspešno omogočen!", | |
2166 | + "disable-account-message": "Uporabniški račun je bil uspešno onemogočen!" | |
2167 | + }, | |
2168 | + "value": { | |
2169 | + "type": "Vrsta vrednosti", | |
2170 | + "string": "Niz", | |
2171 | + "string-value": "Vrednost niza", | |
2172 | + "string-value-required": "Vrednost niza je potrebna", | |
2173 | + "integer": "Celota", | |
2174 | + "integer-value": "Celotna vrednost", | |
2175 | + "integer-value-required": "Zahtevana je celoštevilčna vrednost", | |
2176 | + "invalid-integer-value": "Neveljavna celoštevilska vrednost", | |
2177 | + "double": "Podvojeno", | |
2178 | + "double-value": "Podvojena vrednost", | |
2179 | + "double-value-required": "Zahtevana je podvojena vrednost", | |
2180 | + "boolean": "Logično", | |
2181 | + "boolean-value": "Logična vrednost", | |
2182 | + "false": "Napačno", | |
2183 | + "true": "Pravilno", | |
2184 | + "long": "Dolgo", | |
2185 | + "json": "JSON", | |
2186 | + "json-value": "Vrednost JSON", | |
2187 | + "json-value-invalid": "Vrednost JSON ima neveljavno obliko", | |
2188 | + "json-value-required": "Vrednost JSON je potrebna." | |
2189 | + }, | |
2190 | + "widget": { | |
2191 | + "widget-library": "Knjižnica pripomočkov", | |
2192 | + "widget-bundle": "Paket pripomočkov", | |
2193 | + "select-widgets-bundle": "Izberi paket pripomočkov", | |
2194 | + "management": "Upravljanje pripomočkov", | |
2195 | + "editor": "Urejevalnik pripomočkov", | |
2196 | + "widget-type-not-found": "Težava pri nalaganju konfiguracije pripomočka. <br> Verjetno je bil povezan tip pripomočka odstranjen.", | |
2197 | + "widget-type-load-error": "Pripomoček ni bil naložen zaradi naslednjih napak:", | |
2198 | + "remove": "Odstrani pripomoček", | |
2199 | + "edit": "Uredi pripomoček", | |
2200 | + "remove-widget-title": "Ali ste prepričani, da želite odstraniti pripomoček '{{widgetTitle}}'?", | |
2201 | + "remove-widget-text": "Po potrditvi bodo pripomoček in vsi povezani podatki nepopravljivi.", | |
2202 | + "timeseries": "Časovne serije", | |
2203 | + "search-data": "Iskanje podatkov", | |
2204 | + "no-data-found": "Podatkov ni mogoče najti", | |
2205 | + "latest-values": "Najnovejše vrednosti", | |
2206 | + "rpc": "Nadzorni pripomoček", | |
2207 | + "alarm": "Pripomoček za alarm", | |
2208 | + "static": "Statični pripomoček", | |
2209 | + "select-widget-type": "Izberi vrsto pripomočka", | |
2210 | + "missing-widget-title-error": "Navesti je treba pripomoček!", | |
2211 | + "widget-saved": "Pripomoček je shranjen", | |
2212 | + "unable-to-save-widget-error": "Pripomočka ni mogoče shraniti! V pripomočku so napake!", | |
2213 | + "save": "Shrani pripomoček", | |
2214 | + "saveAs": "Shrani pripomoček kot", | |
2215 | + "save-widget-type-as": "Shrani vrsto pripomočka kot", | |
2216 | + "save-widget-type-as-text": "Vnesite nov naslov pripomočka in / ali izberite paket ciljnih pripomočkov", | |
2217 | + "toggle-fullscreen": "Preklop na celozaslonski način", | |
2218 | + "run": "Zaženi pripomoček", | |
2219 | + "title": "Naslov pripomočka", | |
2220 | + "title-required": "Naslov pripomočka je obvezen.", | |
2221 | + "type": "Vrsta pripomočka", | |
2222 | + "resources": "Viri", | |
2223 | + "resource-url": "URL JavaScript / CSS", | |
2224 | + "resource-is-module": "Je modul", | |
2225 | + "remove-resource": "Odstrani vir", | |
2226 | + "add-resource": "Dodaj vir", | |
2227 | + "html": "HTML", | |
2228 | + "tidy": "Urejeno", | |
2229 | + "css": "CSS", | |
2230 | + "settings-schema": "Shema nastavitev", | |
2231 | + "datakey-settings-schema": "Shema nastavitev podatkovnega ključa", | |
2232 | + "javascript": "Javascript", | |
2233 | + "js": "JS", | |
2234 | + "remove-widget-type-title": "Ali ste prepričani, da želite odstraniti vrsto pripomočka '{{widgetName}}'?", | |
2235 | + "remove-widget-type-text": "Po potrditvi bodo vrsta pripomočka in vsi povezani podatki nepopravljivi.", | |
2236 | + "remove-widget-type": "Odstrani vrsto pripomočka", | |
2237 | + "add-widget-type": "Dodaj novo vrsto pripomočka", | |
2238 | + "widget-type-load-failed-error": "Vrste pripomočka ni bilo mogoče naložiti!", | |
2239 | + "widget-template-load-failed-error": "Predloge pripomočka ni bilo mogoče naložiti!", | |
2240 | + "add": "Dodaj pripomoček", | |
2241 | + "undo": "Razveljavi spremembe pripomočka", | |
2242 | + "export": "Izvozi pripomoček", | |
2243 | + "no-data": "Na pripomočku ni podatkov za prikaz", | |
2244 | + "data-overflow": "Pripomoček prikazuje {{count}} od {{total}} entitet", | |
2245 | + "alarm-data-overflow": "Pripomoček prikazuje alarme za {{allowedEntities}} (največ dovoljenih) entitet od {{totalEntities}} entitet" | |
2246 | + }, | |
2247 | + "widget-action": { | |
2248 | + "header-button": "Gumb glave pripomočka", | |
2249 | + "open-dashboard-state": "Pomakni se do novega stanja na nadzorni plošči", | |
2250 | + "update-dashboard-state": "Posodobi trenutno stanje nadzorne plošče", | |
2251 | + "open-dashboard": "Pomakni se na drugo nadzorno ploščo", | |
2252 | + "custom": "Dejanje po meri", | |
2253 | + "custom-pretty": "Dejanje po meri (s predlogo HTML)", | |
2254 | + "target-dashboard-state": "Ciljno stanje nadzorne plošče", | |
2255 | + "target-dashboard-state-required": "Ciljno stanje nadzorne plošče je potrebno", | |
2256 | + "set-entity-from-widget": "Nastavi entiteto iz pripomočka", | |
2257 | + "target-dashboard": "Ciljna nadzorna plošča", | |
2258 | + "open-right-layout": "Odpri pravilno postavitev nadzorne plošče (mobilni pogled)" | |
2259 | + }, | |
2260 | + "widgets-bundle": { | |
2261 | + "current": "Trenutni paketi", | |
2262 | + "widgets-bundles": "Paketi pripomočkov", | |
2263 | + "add": "Dodaj paket pripomočkov", | |
2264 | + "delete": "Izbriši paket pripomočkov", | |
2265 | + "title": "Naslov", | |
2266 | + "title-required": "Naslov je obvezen.", | |
2267 | + "add-widgets-bundle-text": "Dodaj nov paket pripomočkov", | |
2268 | + "no-widgets-bundles-text": "Najden ni bil noben paket pripomočkov", | |
2269 | + "empty": "Paket pripomočkov je prazen", | |
2270 | + "details": "Podrobnosti", | |
2271 | + "widgets-bundle-details": "Podrobnosti o paketu pripomočkov", | |
2272 | + "delete-widgets-bundle-title": "Ali ste prepričani, da želite izbrisati paket pripomočkov '{{widgetsBundleTitle}}'?", | |
2273 | + "delete-widgets-bundle-text": "Bodite previdni, po potrditvi bodo pripomočki in vsi povezani podatki postali nepopravljivi.", | |
2274 | + "delete-widgets-bundles-title": "Ali ste prepričani, da želite izbrisati { count, plural, 1 {1 widgets bundle} other {# widgets bundles} }?", | |
2275 | + "delete-widgets-bundles-action-title": "Izbriši { count, plural, 1 {1 widgets bundle} other {# widgets bundles} }", | |
2276 | + "delete-widgets-bundles-text": "Bodite previdni, po potrditvi bodo odstranjeni vsi paketi pripomočkov, vsi povezani podatki pa bodo postali nepopravljivi.", | |
2277 | + "no-widgets-bundles-matching": "Najden ni bil noben paket pripomočkov, ki se ujema z '{{widgetsBundle}}'.", | |
2278 | + "widgets-bundle-required": "Paket pripomočkov je potreben.", | |
2279 | + "system": "Sistem", | |
2280 | + "import": "Uvozi paket pripomočkov", | |
2281 | + "export": "Izvozi paket pripomočkov", | |
2282 | + "export-failed-error": "Ni mogoče izvoziti paketa pripomočkov: {{error}}", | |
2283 | + "create-new-widgets-bundle": "Ustvari nov paket pripomočkov", | |
2284 | + "widgets-bundle-file": "Datoteka paketa pripomočkov", | |
2285 | + "invalid-widgets-bundle-file-error": "Ni mogoče uvoziti paketa pripomočkov: neveljavna podatkovna struktura paketa pripomočkov.", | |
2286 | + "search": "Iskanje po paketih pripomočkov", | |
2287 | + "selected-widgets-bundles": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} } izbranih", | |
2288 | + "open-widgets-bundle": "Odpri paket pripomočkov" | |
2289 | + }, | |
2290 | + "widget-config": { | |
2291 | + "data": "Podatki", | |
2292 | + "settings": "Nastavitve", | |
2293 | + "advanced": "Napredno", | |
2294 | + "title": "Naslov", | |
2295 | + "title-tooltip": "Opis naslova", | |
2296 | + "general-settings": "Splošne nastavitve", | |
2297 | + "display-title": "Prikaži naslov", | |
2298 | + "drop-shadow": "Spusti senco", | |
2299 | + "enable-fullscreen": "Omogoči celozaslonski način", | |
2300 | + "background-color": "Barva ozadja", | |
2301 | + "text-color": "Barva besedila", | |
2302 | + "padding": "Oblazinjenje", | |
2303 | + "margin": "Stopnja", | |
2304 | + "widget-style": "Slog pripomočkov", | |
2305 | + "title-style": "Slog naslova", | |
2306 | + "mobile-mode-settings": "Nastavitve mobilnega načina", | |
2307 | + "order": "Naročilo", | |
2308 | + "height": "Višina", | |
2309 | + "units": "Poseben simbol za prikaz poleg vrednosti", | |
2310 | + "decimals": "Število številk po plavajoči vejici", | |
2311 | + "timewindow": "Časovno okno", | |
2312 | + "use-dashboard-timewindow": "Uporabi časovno okno nadzorne plošče", | |
2313 | + "display-timewindow": "Prikaži časovno okno", | |
2314 | + "display-legend": "Prikaži legendo", | |
2315 | + "datasources": "Viri podatkov", | |
2316 | + "maximum-datasources": "Največ { count, plural, 1 {1 vir podatkov je dovoljen.} other {# vir podatkov je dovoljen} }", | |
2317 | + "datasource-type": "Vrsta", | |
2318 | + "datasource-parameters": "Parametri", | |
2319 | + "remove-datasource": "Odstrani vir podatkov", | |
2320 | + "add-datasource": "Dodaj vir podatkov", | |
2321 | + "target-device": "Ciljna naprava", | |
2322 | + "alarm-source": "Vir alarma", | |
2323 | + "actions": "Dejanja", | |
2324 | + "action": "Dejanje", | |
2325 | + "add-action": "Dodaj dejanje", | |
2326 | + "search-actions": "Iskanje dejanj", | |
2327 | + "no-actions-text": "Ni najdenih dejanj", | |
2328 | + "action-source": "Vir dejanja", | |
2329 | + "action-source-required": "Zahtevan je vir dejanj.", | |
2330 | + "action-name": "Ime", | |
2331 | + "action-name-required": "Ime dejanja je obvezno.", | |
2332 | + "action-name-not-unique": "Še eno dejanje z istim imenom že obstaja. <br/> Ime dejanja mora biti enolično v istem viru dejanj.", | |
2333 | + "action-icon": "Ikona", | |
2334 | + "action-type": "Vrsta", | |
2335 | + "action-type-required": "Zahtevana je vrsta dejanja.", | |
2336 | + "edit-action": "Uredi dejanje", | |
2337 | + "delete-action": "Izbriši dejanje", | |
2338 | + "delete-action-title": "Izbriši dejanje pripomočka", | |
2339 | + "delete-action-text": "Ali ste prepričani, da želite izbrisati dejanje pripomočka z imenom '{{actionName}}'?", | |
2340 | + "display-icon": "Prikaži ikono naslova", | |
2341 | + "icon-color": "Barva ikone", | |
2342 | + "icon-size": "Velikost ikone" | |
2343 | + }, | |
2344 | + "widget-type": { | |
2345 | + "import": "Uvozi vrsto pripomočka", | |
2346 | + "export": "Izvozi vrsto pripomočka", | |
2347 | + "export-failed-error": "Ni mogoče izvoziti vrste pripomočka: {{error}}", | |
2348 | + "create-new-widget-type": "Ustvari novo vrsto pripomočka", | |
2349 | + "widget-type-file": "Datoteka vrste pripomočka", | |
2350 | + "invalid-widget-type-file-error": "Ne morem uvoziti vrste gradnika: Neveljavna struktura podatkov vrste pripomočka." | |
2351 | + }, | |
2352 | + "widgets": { | |
2353 | + "date-range-navigator": { | |
2354 | + "localizationMap": { | |
2355 | + "Sun": "Ned", | |
2356 | + "Mon": "Pon", | |
2357 | + "Tue": "Tor", | |
2358 | + "Wed": "Sre", | |
2359 | + "Thu": "Čet", | |
2360 | + "Fri": "Pet", | |
2361 | + "Sat": "Sob", | |
2362 | + "Jan": "Jan", | |
2363 | + "Feb": "Feb", | |
2364 | + "Mar": "Mar", | |
2365 | + "Apr": "Apr", | |
2366 | + "May": "Maj", | |
2367 | + "Jun": "Jun", | |
2368 | + "Jul": "Jul", | |
2369 | + "Aug": "Avg", | |
2370 | + "Sep": "Sep", | |
2371 | + "Oct": "Okt", | |
2372 | + "Nov": "Nov", | |
2373 | + "Dec": "Dec", | |
2374 | + "January": "Januar", | |
2375 | + "February": "Februar", | |
2376 | + "March": "Marec", | |
2377 | + "April": "April", | |
2378 | + "June": "Junij", | |
2379 | + "July": "Julij", | |
2380 | + "August": "Avgust", | |
2381 | + "September": "September", | |
2382 | + "October": "Oktober", | |
2383 | + "November": "November", | |
2384 | + "December": "December", | |
2385 | + "Custom Date Range": "Časovno obdobje po meri", | |
2386 | + "Date Range Template": "Predloga časovnega obdobja", | |
2387 | + "Today": "Danes", | |
2388 | + "Yesterday": "Včeraj", | |
2389 | + "This Week": "Ta teden", | |
2390 | + "Last Week": "Prejšnji teden", | |
2391 | + "This Month": "Ta mesec", | |
2392 | + "Last Month": "Prejšnji mesec", | |
2393 | + "Year": "Leto", | |
2394 | + "This Year": "To leto", | |
2395 | + "Last Year": "Lansko leto", | |
2396 | + "Date picker": "Izbirnik datuma", | |
2397 | + "Hour": "Ura", | |
2398 | + "Day": "Dan", | |
2399 | + "Week": "Teden", | |
2400 | + "2 weeks": "2 tedna", | |
2401 | + "Month": "Mesec", | |
2402 | + "3 months": "3 mesece", | |
2403 | + "6 months": "6 mesecev", | |
2404 | + "Custom interval": "Interval po meri", | |
2405 | + "Interval": "Interval", | |
2406 | + "Step size": "Velikost koraka", | |
2407 | + "Ok": "V redu" | |
2408 | + } | |
2409 | + }, | |
2410 | + "input-widgets": { | |
2411 | + "attribute-not-allowed": "Parametra atributa v tem pripomočku ni mogoče uporabiti", | |
2412 | + "blocked-location": "Geolokacija je blokirana v vašem brskalniku", | |
2413 | + "claim-device": "Zahtevaj napravo", | |
2414 | + "claim-failed": "Naprave ni bilo mogoče zahtevati!", | |
2415 | + "claim-not-found": "Naprave ni mogoče najti!", | |
2416 | + "claim-successful": "Naprava je bila uspešno zahtevana!", | |
2417 | + "date": "Datum", | |
2418 | + "device-name": "Ime naprave", | |
2419 | + "device-name-required": "Ime naprave je obvezno", | |
2420 | + "discard-changes": "Zavrzi spremembe", | |
2421 | + "entity-attribute-required": "Zahtevan je atribut entitete", | |
2422 | + "entity-coordinate-required": "Oba polja, zemljepisna širina in dolžina sta obvezna", | |
2423 | + "entity-timeseries-required": "Potreben je časovni niz entitet", | |
2424 | + "get-location": "Pridobi trenutno lokacijo", | |
2425 | + "invalid-date": "Invalid Date", | |
2426 | + "latitude": "Zemljepisna širina", | |
2427 | + "longitude": "Zemljepisna dolžina", | |
2428 | + "min-value-error": "Min value is {{value}}", | |
2429 | + "max-value-error": "Max value is {{value}}", | |
2430 | + "not-allowed-entity": "Izbrana entiteta ne sme imeti atributov v skupni rabi", | |
2431 | + "no-attribute-selected": "Noben atribut ni izbran", | |
2432 | + "no-datakey-selected": "Nobena podatkovna tipka ni izbrana", | |
2433 | + "no-coordinate-specified": "Podatkovni ključ za zemljepisno širino / dolžino ni določen", | |
2434 | + "no-entity-selected": "Nobena entiteta ni izbrana", | |
2435 | + "no-image": "Ni slike", | |
2436 | + "no-support-geolocation": "Vaš brskalnik ne podpira geolokacije", | |
2437 | + "no-support-web-camera": "Ni podprte spletne kamere", | |
2438 | + "enable-https-use-widget": "Please enable HTTPS to use this widget", | |
2439 | + "no-found-your-camera": "Can't find your camera", | |
2440 | + "no-permission-camera": "Permission was denied by the user / This site doesn't have permission to use the camera", | |
2441 | + "no-timeseries-selected": "Izbrana ni nobena časovna serija", | |
2442 | + "secret-key": "Skrivni ključ", | |
2443 | + "secret-key-required": "Potreben je skrivni ključ", | |
2444 | + "switch-attribute-value": "Preklopi vrednost atributa entitete", | |
2445 | + "switch-camera": "Preklopi kamero", | |
2446 | + "switch-timeseries-value": "Preklopi vrednost časovnega niza entitete", | |
2447 | + "take-photo": "Fotografiraj", | |
2448 | + "time": "Čas", | |
2449 | + "timeseries-not-allowed": "V tem pripomočku ni mogoče uporabiti parametra časovne vrste", | |
2450 | + "update-failed": "Posodobitev ni uspela", | |
2451 | + "update-successful": "Posodobitev uspešna", | |
2452 | + "update-attribute": "Posodobi atribut", | |
2453 | + "update-timeseries": "Posodobi časovne vrste", | |
2454 | + "value": "Vrednost" | |
2455 | + } | |
2456 | + }, | |
2457 | + "icon": { | |
2458 | + "icon": "Ikona", | |
2459 | + "select-icon": "Izberi ikono", | |
2460 | + "material-icons": "Ikone materiala", | |
2461 | + "show-all": "Pokaži vse ikone" | |
2462 | + }, | |
2463 | + "custom": { | |
2464 | + "widget-action": { | |
2465 | + "action-cell-button": "Gumb akcijske celice", | |
2466 | + "row-click": "Klik na vrstico", | |
2467 | + "polygon-click": "Klik na poligon", | |
2468 | + "marker-click": "Klik na oznako", | |
2469 | + "tooltip-tag-action": "Dejanje oznake orodja", | |
2470 | + "node-selected": "Na izbranem vozlišču", | |
2471 | + "element-click": "Klik na HTML element", | |
2472 | + "pie-slice-click": "Klik na rezino", | |
2473 | + "row-double-click": "Dvojni klik na vrstico" | |
2474 | + } | |
2475 | + }, | |
2476 | + "language": { | |
2477 | + "language": "Jezik" | |
2478 | + } | |
2479 | +} | ... | ... |
... | ... | @@ -24,6 +24,8 @@ |
24 | 24 | |
25 | 25 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
26 | 26 | <link rel="icon" type="image/x-icon" href="thingsboard.ico"> |
27 | + <link rel="preload" href="assets/fonts/MaterialIcons-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous" /> | |
28 | + <link rel="stylesheet" href="assets/fonts/material-icons.css" /> | |
27 | 29 | <style type="text/css"> |
28 | 30 | |
29 | 31 | body, html { | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | /* You can add global styles to this file, and also import other style files */ |
17 | 17 | |
18 | -@import '~material-design-icons/iconfont/material-icons.css'; | |
19 | 18 | @import '~typeface-roboto/index.css'; |
20 | 19 | @import '~font-awesome/css/font-awesome.min.css'; |
21 | 20 | @import 'theme.scss'; | ... | ... |