@ -15,4 +15,552 @@
limitations under the License.
-->
< div > OPC UA< / div >
< md-card class = "extension-form extension-opc" >
< md-card-title >
< md-card-title-text >
< span translate class = "md-headline" > extension.configuration< / span >
< / md-card-title-text >
< / md-card-title >
< md-card-content >
< v-accordion id = "http-server-configs-accordion" class = "vAccordion--default" >
< v-pane id = "http-servers-pane" expanded = "true" >
< v-pane-header >
{{ 'extension.opc-server' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "configuration.servers.length === 0" >
< span translate layout-align = "center center" class = "tb-prompt" > extension.opc-add-server-prompt< / span >
< / div >
< div ng-if = "configuration.servers.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(serverIndex, server) in configuration.servers" >
< md-button aria-label = "{{ 'action.remove' | translate }}"
class="md-icon-button"
ng-click="removeItem(server, configuration.servers)"
ng-hide="configuration.servers.length < 2 "
>
< ng-md-icon icon = "close" aria-label = "{{ 'action.remove' | translate }}" > < / ng-md-icon >
< md-tooltip md-direction = "top" >
{{ 'action.remove' | translate }}
< / md-tooltip >
< / md-button >
< md-card >
< md-card-content >
< div layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-application-name< / label >
< input required name = "applicationName_{{serverIndex}}" ng-model = "server.applicationName" >
< div ng-messages = "theForm['applicationName_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-application-uri< / label >
< input required name = "applicationUri_{{serverIndex}}" ng-model = "server.applicationUri" >
< div ng-messages = "theForm['applicationUri_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< div layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-host< / label >
< input required name = "host_{{serverIndex}}" ng-model = "server.host" >
< div ng-messages = "theForm['host_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-port< / label >
< input type = "number"
required
name="port_{{serverIndex}}"
ng-model="server.port"
min="1"
max="65535"
>
< div ng-messages = "theForm['port_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< div translate
ng-message="min"
>Port should be in a range from 1 to 65535< / div >
< div translate
ng-message="max"
>Port should be in a range from 1 to 65535< / div >
< / div >
< / md-input-container >
< / div >
< div layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-scan-period-in-seconds< / label >
< input type = "number"
required
name="scanPeriodInSeconds_{{serverIndex}}"
ng-model="server.scanPeriodInSeconds">
< div ng-messages = "theForm['scanPeriodInSeconds_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-timeout-in-millis< / label >
< input type = "number"
required name="timeoutInMillis_{{serverIndex}}"
ng-model="server.timeoutInMillis"
>
< div ng-messages = "theForm['timeoutInMillis_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< div layout = "row" >
< md-input-container flex = "50" class = "md-block tb-container-for-select" >
< label translate > extension.opc-security< / label >
< md-select required
name="securityType_{{serverIndex}}"
ng-model="server.security">
< md-option ng-value = "securityType"
ng-repeat="(securityType, securityValue) in types.extensionOpcSecurityTypes"
>< span ng-bind = "::securityValue" > < / span > < / md-option >
< / md-select >
< div ng-messages = "theForm['securityType_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block tb-container-for-select" >
< label translate > extension.opc-identity< / label >
< md-select required
name="identityType_{{serverIndex}}"
ng-model="server.identity.type"
>
< md-option ng-value = "identityType"
ng-repeat="(identityType, identityValue) in types.extensionIdentityType"
>< span ng-bind = "::identityValue" > < / span > < / md-option >
< / md-select >
< div ng-messages = "theForm['identityType_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< div ng-if = "server.identity.type != 'username'" >
< span class = ""
ng-init="server.identity = {'type':'anonymous'}">< / span >
< / div >
< div layout = "row" ng-if = "server.identity.type == 'username'" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-username< / label >
< input required
name="identityUsername_{{serverIndex}}"
ng-model="server.identity.username"
>
< div ng-messages = "theForm['identityUsername_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-password< / label >
< input required
name="identityPassword_{{serverIndex}}" ng-model="server.identity.password">
< div ng-messages = "theForm['identityPassword_' + serverIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< v-accordion id = "opc-attributes-accordion" class = "vAccordion--default" >
< v-pane id = "opc-attributes-pane" >
< v-pane-header >
{{ 'extension.opc-keystore' | translate }}
< / v-pane-header >
< v-pane-content >
< md-input-container class = "md-block tb-container-for-select" >
< label translate > extension.opc-keystore-type< / label >
< md-select required name = "keystoreType_{{serverIndex}}" ng-model = "server.keystore.type" >
< md-option ng-value = "keystoreType" ng-repeat = "(keystoreType, keystoreValue) in types.extensionKeystoreType" > < span ng-bind = "::keystoreValue" > < / span > < / md-option >
< / md-select >
< div ng-messages = "theForm['keystoreType_'+serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< div class = "tb-container" >
< span ng-init = 'fieldsToFill = {"fileName":"fileName", "file":"file"}' > < / span >
< label class = "tb-label" translate > extension.opc-keystore-location< / label >
< div flow-init = "{singleFile:true}" flow-file-added = 'fileAdded($file, server.keystore, fieldsToFill)' class = "tb-file-select-container" >
< div class = "tb-file-clear-container" >
< md-button ng-click = 'clearFile(server.keystore, fieldsToFill)' class = "tb-file-clear-btn md-icon-button md-primary" aria-label = "{{ 'action.remove' | translate }}" >
< md-tooltip md-direction = "top" >
{{ 'action.remove' | translate }}
< / md-tooltip >
< md-icon aria-label = "{{ 'action.remove' | translate }}" class = "material-icons" > close< / md-icon >
< / md-button >
< / div >
< div class = "alert tb-flow-drop" flow-drop >
< label for = "dropFileKeystore_{{serverIndex}}" translate > extension.drop-file< / label >
< input flow-attrs = "{accept:'.pfx,.p12'}"
type="file"
class="file-input"
flow-btn id="dropFileKeystore_{{serverIndex}}"
name="keystoreFile"
ng-model="server.keystore.file"
>
< / div >
< / div >
< / div >
< div >
< div ng-if = "!server.keystore[fieldsToFill.fileName]" class = "tb-error-message" translate > extension.no-file< / div >
< div ng-if = "server.keystore[fieldsToFill.fileName]" > {{server.keystore[fieldsToFill.fileName]}}< / div >
< / div >
< div flex layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-keystore-password< / label >
< input required name = "keystorePassword_{{serverIndex}}" ng-model = "server.keystore.password" >
< div ng-messages = "theForm['keystorePassword_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-keystore-alias< / label >
< input required name = "keystoreAlias_{{serverIndex}}" ng-model = "server.keystore.alias" >
< div ng-messages = "theForm['keystoreAlias_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< md-input-container class = "md-block" >
< label translate > extension.opc-keystore-key-password< / label >
< input required name = "keystoreKeyPassword_{{serverIndex}}" ng-model = "server.keystore.keyPassword" >
< div ng-messages = "theForm['keystoreKeyPassword_' + serverIndex].$error" >
< div translate ng-message = "required" > extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "opc-attributes-accordion"
class="vAccordion--default"
>
< v-pane id = "opc-attributes-pane" >
< v-pane-header >
{{ 'extension.opc-mapping' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "server.mapping.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item"
ng-repeat="(mapIndex, map) in server.mapping"
>
< md-button aria-label = "{{ 'action.remove' | translate }}"
class="md-icon-button"
ng-click="removeItem(map, server.mapping)"
>
< ng-md-icon icon = "close" aria-label = "{{ 'action.remove' | translate }}" > < / ng-md-icon >
< md-tooltip md-direction = "top" >
{{ 'action.remove' | translate }}
< / md-tooltip >
< / md-button >
< md-card >
< md-card-content >
< div flex layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-device-node-pattern< / label >
< input required
name="deviceNodePattern_{{serverIndex}}{{mapIndex}}"
ng-model="map.deviceNodePattern"
>
< div ng-messages = "theForm['deviceNodePattern_' + serverIndex + mapIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.opc-device-name-pattern< / label >
< input required
name="deviceNamePattern_{{serverIndex}}{{mapIndex}}"
ng-model="map.deviceNamePattern"
>
< div ng-messages = "theForm['deviceNamePattern_' + serverIndex + mapIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / div >
< v-accordion id = "opc-attributes-accordion"
class="vAccordion--default"
>
< v-pane id = "opc-attributes-pane" >
< v-pane-header >
{{ 'extension.opc-mapping-attributes' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-show = "map.attributes.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item"
ng-repeat="(attributeIndex, attribute) in map.attributes"
>
< md-button aria-label = "{{ 'action.remove' | translate }}"
class="md-icon-button"
ng-click="removeItem(attribute, map.attributes)">
< ng-md-icon icon = "close"
aria-label="{{ 'action.remove' | translate }}"
>< / ng-md-icon >
< md-tooltip md-direction = "top" >
{{ 'action.remove' | translate }}
< / md-tooltip >
< / md-button >
< md-card >
< md-card-content >
< section flex
layout="row"
>
< md-input-container flex = "60" class = "md-block" >
< label translate > extension.key< / label >
< input required
name="opcAttributeKey_{{serverIndex}}{{mapIndex}}{{attributeIndex}}"
ng-model="attribute.key"
>
< div ng-messages = "theForm['opcAttributeKey_' + serverIndex + mapIndex + attributeIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "40" class = "md-block tb-container-for-select" >
< label translate > extension.type< / label >
< md-select required name = "opcAttributeType_{{serverIndex}}{{mapIndex}}{{attributeIndex}}"
ng-model="attribute.type"
>
< md-option ng-repeat = "(attrType, attrTypeValue) in types.extensionValueType"
ng-value="attrType"
>
{{attrTypeValue | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['opcAttributeType_' + serverIndex + mapIndex + attributeIndex].$error" >
< div translate
ng-message="required"
>extension.required-type< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "100" class = "md-block" >
< label translate > extension.value< / label >
< input required name = "opcAttributeValue_{{serverIndex}}{{mapIndex}}{{attributeIndex}}"
ng-model="attribute.value"
>
< div ng-messages = "theForm['opcAttributeValue_' + serverIndex + mapIndex + attributeIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / section >
< / md-card-content >
< / md-card >
< / li >
< / ol >
< / div >
< div flex layout = "row" layout-align = "start center" >
< md-button class = "md-primary md-raised"
ng-click="addNewAttribute(map.attributes)"
aria-label="{{ 'action.add' | translate }}"
>
< md-tooltip md-direction = "top" >
{{ 'extension.add-map' | translate }}
< / md-tooltip >
< md-icon class = "material-icons" > add< / md-icon >
< span translate > action.add< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "opc-timeseries-accordion" class = "vAccordion--default" >
< v-pane id = "opc-timeseries-pane" >
< v-pane-header >
{{ 'extension.opc-timeseries' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-show = "map.timeseries.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item"
ng-repeat="(timeseriesIndex, timeseries) in map.timeseries"
>
< md-button aria-label = "{{ 'action.remove' | translate }}"
class="md-icon-button"
ng-click="removeItem(timeseries, map.timeseries)"
>
< ng-md-icon icon = "close" aria-label = "{{ 'action.remove' | translate }}" > < / ng-md-icon >
< md-tooltip md-direction = "top" >
{{ 'action.remove' | translate }}
< / md-tooltip >
< / md-button >
< md-card >
< md-card-content >
< section flex layout = "row" >
< md-input-container flex = "60" class = "md-block" >
< label translate > extension.key< / label >
< input required
name="opcTimeseriesKey_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}"
ng-model="timeseries.key"
>
< div ng-messages = "theForm['opcTimeseriesKey_' + serverIndex + mapIndex + timeseriesIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "40"
class="md-block tb-container-for-select"
>
< label translate > extension.type< / label >
< md-select required
name="opcTimeseriesType_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}"
ng-model="timeseries.type"
>
< md-option ng-repeat = "(attrType, attrTypeValue) in types.extensionValueType"
ng-value="attrType"
>
{{attrTypeValue | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['opcTimeseriesType_' + serverIndex + mapIndex + timeseriesIndex].$error" >
< div translate
ng-message="required"
>extension.opc-field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "100" class = "md-block" >
< label translate > extension.value< / label >
< input required name = "opcTimeseriesValue_{{serverIndex}}{{mapIndex}}{{timeseriesIndex}}" ng-model = "timeseries.value" >
< div ng-messages = "theForm['opcTimeseriesValue_' + serverIndex + mapIndex + timeseriesIndex].$error" >
< div translate ng-message = "required" > extension.required-value< / div >
< / div >
< / md-input-container >
< / section >
< / md-card-content >
< / md-card >
< / li >
< / ol >
< / div >
< div flex layout = "row" layout-align = "start center" >
< md-button class = "md-primary md-raised"
ng-click="addNewAttribute(map.timeseries)"
aria-label="{{ 'action.add' | translate }}"
>
< md-tooltip md-direction = "top" >
{{ 'extension.add-timeseries' | translate }}
< / md-tooltip >
< md-icon class = "material-icons" > add< / md-icon >
< span translate > action.add< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< / md-card-content >
< / md-card >
< / li >
< / ol >
< / div >
< div flex
layout="row"
layout-align="start center"
>
< md-button class = "md-primary md-raised"
ng-click="addMap(server.mapping)"
aria-label="{{ 'action.add' | translate }}"
>
< md-tooltip md-direction = "top" >
{{ 'extension.add-map' | translate }}
< / md-tooltip >
< md-icon class = "material-icons" > add< / md-icon >
< span translate > action.add< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< / md-card-content >
< / md-card >
< / li >
< / ol >
< div flex
layout="row"
layout-align="start center"
>
< md-button class = "md-primary md-raised"
ng-click="addServer(configuration.servers)"
aria-label="{{ 'action.add' | translate }}"
>
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.opc-add-another-server< / span >
< / md-button >
< / div >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
<!-- {{config}} -->
< / md-card-content >
< / md-card >