Showing
9 changed files
with
845 additions
and
35 deletions
@@ -332,6 +332,20 @@ export default angular.module('thingsboard.types', []) | @@ -332,6 +332,20 @@ export default angular.module('thingsboard.types', []) | ||
332 | toDouble: 'extension.to-double', | 332 | toDouble: 'extension.to-double', |
333 | custom: 'extension.custom' | 333 | custom: 'extension.custom' |
334 | }, | 334 | }, |
335 | + extensionOpcSecurityTypes: { | ||
336 | + Basic128Rsa15: "Basic128Rsa15", | ||
337 | + Basic256: "Basic256", | ||
338 | + Basic256Sha256: "Basic256Sha256", | ||
339 | + None: "None" | ||
340 | + }, | ||
341 | + extensionIdentityType: { | ||
342 | + anonymous: "anonymous", | ||
343 | + username: "username" | ||
344 | + }, | ||
345 | + extensionKeystoreType: { | ||
346 | + PKCS12: "PKCS12", | ||
347 | + JKS: "JKS" | ||
348 | + }, | ||
335 | latestTelemetry: { | 349 | latestTelemetry: { |
336 | value: "LATEST_TELEMETRY", | 350 | value: "LATEST_TELEMETRY", |
337 | name: "attribute.scope-latest-telemetry", | 351 | name: "attribute.scope-latest-telemetry", |
@@ -29,45 +29,72 @@ export default function ExtensionDialogController($scope, $mdDialog, $translate, | @@ -29,45 +29,72 @@ export default function ExtensionDialogController($scope, $mdDialog, $translate, | ||
29 | vm.entityId = entityId; | 29 | vm.entityId = entityId; |
30 | vm.allExtensions = allExtensions; | 30 | vm.allExtensions = allExtensions; |
31 | 31 | ||
32 | - vm.configuration = {}; | ||
33 | - vm.newExtension = {id:"",type:"",configuration:vm.configuration}; | ||
34 | 32 | ||
35 | - if(!vm.isAdd) { | ||
36 | - vm.newExtension = angular.copy(extension); | ||
37 | - vm.configuration = vm.newExtension.configuration; | ||
38 | - editTransformers(vm.newExtension); | 33 | + if (extension) { // Editing |
34 | + //vm.configuration = vm.extension.configuration; | ||
35 | + vm.extension = angular.copy(extension); | ||
36 | + editTransformers(vm.extension); | ||
37 | + } else { // Add new | ||
38 | + vm.extension = {}; | ||
39 | } | 39 | } |
40 | 40 | ||
41 | - vm.cancel = cancel; | ||
42 | - vm.save = save; | ||
43 | 41 | ||
42 | + vm.extensionTypeChange = function () { | ||
43 | + // $scope.theForm.$setPristine(); | ||
44 | + // $scope.theForm.$setUntouched(); | ||
45 | + | ||
46 | + if (vm.extension.type === "HTTP") { | ||
47 | + vm.extension.configuration = { | ||
48 | + "converterConfigurations": [] | ||
49 | + }; | ||
50 | + } | ||
51 | + if (vm.extension.type === "MQTT") { | ||
52 | + vm.extension.configuration = { | ||
53 | + "brokers": [] | ||
54 | + }; | ||
55 | + } | ||
56 | + if (vm.extension.type === "OPC UA") { | ||
57 | + vm.extension.configuration = { | ||
58 | + "servers": [] | ||
59 | + }; | ||
60 | + } | ||
61 | + }; | ||
62 | + | ||
63 | + vm.cancel = cancel; | ||
44 | function cancel() { | 64 | function cancel() { |
45 | $mdDialog.cancel(); | 65 | $mdDialog.cancel(); |
46 | } | 66 | } |
67 | + | ||
68 | + vm.save = save; | ||
47 | function save() { | 69 | function save() { |
48 | saveTransformers(); | 70 | saveTransformers(); |
49 | if(vm.isAdd) { | 71 | if(vm.isAdd) { |
50 | - vm.allExtensions.push(vm.newExtension); | 72 | + vm.allExtensions.push(vm.extension); |
51 | } else { | 73 | } else { |
52 | var index = vm.allExtensions.indexOf(extension); | 74 | var index = vm.allExtensions.indexOf(extension); |
53 | if(index > -1) { | 75 | if(index > -1) { |
54 | - vm.allExtensions[index] = vm.newExtension; | 76 | + vm.allExtensions[index] = vm.extension; |
55 | } | 77 | } |
56 | } | 78 | } |
57 | 79 | ||
58 | var editedValue = angular.toJson(vm.allExtensions); | 80 | var editedValue = angular.toJson(vm.allExtensions); |
59 | 81 | ||
60 | - attributeService.saveEntityAttributes(vm.entityType, vm.entityId, types.attributesScope.shared.value, [{key:"configuration", value:editedValue}]).then( | ||
61 | - function success() { | ||
62 | - $scope.theForm.$setPristine(); | ||
63 | - $mdDialog.hide(); | ||
64 | - } | ||
65 | - ); | 82 | + attributeService |
83 | + .saveEntityAttributes( | ||
84 | + vm.entityType, | ||
85 | + vm.entityId, | ||
86 | + types.attributesScope.shared.value, | ||
87 | + [{key:"configuration", value:editedValue}] | ||
88 | + ) | ||
89 | + .then(function success() { | ||
90 | + $scope.theForm.$setPristine(); | ||
91 | + $mdDialog.hide(); | ||
92 | + }); | ||
66 | } | 93 | } |
67 | 94 | ||
68 | vm.validateId = function() { | 95 | vm.validateId = function() { |
69 | var coincidenceArray = vm.allExtensions.filter(function(ext) { | 96 | var coincidenceArray = vm.allExtensions.filter(function(ext) { |
70 | - return ext.id == vm.newExtension.id; | 97 | + return ext.id == vm.extension.id; |
71 | }); | 98 | }); |
72 | if(coincidenceArray.length) { | 99 | if(coincidenceArray.length) { |
73 | if(!vm.isAdd) { | 100 | if(!vm.isAdd) { |
@@ -82,11 +109,11 @@ export default function ExtensionDialogController($scope, $mdDialog, $translate, | @@ -82,11 +109,11 @@ export default function ExtensionDialogController($scope, $mdDialog, $translate, | ||
82 | } else { | 109 | } else { |
83 | $scope.theForm.extensionId.$setValidity('uniqueIdValidation', true); | 110 | $scope.theForm.extensionId.$setValidity('uniqueIdValidation', true); |
84 | } | 111 | } |
85 | - } | 112 | + }; |
86 | 113 | ||
87 | function saveTransformers() { | 114 | function saveTransformers() { |
88 | - var config = vm.newExtension.configuration.converterConfigurations; | ||
89 | - if(vm.newExtension.type == types.extensionType.http) { | 115 | + var config = vm.extension.configuration.converterConfigurations; |
116 | + if(vm.extension.type == types.extensionType.http) { | ||
90 | for(let i=0;i<config.length;i++) { | 117 | for(let i=0;i<config.length;i++) { |
91 | for(let j=0;j<config[i].converters.length;j++){ | 118 | for(let j=0;j<config[i].converters.length;j++){ |
92 | for(let k=0;k<config[i].converters[j].attributes.length;k++){ | 119 | for(let k=0;k<config[i].converters[j].attributes.length;k++){ |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<md-dialog aria-label="{{ (vm.isAdd ? 'extension.add' : 'extension.edit' ) | translate }}" style="min-width: 1000px;"> | 18 | +<md-dialog class="extensionDialog" aria-label="{{ (vm.isAdd ? 'extension.add' : 'extension.edit' ) | translate }}"> |
19 | <form name="theForm" ng-submit="vm.save()"> | 19 | <form name="theForm" ng-submit="vm.save()"> |
20 | <md-toolbar> | 20 | <md-toolbar> |
21 | <div class="md-toolbar-tools"> | 21 | <div class="md-toolbar-tools"> |
@@ -26,8 +26,11 @@ | @@ -26,8 +26,11 @@ | ||
26 | </md-button> | 26 | </md-button> |
27 | </div> | 27 | </div> |
28 | </md-toolbar> | 28 | </md-toolbar> |
29 | + | ||
29 | <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> | 30 | <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> |
31 | + | ||
30 | <span style="min-height: 5px;" flex="" ng-show="!loading"></span> | 32 | <span style="min-height: 5px;" flex="" ng-show="!loading"></span> |
33 | + | ||
31 | <md-dialog-content> | 34 | <md-dialog-content> |
32 | <div class="md-dialog-content"> | 35 | <div class="md-dialog-content"> |
33 | <md-content class="md-padding" layout="column"> | 36 | <md-content class="md-padding" layout="column"> |
@@ -35,41 +38,48 @@ | @@ -35,41 +38,48 @@ | ||
35 | <section flex layout="row"> | 38 | <section flex layout="row"> |
36 | <md-input-container flex="60" class="md-block"> | 39 | <md-input-container flex="60" class="md-block"> |
37 | <label translate>extension.extension-id</label> | 40 | <label translate>extension.extension-id</label> |
38 | - <input required name="extensionId" ng-model="vm.newExtension.id" ng-change="vm.validateId()"> | 41 | + <input required name="extensionId" ng-model="vm.extension.id" ng-change="vm.validateId()"> |
39 | <div ng-messages="theForm.extensionId.$error"> | 42 | <div ng-messages="theForm.extensionId.$error"> |
40 | <div translate ng-message="required">extension.id-required</div> | 43 | <div translate ng-message="required">extension.id-required</div> |
41 | <div translate ng-message="uniqueIdValidation">extension.unique-id-required</div> | 44 | <div translate ng-message="uniqueIdValidation">extension.unique-id-required</div> |
42 | </div> | 45 | </div> |
43 | </md-input-container> | 46 | </md-input-container> |
47 | + | ||
44 | <md-input-container flex="40" class="md-block"> | 48 | <md-input-container flex="40" class="md-block"> |
45 | <label translate>extension.extension-type</label> | 49 | <label translate>extension.extension-type</label> |
46 | - <md-select ng-disabled="!vm.isAdd" required name="extensionType" ng-model="vm.newExtension.type"> | 50 | + |
51 | + <md-select ng-disabled="!vm.isAdd" required name="extensionType" ng-change="vm.extensionTypeChange()" ng-model="vm.extension.type"> | ||
47 | <md-option ng-repeat="(key,value) in vm.types.extensionType" ng-value="value"> | 52 | <md-option ng-repeat="(key,value) in vm.types.extensionType" ng-value="value"> |
48 | {{value}} | 53 | {{value}} |
49 | </md-option> | 54 | </md-option> |
50 | </md-select> | 55 | </md-select> |
56 | + | ||
51 | <div ng-messages="theForm.extensionType.$error"> | 57 | <div ng-messages="theForm.extensionType.$error"> |
52 | <div translate ng-message="required">extension.type-required</div> | 58 | <div translate ng-message="required">extension.type-required</div> |
53 | </div> | 59 | </div> |
54 | </md-input-container> | 60 | </md-input-container> |
55 | </section> | 61 | </section> |
56 | 62 | ||
57 | - <div tb-extension-form-http config="vm.configuration" is-add="vm.isAdd" ng-if="vm.newExtension.type && vm.newExtension.type == vm.types.extensionType.http"></div> | 63 | + <div tb-extension-form-http config="vm.extension.configuration" is-add="vm.isAdd" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.http"></div> |
58 | 64 | ||
65 | + <div tb-extension-form-opc configuration="vm.extension.configuration" ng-if="vm.extension.type && vm.extension.type == vm.types.extensionType.opc"></div> | ||
59 | </fieldset> | 66 | </fieldset> |
60 | - | ||
61 | - <!--<div>{{vm.newExtension}}</div>--> | 67 | + <!--<div>{{vm.extension}}</div>--> |
62 | </md-content> | 68 | </md-content> |
63 | </div> | 69 | </div> |
64 | </md-dialog-content> | 70 | </md-dialog-content> |
71 | + | ||
65 | <md-dialog-actions layout="row"> | 72 | <md-dialog-actions layout="row"> |
66 | <span flex></span> | 73 | <span flex></span> |
67 | - <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" | 74 | + <md-button type="submit" |
75 | + ng-disabled="loading || theForm.$invalid || !theForm.$dirty" | ||
68 | class="md-raised md-primary"> | 76 | class="md-raised md-primary"> |
69 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} | 77 | {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} |
70 | </md-button> | 78 | </md-button> |
79 | + | ||
71 | <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }} | 80 | <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }} |
72 | </md-button> | 81 | </md-button> |
73 | </md-dialog-actions> | 82 | </md-dialog-actions> |
74 | </form> | 83 | </form> |
75 | -</md-dialog> | ||
84 | +</md-dialog> | ||
85 | + |
@@ -126,11 +126,13 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | @@ -126,11 +126,13 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | ||
126 | controllerAs: 'vm', | 126 | controllerAs: 'vm', |
127 | templateUrl: extensionDialogTemplate, | 127 | templateUrl: extensionDialogTemplate, |
128 | parent: angular.element($document[0].body), | 128 | parent: angular.element($document[0].body), |
129 | - locals: { isAdd: isAdd, | ||
130 | - allExtensions: vm.allExtensions, | ||
131 | - entityId: vm.entityId, | ||
132 | - entityType: vm.entityType, | ||
133 | - extension: extension}, | 129 | + locals: { |
130 | + isAdd: isAdd, | ||
131 | + allExtensions: vm.allExtensions, | ||
132 | + entityId: vm.entityId, | ||
133 | + entityType: vm.entityType, | ||
134 | + extension: extension | ||
135 | + }, | ||
134 | bindToController: true, | 136 | bindToController: true, |
135 | targetEvent: $event, | 137 | targetEvent: $event, |
136 | fullscreen: true, | 138 | fullscreen: true, |
1 | +/* | ||
2 | + * Copyright © 2016-2017 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'brace/ext/language_tools'; | ||
18 | +import 'brace/mode/json'; | ||
19 | +import 'brace/theme/github'; | ||
20 | + | ||
21 | +import './extension-form.scss'; | ||
22 | + | ||
23 | +/* eslint-disable angular/log */ | ||
24 | + | ||
25 | +import extensionFormOpcTemplate from './extension-form-opc.tpl.html'; | ||
26 | + | ||
27 | +/* eslint-enable import/no-unresolved, import/default */ | ||
28 | + | ||
29 | +/*@ngInject*/ | ||
30 | +export default function ExtensionFormOpcDirective($compile, $templateCache, $translate, types) { | ||
31 | + | ||
32 | + | ||
33 | + var linker = function(scope, element) { | ||
34 | + | ||
35 | + | ||
36 | + function Server() { | ||
37 | + this.applicationName = "Thingsboard OPC-UA client"; | ||
38 | + this.applicationUri = ""; | ||
39 | + this.host = "localhost"; | ||
40 | + this.port = 49320; | ||
41 | + this.scanPeriodInSeconds = 10; | ||
42 | + this.timeoutInMillis = 5000; | ||
43 | + this.security = "Basic128Rsa15"; | ||
44 | + this.identity = { | ||
45 | + "type": "anonymous" | ||
46 | + }; | ||
47 | + this.keystore = { | ||
48 | + "type": "PKCS12", | ||
49 | + "location": "example.pfx", | ||
50 | + "password": "secret", | ||
51 | + "alias": "gateway", | ||
52 | + "keyPassword": "secret" | ||
53 | + }; | ||
54 | + this.mapping = [] | ||
55 | + } | ||
56 | + | ||
57 | + function Map() { | ||
58 | + this.deviceNodePattern = "Channel1\\.Device\\d+$"; | ||
59 | + this.deviceNamePattern = "Device ${_System._DeviceId}"; | ||
60 | + this.attributes = []; | ||
61 | + this.timeseries = []; | ||
62 | + } | ||
63 | + | ||
64 | + function Attribute() { | ||
65 | + this.key = "Tag1"; | ||
66 | + this.type = "string"; | ||
67 | + this.value = "${Tag1}"; | ||
68 | + } | ||
69 | + | ||
70 | + function Timeseries() { | ||
71 | + this.key = "Tag2"; | ||
72 | + this.type = "long"; | ||
73 | + this.value = "${Tag2}"; | ||
74 | + } | ||
75 | + | ||
76 | + | ||
77 | + var template = $templateCache.get(extensionFormOpcTemplate); | ||
78 | + element.html(template); | ||
79 | + | ||
80 | + scope.types = types; | ||
81 | + scope.theForm = scope.$parent.theForm; | ||
82 | + | ||
83 | + | ||
84 | + if (!scope.configuration.servers.length) { | ||
85 | + scope.configuration.servers.push(new Server()); | ||
86 | + } | ||
87 | + | ||
88 | + scope.addServer = function(serversList) { | ||
89 | + serversList.push(new Server()); | ||
90 | + // scope.addMap(serversList[serversList.length-1].mapping); | ||
91 | + | ||
92 | + scope.theForm.$setDirty(); | ||
93 | + }; | ||
94 | + | ||
95 | + scope.addMap = function(mappingList) { | ||
96 | + mappingList.push(new Map()); | ||
97 | + scope.theForm.$setDirty(); | ||
98 | + }; | ||
99 | + | ||
100 | + scope.addNewAttribute = function(attributesList) { | ||
101 | + attributesList.push(new Attribute()); | ||
102 | + scope.theForm.$setDirty(); | ||
103 | + }; | ||
104 | + | ||
105 | + scope.addNewTimeseries = function(timeseriesList) { | ||
106 | + timeseriesList.push(new Timeseries()); | ||
107 | + scope.theForm.$setDirty(); | ||
108 | + }; | ||
109 | + | ||
110 | + | ||
111 | + scope.removeItem = (item, itemList) => { | ||
112 | + var index = itemList.indexOf(item); | ||
113 | + if (index > -1) { | ||
114 | + itemList.splice(index, 1); | ||
115 | + } | ||
116 | + scope.theForm.$setDirty(); | ||
117 | + }; | ||
118 | + | ||
119 | + | ||
120 | + $compile(element.contents())(scope); | ||
121 | + | ||
122 | + | ||
123 | + scope.fileAdded = function($file, model, options) { | ||
124 | + let reader = new FileReader(); | ||
125 | + reader.onload = function(event) { | ||
126 | + scope.$apply(function() { | ||
127 | + if(event.target.result) { | ||
128 | + scope.theForm.$setDirty(); | ||
129 | + let addedFile = event.target.result; | ||
130 | + | ||
131 | + if (addedFile && addedFile.length > 0) { | ||
132 | + model[options.fileName] = $file.name; | ||
133 | + model[options.file] = addedFile.replace(/^data.*base64,/, ""); | ||
134 | + | ||
135 | + } | ||
136 | + } | ||
137 | + }); | ||
138 | + }; | ||
139 | + reader.readAsDataURL($file.file); | ||
140 | + | ||
141 | + }; | ||
142 | + | ||
143 | + scope.clearFile = function(model, options) { | ||
144 | + scope.theForm.$setDirty(); | ||
145 | + | ||
146 | + model[options.fileName] = null; | ||
147 | + model[options.file] = null; | ||
148 | + | ||
149 | + }; | ||
150 | + | ||
151 | + }; | ||
152 | + | ||
153 | + return { | ||
154 | + restrict: "A", | ||
155 | + link: linker, | ||
156 | + scope: { | ||
157 | + configuration: "=", | ||
158 | + isAdd: "=" | ||
159 | + } | ||
160 | + } | ||
161 | +} |
@@ -15,4 +15,552 @@ | @@ -15,4 +15,552 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div>OPC UA</div> | ||
18 | +<md-card class="extension-form extension-opc"> | ||
19 | + <md-card-title> | ||
20 | + <md-card-title-text> | ||
21 | + <span translate class="md-headline">extension.configuration</span> | ||
22 | + </md-card-title-text> | ||
23 | + </md-card-title> | ||
24 | + | ||
25 | + <md-card-content> | ||
26 | + <v-accordion id="http-server-configs-accordion" class="vAccordion--default"> | ||
27 | + <v-pane id="http-servers-pane" expanded="true"> | ||
28 | + <v-pane-header> | ||
29 | + {{ 'extension.opc-server' | translate }} | ||
30 | + </v-pane-header> | ||
31 | + | ||
32 | + <v-pane-content> | ||
33 | + <div ng-if="configuration.servers.length === 0"> | ||
34 | + <span translate layout-align="center center" class="tb-prompt">extension.opc-add-server-prompt</span> | ||
35 | + </div> | ||
36 | + | ||
37 | + <div ng-if="configuration.servers.length > 0"> | ||
38 | + <ol class="list-group"> | ||
39 | + <li class="list-group-item" ng-repeat="(serverIndex, server) in configuration.servers"> | ||
40 | + <md-button aria-label="{{ 'action.remove' | translate }}" | ||
41 | + class="md-icon-button" | ||
42 | + ng-click="removeItem(server, configuration.servers)" | ||
43 | + ng-hide="configuration.servers.length < 2" | ||
44 | + > | ||
45 | + <ng-md-icon icon="close" aria-label="{{ 'action.remove' | translate }}"></ng-md-icon> | ||
46 | + <md-tooltip md-direction="top"> | ||
47 | + {{ 'action.remove' | translate }} | ||
48 | + </md-tooltip> | ||
49 | + </md-button> | ||
50 | + | ||
51 | + <md-card> | ||
52 | + <md-card-content> | ||
53 | + | ||
54 | + <div layout="row"> | ||
55 | + <md-input-container flex="50" class="md-block"> | ||
56 | + <label translate>extension.opc-application-name</label> | ||
57 | + <input required name="applicationName_{{serverIndex}}" ng-model="server.applicationName"> | ||
58 | + <div ng-messages="theForm['applicationName_' + serverIndex].$error"> | ||
59 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
60 | + </div> | ||
61 | + </md-input-container> | ||
62 | + | ||
63 | + | ||
64 | + <md-input-container flex="50" class="md-block"> | ||
65 | + <label translate>extension.opc-application-uri</label> | ||
66 | + <input required name="applicationUri_{{serverIndex}}" ng-model="server.applicationUri"> | ||
67 | + <div ng-messages="theForm['applicationUri_' + serverIndex].$error"> | ||
68 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
69 | + </div> | ||
70 | + </md-input-container> | ||
71 | + </div> | ||
72 | + | ||
73 | + | ||
74 | + <div layout="row"> | ||
75 | + <md-input-container flex="50" class="md-block"> | ||
76 | + <label translate>extension.opc-host</label> | ||
77 | + <input required name="host_{{serverIndex}}" ng-model="server.host"> | ||
78 | + <div ng-messages="theForm['host_' + serverIndex].$error"> | ||
79 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
80 | + </div> | ||
81 | + </md-input-container> | ||
82 | + | ||
83 | + <md-input-container flex="50" class="md-block"> | ||
84 | + <label translate>extension.opc-port</label> | ||
85 | + <input type="number" | ||
86 | + required | ||
87 | + name="port_{{serverIndex}}" | ||
88 | + ng-model="server.port" | ||
89 | + min="1" | ||
90 | + max="65535" | ||
91 | + > | ||
92 | + <div ng-messages="theForm['port_' + serverIndex].$error"> | ||
93 | + <div translate | ||
94 | + ng-message="required" | ||
95 | + >extension.opc-field-required</div> | ||
96 | + <div translate | ||
97 | + ng-message="min" | ||
98 | + >Port should be in a range from 1 to 65535</div> | ||
99 | + <div translate | ||
100 | + ng-message="max" | ||
101 | + >Port should be in a range from 1 to 65535</div> | ||
102 | + </div> | ||
103 | + </md-input-container> | ||
104 | + </div> | ||
105 | + | ||
106 | + <div layout="row"> | ||
107 | + <md-input-container flex="50" class="md-block"> | ||
108 | + <label translate>extension.opc-scan-period-in-seconds</label> | ||
109 | + <input type="number" | ||
110 | + required | ||
111 | + name="scanPeriodInSeconds_{{serverIndex}}" | ||
112 | + ng-model="server.scanPeriodInSeconds"> | ||
113 | + <div ng-messages="theForm['scanPeriodInSeconds_' + serverIndex].$error"> | ||
114 | + <div translate | ||
115 | + ng-message="required" | ||
116 | + >extension.opc-field-required</div> | ||
117 | + </div> | ||
118 | + </md-input-container> | ||
119 | + | ||
120 | + <md-input-container flex="50" class="md-block"> | ||
121 | + <label translate>extension.opc-timeout-in-millis</label> | ||
122 | + <input type="number" | ||
123 | + required name="timeoutInMillis_{{serverIndex}}" | ||
124 | + ng-model="server.timeoutInMillis" | ||
125 | + > | ||
126 | + <div ng-messages="theForm['timeoutInMillis_' + serverIndex].$error"> | ||
127 | + <div translate | ||
128 | + ng-message="required" | ||
129 | + >extension.opc-field-required</div> | ||
130 | + </div> | ||
131 | + </md-input-container> | ||
132 | + </div> | ||
133 | + | ||
134 | + <div layout="row"> | ||
135 | + | ||
136 | + <md-input-container flex="50" class="md-block tb-container-for-select"> | ||
137 | + <label translate>extension.opc-security</label> | ||
138 | + <md-select required | ||
139 | + name="securityType_{{serverIndex}}" | ||
140 | + ng-model="server.security"> | ||
141 | + <md-option ng-value="securityType" | ||
142 | + ng-repeat="(securityType, securityValue) in types.extensionOpcSecurityTypes" | ||
143 | + ><span ng-bind="::securityValue"></span></md-option> | ||
144 | + </md-select> | ||
145 | + <div ng-messages="theForm['securityType_' + serverIndex].$error"> | ||
146 | + <div translate | ||
147 | + ng-message="required" | ||
148 | + >extension.opc-field-required</div> | ||
149 | + </div> | ||
150 | + </md-input-container> | ||
151 | + | ||
152 | + <md-input-container flex="50" class="md-block tb-container-for-select"> | ||
153 | + <label translate>extension.opc-identity</label> | ||
154 | + <md-select required | ||
155 | + name="identityType_{{serverIndex}}" | ||
156 | + ng-model="server.identity.type" | ||
157 | + > | ||
158 | + <md-option ng-value="identityType" | ||
159 | + ng-repeat="(identityType, identityValue) in types.extensionIdentityType" | ||
160 | + ><span ng-bind="::identityValue"></span></md-option> | ||
161 | + </md-select> | ||
162 | + <div ng-messages="theForm['identityType_' + serverIndex].$error"> | ||
163 | + <div translate | ||
164 | + ng-message="required" | ||
165 | + >extension.opc-field-required</div> | ||
166 | + </div> | ||
167 | + </md-input-container> | ||
168 | + </div> | ||
169 | + | ||
170 | + | ||
171 | + <div ng-if="server.identity.type != 'username'"> | ||
172 | + <span class="" | ||
173 | + ng-init="server.identity = {'type':'anonymous'}"></span> | ||
174 | + </div> | ||
175 | + <div layout="row" ng-if="server.identity.type == 'username'"> | ||
176 | + <md-input-container flex="50" class="md-block"> | ||
177 | + <label translate>extension.opc-username</label> | ||
178 | + <input required | ||
179 | + name="identityUsername_{{serverIndex}}" | ||
180 | + ng-model="server.identity.username" | ||
181 | + > | ||
182 | + <div ng-messages="theForm['identityUsername_' + serverIndex].$error"> | ||
183 | + <div translate | ||
184 | + ng-message="required" | ||
185 | + >extension.opc-field-required</div> | ||
186 | + </div> | ||
187 | + </md-input-container> | ||
188 | + | ||
189 | + <md-input-container flex="50" class="md-block"> | ||
190 | + <label translate>extension.opc-password</label> | ||
191 | + <input required | ||
192 | + name="identityPassword_{{serverIndex}}" ng-model="server.identity.password"> | ||
193 | + <div ng-messages="theForm['identityPassword_' + serverIndex].$error"> | ||
194 | + <div translate | ||
195 | + ng-message="required" | ||
196 | + >extension.opc-field-required</div> | ||
197 | + </div> | ||
198 | + </md-input-container> | ||
199 | + </div> | ||
200 | + | ||
201 | + | ||
202 | + <v-accordion id="opc-attributes-accordion" class="vAccordion--default"> | ||
203 | + <v-pane id="opc-attributes-pane"> | ||
204 | + <v-pane-header> | ||
205 | + {{ 'extension.opc-keystore' | translate }} | ||
206 | + </v-pane-header> | ||
207 | + <v-pane-content> | ||
208 | + | ||
209 | + <md-input-container class="md-block tb-container-for-select"> | ||
210 | + <label translate>extension.opc-keystore-type</label> | ||
211 | + <md-select required name="keystoreType_{{serverIndex}}" ng-model="server.keystore.type"> | ||
212 | + <md-option ng-value="keystoreType" ng-repeat="(keystoreType, keystoreValue) in types.extensionKeystoreType"><span ng-bind="::keystoreValue"></span></md-option> | ||
213 | + </md-select> | ||
214 | + <div ng-messages="theForm['keystoreType_'+serverIndex].$error"> | ||
215 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
216 | + </div> | ||
217 | + </md-input-container> | ||
218 | + | ||
219 | + <div class="tb-container"> | ||
220 | + <span ng-init='fieldsToFill = {"fileName":"fileName", "file":"file"}'></span> | ||
221 | + <label class="tb-label" translate>extension.opc-keystore-location</label> | ||
222 | + <div flow-init="{singleFile:true}" flow-file-added='fileAdded($file, server.keystore, fieldsToFill)' class="tb-file-select-container"> | ||
223 | + <div class="tb-file-clear-container"> | ||
224 | + <md-button ng-click='clearFile(server.keystore, fieldsToFill)' class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ 'action.remove' | translate }}"> | ||
225 | + <md-tooltip md-direction="top"> | ||
226 | + {{ 'action.remove' | translate }} | ||
227 | + </md-tooltip> | ||
228 | + <md-icon aria-label="{{ 'action.remove' | translate }}" class="material-icons">close</md-icon> | ||
229 | + </md-button> | ||
230 | + </div> | ||
231 | + <div class="alert tb-flow-drop" flow-drop> | ||
232 | + <label for="dropFileKeystore_{{serverIndex}}" translate>extension.drop-file</label> | ||
233 | + <input flow-attrs="{accept:'.pfx,.p12'}" | ||
234 | + type="file" | ||
235 | + class="file-input" | ||
236 | + flow-btn id="dropFileKeystore_{{serverIndex}}" | ||
237 | + name="keystoreFile" | ||
238 | + ng-model="server.keystore.file" | ||
239 | + > | ||
240 | + </div> | ||
241 | + </div> | ||
242 | + </div> | ||
243 | + <div> | ||
244 | + <div ng-if="!server.keystore[fieldsToFill.fileName]" class="tb-error-message" translate>extension.no-file</div> | ||
245 | + <div ng-if="server.keystore[fieldsToFill.fileName]">{{server.keystore[fieldsToFill.fileName]}}</div> | ||
246 | + </div> | ||
247 | + | ||
248 | + | ||
249 | + <div flex layout="row"> | ||
250 | + <md-input-container flex="50" class="md-block"> | ||
251 | + <label translate>extension.opc-keystore-password</label> | ||
252 | + <input required name="keystorePassword_{{serverIndex}}" ng-model="server.keystore.password"> | ||
253 | + <div ng-messages="theForm['keystorePassword_' + serverIndex].$error"> | ||
254 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
255 | + </div> | ||
256 | + </md-input-container> | ||
257 | + | ||
258 | + <md-input-container flex="50" class="md-block"> | ||
259 | + <label translate>extension.opc-keystore-alias</label> | ||
260 | + <input required name="keystoreAlias_{{serverIndex}}" ng-model="server.keystore.alias"> | ||
261 | + <div ng-messages="theForm['keystoreAlias_' + serverIndex].$error"> | ||
262 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
263 | + </div> | ||
264 | + </md-input-container> | ||
265 | + </div> | ||
266 | + | ||
267 | + <md-input-container class="md-block"> | ||
268 | + <label translate>extension.opc-keystore-key-password</label> | ||
269 | + <input required name="keystoreKeyPassword_{{serverIndex}}" ng-model="server.keystore.keyPassword"> | ||
270 | + <div ng-messages="theForm['keystoreKeyPassword_' + serverIndex].$error"> | ||
271 | + <div translate ng-message="required">extension.opc-field-required</div> | ||
272 | + </div> | ||
273 | + </md-input-container> | ||
274 | + | ||
275 | + </v-pane-content> | ||
276 | + </v-pane> | ||
277 | + </v-accordion> | ||
278 | + | ||
279 | + | ||
280 | + <v-accordion id="opc-attributes-accordion" | ||
281 | + class="vAccordion--default" | ||
282 | + > | ||
283 | + <v-pane id="opc-attributes-pane"> | ||
284 | + <v-pane-header> | ||
285 | + {{ 'extension.opc-mapping' | translate }} | ||
286 | + </v-pane-header> | ||
287 | + <v-pane-content> | ||
288 | + <div ng-if="server.mapping.length > 0"> | ||
289 | + <ol class="list-group"> | ||
290 | + <li class="list-group-item" | ||
291 | + ng-repeat="(mapIndex, map) in server.mapping" | ||
292 | + > | ||
293 | + <md-button aria-label="{{ 'action.remove' | translate }}" | ||
294 | + class="md-icon-button" | ||
295 | + ng-click="removeItem(map, server.mapping)" | ||
296 | + > | ||
297 | + <ng-md-icon icon="close" aria-label="{{ 'action.remove' | translate }}"></ng-md-icon> | ||
298 | + <md-tooltip md-direction="top"> | ||
299 | + {{ 'action.remove' | translate }} | ||
300 | + </md-tooltip> | ||
301 | + </md-button> | ||
302 | + | ||
303 | + <md-card> | ||
304 | + <md-card-content> | ||
305 | + <div flex layout="row"> | ||
306 | + <md-input-container flex="50" class="md-block"> | ||
307 | + <label translate>extension.opc-device-node-pattern</label> | ||
308 | + <input required | ||
309 | + name="deviceNodePattern_{{serverIndex}}{{mapIndex}}" | ||
310 | + ng-model="map.deviceNodePattern" | ||
311 | + > | ||
312 | + <div ng-messages="theForm['deviceNodePattern_' + serverIndex + mapIndex].$error"> | ||
313 | + <div translate | ||
314 | + ng-message="required" | ||
315 | + >extension.opc-field-required</div> | ||
316 | + </div> | ||
317 | + </md-input-container> | ||
318 | + | ||
319 | + <md-input-container flex="50" class="md-block"> | ||
320 | + <label translate>extension.opc-device-name-pattern</label> | ||
321 | + <input required | ||
322 | + name="deviceNamePattern_{{serverIndex}}{{mapIndex}}" | ||
323 | + ng-model="map.deviceNamePattern" | ||
324 | + > | ||
325 | + <div ng-messages="theForm['deviceNamePattern_' + serverIndex + mapIndex].$error"> | ||
326 | + <div translate | ||
327 | + ng-message="required" | ||
328 | + >extension.opc-field-required</div> | ||
329 | + </div> | ||
330 | + </md-input-container> | ||
331 | + </div> | ||
332 | + | ||
333 | + | ||
334 | + <v-accordion id="opc-attributes-accordion" | ||
335 | + class="vAccordion--default" | ||
336 | + > | ||
337 | + <v-pane id="opc-attributes-pane"> | ||
338 | + <v-pane-header> | ||
339 | + {{ 'extension.opc-mapping-attributes' | translate }} | ||
340 | + </v-pane-header> | ||
341 | + <v-pane-content> | ||
342 | + <div ng-show="map.attributes.length > 0"> | ||
343 | + <ol class="list-group"> | ||
344 | + <li class="list-group-item" | ||
345 | + ng-repeat="(attributeIndex, attribute) in map.attributes" | ||
346 | + > | ||
347 | + <md-button aria-label="{{ 'action.remove' | translate }}" | ||
348 | + class="md-icon-button" | ||
349 | + ng-click="removeItem(attribute, map.attributes)"> | ||
350 | + <ng-md-icon icon="close" | ||
351 | + aria-label="{{ 'action.remove' | translate }}" | ||
352 | + ></ng-md-icon> | ||
353 | + <md-tooltip md-direction="top"> | ||
354 | + {{ 'action.remove' | translate }} | ||
355 | + </md-tooltip> | ||
356 | + </md-button> | ||
357 | + <md-card> | ||
358 | + <md-card-content> | ||
359 | + | ||
360 | + <section flex | ||
361 | + layout="row" | ||
362 | + > | ||
363 | + <md-input-container flex="60" class="md-block"> | ||
364 | + <label translate>extension.key</label> | ||
365 | + <input required | ||
366 | + name="opcAttributeKey_{{serverIndex}}{{mapIndex}}{{attributeIndex}}" | ||
367 | + ng-model="attribute.key" | ||
368 | + > | ||
369 | + <div ng-messages="theForm['opcAttributeKey_' + serverIndex + mapIndex + attributeIndex].$error"> | ||
370 | + <div translate | ||
371 | + ng-message="required" | ||
372 | + >extension.opc-field-required</div> | ||
373 | + </div> | ||
374 | + </md-input-container> | ||
375 | + <md-input-container flex="40" class="md-block tb-container-for-select"> | ||
376 | + <label translate>extension.type</label> | ||
377 | + <md-select required name="opcAttributeType_{{serverIndex}}{{mapIndex}}{{attributeIndex}}" | ||
378 | + ng-model="attribute.type" | ||
379 | + > | ||
380 | + <md-option ng-repeat="(attrType, attrTypeValue) in types.extensionValueType" | ||
381 | + ng-value="attrType" | ||
382 | + > | ||
383 | + {{attrTypeValue | translate}} | ||
384 | + </md-option> | ||
385 | + </md-select> | ||
386 | + <div ng-messages="theForm['opcAttributeType_' + serverIndex + mapIndex + attributeIndex].$error"> | ||
387 | + <div translate | ||
388 | + ng-message="required" | ||
389 | + >extension.required-type</div> | ||
390 | + </div> | ||
391 | + </md-input-container> | ||
392 | + </section> | ||
393 | + | ||
394 | + <section flex layout="row"> | ||
395 | + <md-input-container flex="100" class="md-block"> | ||
396 | + <label translate>extension.value</label> | ||
397 | + <input required name="opcAttributeValue_{{serverIndex}}{{mapIndex}}{{attributeIndex}}" | ||
398 | + ng-model="attribute.value" | ||
399 | + > | ||
400 | + <div ng-messages="theForm['opcAttributeValue_' + serverIndex + mapIndex + attributeIndex].$error"> | ||
401 | + <div translate | ||
402 | + ng-message="required" | ||
403 | + >extension.opc-field-required</div> | ||
404 | + </div> | ||
405 | + </md-input-container> | ||
406 | + | ||
407 | + </section> | ||
408 | + | ||
409 | + | ||
410 | + </md-card-content> | ||
411 | + </md-card> | ||
412 | + </li> | ||
413 | + </ol> | ||
414 | + </div> | ||
415 | + <div flex layout="row" layout-align="start center"> | ||
416 | + <md-button class="md-primary md-raised" | ||
417 | + ng-click="addNewAttribute(map.attributes)" | ||
418 | + aria-label="{{ 'action.add' | translate }}" | ||
419 | + > | ||
420 | + <md-tooltip md-direction="top"> | ||
421 | + {{ 'extension.add-map' | translate }} | ||
422 | + </md-tooltip> | ||
423 | + <md-icon class="material-icons">add</md-icon> | ||
424 | + <span translate>action.add</span> | ||
425 | + </md-button> | ||
426 | + </div> | ||
427 | + </v-pane-content> | ||
428 | + </v-pane> | ||
429 | + </v-accordion> | ||
430 | + | ||
431 | + <v-accordion id="opc-timeseries-accordion" class="vAccordion--default"> | ||
432 | + <v-pane id="opc-timeseries-pane"> | ||
433 | + <v-pane-header> | ||
434 | + {{ 'extension.opc-timeseries' | translate }} | ||
435 | + </v-pane-header> | ||
436 | + <v-pane-content> | ||
437 | + <div ng-show="map.timeseries.length > 0"> | ||
438 | + <ol class="list-group"> | ||
439 | + <li class="list-group-item" | ||
440 | + ng-repeat="(timeseriesIndex, timeseries) in map.timeseries" | ||
441 | + > | ||
442 | + <md-button aria-label="{{ 'action.remove' | translate }}" | ||
443 | + class="md-icon-button" | ||
444 | + ng-click="removeItem(timeseries, map.timeseries)" | ||
445 | + > | ||
446 | + <ng-md-icon icon="close" aria-label="{{ 'action.remove' | translate }}"></ng-md-icon> | ||
447 | + <md-tooltip md-direction="top"> | ||
448 | + {{ 'action.remove' | translate }} | ||
449 | + </md-tooltip> | ||
450 | + </md-button> | ||
451 | + <md-card> | ||
452 | + <md-card-content> | ||
453 | + <section flex layout="row"> | ||
454 | + <md-input-container flex="60" class="md-block"> | ||
455 | + <label translate>extension.key</label> | ||
456 | + <input required | ||
457 | + name="opcTimeseriesKey_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}" | ||
458 | + ng-model="timeseries.key" | ||
459 | + > | ||
460 | + <div ng-messages="theForm['opcTimeseriesKey_' + serverIndex + mapIndex + timeseriesIndex].$error"> | ||
461 | + <div translate | ||
462 | + ng-message="required" | ||
463 | + >extension.opc-field-required</div> | ||
464 | + </div> | ||
465 | + </md-input-container> | ||
466 | + <md-input-container flex="40" | ||
467 | + class="md-block tb-container-for-select" | ||
468 | + > | ||
469 | + <label translate>extension.type</label> | ||
470 | + <md-select required | ||
471 | + name="opcTimeseriesType_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}" | ||
472 | + ng-model="timeseries.type" | ||
473 | + > | ||
474 | + <md-option ng-repeat="(attrType, attrTypeValue) in types.extensionValueType" | ||
475 | + ng-value="attrType" | ||
476 | + > | ||
477 | + {{attrTypeValue | translate}} | ||
478 | + </md-option> | ||
479 | + </md-select> | ||
480 | + <div ng-messages="theForm['opcTimeseriesType_' + serverIndex + mapIndex + timeseriesIndex].$error"> | ||
481 | + <div translate | ||
482 | + ng-message="required" | ||
483 | + >extension.opc-field-required</div> | ||
484 | + </div> | ||
485 | + </md-input-container> | ||
486 | + </section> | ||
487 | + <section flex layout="row"> | ||
488 | + <md-input-container flex="100" class="md-block"> | ||
489 | + <label translate>extension.value</label> | ||
490 | + <input required name="opcTimeseriesValue_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}" ng-model="timeseries.value"> | ||
491 | + <div ng-messages="theForm['opcTimeseriesValue_' + serverIndex + mapIndex + timeseriesIndex].$error"> | ||
492 | + <div translate ng-message="required">extension.required-value</div> | ||
493 | + </div> | ||
494 | + </md-input-container> | ||
495 | + </section> | ||
496 | + </md-card-content> | ||
497 | + </md-card> | ||
498 | + </li> | ||
499 | + </ol> | ||
500 | + </div> | ||
501 | + <div flex layout="row" layout-align="start center"> | ||
502 | + <md-button class="md-primary md-raised" | ||
503 | + ng-click="addNewAttribute(map.timeseries)" | ||
504 | + aria-label="{{ 'action.add' | translate }}" | ||
505 | + > | ||
506 | + <md-tooltip md-direction="top"> | ||
507 | + {{ 'extension.add-timeseries' | translate }} | ||
508 | + </md-tooltip> | ||
509 | + <md-icon class="material-icons">add</md-icon> | ||
510 | + <span translate>action.add</span> | ||
511 | + </md-button> | ||
512 | + </div> | ||
513 | + </v-pane-content> | ||
514 | + </v-pane> | ||
515 | + </v-accordion> | ||
516 | + | ||
517 | + | ||
518 | + </md-card-content> | ||
519 | + </md-card> | ||
520 | + </li> | ||
521 | + </ol> | ||
522 | + </div> | ||
523 | + <div flex | ||
524 | + layout="row" | ||
525 | + layout-align="start center" | ||
526 | + > | ||
527 | + <md-button class="md-primary md-raised" | ||
528 | + ng-click="addMap(server.mapping)" | ||
529 | + aria-label="{{ 'action.add' | translate }}" | ||
530 | + > | ||
531 | + <md-tooltip md-direction="top"> | ||
532 | + {{ 'extension.add-map' | translate }} | ||
533 | + </md-tooltip> | ||
534 | + <md-icon class="material-icons">add</md-icon> | ||
535 | + <span translate>action.add</span> | ||
536 | + </md-button> | ||
537 | + </div> | ||
538 | + </v-pane-content> | ||
539 | + </v-pane> | ||
540 | + </v-accordion> | ||
541 | + | ||
542 | + </md-card-content> | ||
543 | + </md-card> | ||
544 | + </li> | ||
545 | + </ol> | ||
546 | + | ||
547 | + <div flex | ||
548 | + layout="row" | ||
549 | + layout-align="start center" | ||
550 | + > | ||
551 | + <md-button class="md-primary md-raised" | ||
552 | + ng-click="addServer(configuration.servers)" | ||
553 | + aria-label="{{ 'action.add' | translate }}" | ||
554 | + > | ||
555 | + <md-icon class="material-icons">add</md-icon> | ||
556 | + <span translate>extension.opc-add-another-server</span> | ||
557 | + </md-button> | ||
558 | + </div> | ||
559 | + | ||
560 | + </div> | ||
561 | + </v-pane-content> | ||
562 | + </v-pane> | ||
563 | + </v-accordion> | ||
564 | + <!--{{config}}--> | ||
565 | + </md-card-content> | ||
566 | +</md-card> |
@@ -37,4 +37,20 @@ | @@ -37,4 +37,20 @@ | ||
37 | .ace_text-input { | 37 | .ace_text-input { |
38 | position:absolute!important | 38 | position:absolute!important |
39 | } | 39 | } |
40 | +} | ||
41 | + | ||
42 | +.extensionDialog { | ||
43 | + min-width: 1000px; | ||
44 | +} | ||
45 | + | ||
46 | +.tb-container-for-select { | ||
47 | + height: 58px; | ||
48 | +} | ||
49 | + | ||
50 | +.tb-drop-file-input-hide { | ||
51 | + height: 200%; | ||
52 | + display: block; | ||
53 | + position: absolute; | ||
54 | + bottom: 0; | ||
55 | + width: 100%; | ||
40 | } | 56 | } |
@@ -16,10 +16,12 @@ | @@ -16,10 +16,12 @@ | ||
16 | 16 | ||
17 | import ExtensionTableDirective from './extension-table.directive'; | 17 | import ExtensionTableDirective from './extension-table.directive'; |
18 | import ExtensionFormHttpDirective from './extensions-forms/extension-form-http.directive'; | 18 | import ExtensionFormHttpDirective from './extensions-forms/extension-form-http.directive'; |
19 | +import ExtensionFormOpcDirective from './extensions-forms/extension-form-opc.directive'; | ||
19 | import {ParseToNull} from './extension-dialog.controller'; | 20 | import {ParseToNull} from './extension-dialog.controller'; |
20 | 21 | ||
21 | export default angular.module('thingsboard.extension', []) | 22 | export default angular.module('thingsboard.extension', []) |
22 | .directive('tbExtensionTable', ExtensionTableDirective) | 23 | .directive('tbExtensionTable', ExtensionTableDirective) |
23 | .directive('tbExtensionFormHttp', ExtensionFormHttpDirective) | 24 | .directive('tbExtensionFormHttp', ExtensionFormHttpDirective) |
25 | + .directive('tbExtensionFormOpc', ExtensionFormOpcDirective) | ||
24 | .directive('parseToNull', ParseToNull) | 26 | .directive('parseToNull', ParseToNull) |
25 | .name; | 27 | .name; |
@@ -773,14 +773,44 @@ export default angular.module('thingsboard.locale', []) | @@ -773,14 +773,44 @@ export default angular.module('thingsboard.locale', []) | ||
773 | "json-parse": "Unable to parse transformer json.", | 773 | "json-parse": "Unable to parse transformer json.", |
774 | "attributes": "Attributes", | 774 | "attributes": "Attributes", |
775 | "add-attribute": "Add attribute", | 775 | "add-attribute": "Add attribute", |
776 | + "add-map": "Add mapping element", | ||
776 | "timeseries": "Timeseries", | 777 | "timeseries": "Timeseries", |
777 | "add-timeseries": "Add timeseries", | 778 | "add-timeseries": "Add timeseries", |
779 | + | ||
780 | + "opc-field-required": "Field is required", | ||
781 | + "opc-server": "Servers", | ||
782 | + "opc-add-server-hint": "Add server", | ||
783 | + "opc-add-server-prompt": "Please add server", | ||
784 | + "opc-server-id": "Server id", | ||
785 | + "opc-timeseries": "Timeseries", | ||
786 | + "opc-application-name": "Application name", | ||
787 | + "opc-application-uri": "Application uri", | ||
788 | + "opc-host": "Host", | ||
789 | + "opc-port": "Port", | ||
790 | + "opc-scan-period-in-seconds": "Scan period in seconds", | ||
791 | + "opc-timeout-in-millis": "Timeout in milliseconds", | ||
792 | + "opc-security": "Security", | ||
793 | + "opc-identity": "Identity", | ||
794 | + "opc-keystore": "Keystore", | ||
795 | + "opc-type": "Type", | ||
796 | + "opc-keystore-type":"Type", | ||
797 | + "opc-keystore-location":"Location *", | ||
798 | + "opc-keystore-password":"Password", | ||
799 | + "opc-keystore-alias":"Alias", | ||
800 | + "opc-keystore-key-password":"Key password", | ||
801 | + "opc-mapping":"Mapping", | ||
802 | + "opc-device-node-pattern":"Device node pattern", | ||
803 | + "opc-device-name-pattern":"Device name pattern", | ||
804 | + "opc-mapping-attributes":"Mapping attributes", | ||
805 | + "opc-username":"Username", | ||
806 | + "opc-password":"Password", | ||
807 | + "opc-add-another-server":"Add another server", | ||
778 | }, | 808 | }, |
779 | "fullscreen": { | 809 | "fullscreen": { |
780 | "expand": "Expand to fullscreen", | 810 | "expand": "Expand to fullscreen", |
781 | "exit": "Exit fullscreen", | 811 | "exit": "Exit fullscreen", |
782 | "toggle": "Toggle fullscreen mode", | 812 | "toggle": "Toggle fullscreen mode", |
783 | - "fullscreen": "Fullscreen" | 813 | + "fullscreen": "Fullscreen", |
784 | }, | 814 | }, |
785 | "function": { | 815 | "function": { |
786 | "function": "Function" | 816 | "function": "Function" |