@ -15,4 +15,846 @@
limitations under the License.
-->
< div > MQTT< / div >
< md-card class = "extension-form extension-mqtt" >
< md-card-title name = "testValid" >
< 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 = "mqtt-brokers-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-brokers-pane" expanded = "true" >
< v-pane-header >
{{ 'extension.brokers' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "brokers.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(brokerIndex,broker) in brokers" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeBroker(broker)" ng-hide = "brokers.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 >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" >
< label translate > extension.port< / label >
< input required type = "number" min = "1" max = "65535" name = "mqttPort_{{brokerIndex}}" ng-model = "broker.port" >
< div ng-messages = "theForm['mqttPort_' + brokerIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< div translate ng-message = "min" > extension.port-range< / div >
< div translate ng-message = "max" > extension.port-range< / div >
< / div >
< / md-input-container >
< md-input-container flex = "60" class = "md-block" >
< label translate > extension.host< / label >
< input required name = "mqttHost_{{brokerIndex}}" ng-model = "broker.host" >
< div ng-messages = "theForm['mqttHost_' + brokerIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" >
< label translate > extension.retry-interval< / label >
< input required type = "number" name = "mqttRetryInterval_{{brokerIndex}}" ng-model = "broker.retryInterval" >
< div ng-messages = "theForm['mqttRetryInterval_' + brokerIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.credentials< / label >
< md-select required name = "mqttCredentials_{{brokerIndex}}" ng-model = "broker.credentials.type" ng-change = "changeCredentials(broker)" >
< md-option ng-repeat = "(credentialsType, credentialsValue) in types.mqttCredentialTypes" ng-value = "credentialsValue.value" >
{{credentialsValue.name | translate}}
< / md-option >
< / md-select >
< / md-input-container >
< md-input-container flex = "10" class = "md-block" >
< md-checkbox flex aria-label = "{{ 'extension.ssl' | translate }}"
ng-model="broker.ssl">{{ 'extension.ssl' | translate }}
< / md-checkbox >
< / md-input-container >
< / section >
< section flex layout = "row" ng-if = 'broker.credentials.type == "basic"' >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttUsername_' + brokerIndex].$touched && theForm['mqttUsername_' + brokerIndex].$invalid" >
< label translate > extension.username< / label >
< input required name = "mqttUsername_{{brokerIndex}}" ng-model = "broker.credentials.username" >
< div ng-messages = "theForm['mqttUsername_' + brokerIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "60" class = "md-block" md-is-error = "theForm['mqttPassword_' + brokerIndex].$touched && theForm['mqttPassword_' + brokerIndex].$invalid" >
< label translate > extension.password< / label >
< input required name = "mqttPassword_{{brokerIndex}}" ng-model = "broker.credentials.password" >
< div ng-messages = "theForm['mqttPassword_' + brokerIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "column" ng-if = 'broker.credentials.type == "cert.PEM"' class = "dropdown-section" >
< div class = "tb-container" ng-class = "broker.credentials.caCertFileName ? 'ng-valid' : 'ng-invalid'" >
< label class = "tb-label" translate > extension.ca-cert< / label >
< div flow-init = "{singleFile:true}" flow-file-added = 'fileAdded($file, broker, "caCert")' class = "tb-file-select-container" >
< div class = "tb-file-clear-container" >
< md-button ng-click = 'clearFile(broker, "caCert")' 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 = "caCertSelect_{{brokerIndex}}" translate > extension.drop-file< / label >
< input class = "file-input" flow-btn flow-attrs = "{accept:'.pem'}" id = "caCertSelect_{{brokerIndex}}" >
< / div >
< / div >
< / div >
< div class = "dropdown-messages" >
< div ng-if = "!broker.credentials.caCertFileName" class = "tb-error-message" translate > extension.no-file< / div >
< div ng-if = "broker.credentials.caCertFileName" > {{broker.credentials.caCertFileName}}< / div >
< / div >
< div class = "tb-container" ng-class = "broker.credentials.privateKeyFileName ? 'ng-valid' : 'ng-invalid'" >
< label class = "tb-label" translate > extension.private-key< / label >
< div flow-init = "{singleFile:true}" flow-file-added = 'fileAdded($file, broker, "privateKey")' class = "tb-file-select-container" >
< div class = "tb-file-clear-container" >
< md-button ng-click = 'clearFile(broker, "privateKey")' 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 = "privateKeySelect_{{brokerIndex}}" translate > extension.drop-file< / label >
< input class = "file-input" flow-btn flow-attrs = "{accept:'.pem'}" id = "privateKeySelect_{{brokerIndex}}" >
< / div >
< / div >
< / div >
< div class = "dropdown-messages" >
< div ng-if = "!broker.credentials.privateKeyFileName" class = "tb-error-message" translate > extension.no-file< / div >
< div ng-if = "broker.credentials.privateKeyFileName" > {{broker.credentials.privateKeyFileName}}< / div >
< / div >
< div class = "tb-container" ng-class = "broker.credentials.certFileName ? 'ng-valid' : 'ng-invalid'" >
< label class = "tb-label" translate > extension.cert< / label >
< div flow-init = "{singleFile:true}" flow-file-added = 'fileAdded($file, broker, "Cert")' class = "tb-file-select-container" >
< div class = "tb-file-clear-container" >
< md-button ng-click = 'clearFile(broker, "Cert")' 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 = "CertSelect_{{brokerIndex}}" translate > extension.drop-file< / label >
< input class = "file-input" flow-btn flow-attrs = "{accept:'.pem'}" id = "CertSelect_{{brokerIndex}}" >
< / div >
< / div >
< / div >
< div class = "dropdown-messages" >
< div ng-if = "!broker.credentials.certFileName" class = "tb-error-message" translate > extension.no-file< / div >
< div ng-if = "broker.credentials.certFileName" > {{broker.credentials.certFileName}}< / div >
< / div >
< / section >
< v-accordion id = "mqtt-mapping-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-mapping-pane" >
< v-pane-header >
{{ 'extension.mapping' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.mapping.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(mapIndex,map) in broker.mapping" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeMap(map, broker.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 >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttConverterType_' + brokerIndex + mapIndex].$touched && theForm['mqttConverterType_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.converter-type< / label >
< md-select required name = "mqttConverterType_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converterType" ng-change = "changeConverterType(map)" >
< md-option ng-repeat = "(converterType, value) in types.mqttConverterTypes" ng-value = "converterType" >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['mqttConverterType_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "60" class = "md-block" >
< label translate > extension.topic-filter< / label >
< input required name = "mqttTopicFilter_{{brokerIndex}}{{mapIndex}}" ng-model = "map.topicFilter" >
< div ng-messages = "theForm['mqttTopicFilter_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< div ng-if = 'map.converterType =="json"' ng-init = "map.converter.type = 'json'" >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttDeviceNameExpression_' + brokerIndex + mapIndex].$touched && theForm['mqttDeviceNameExpression_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.device-name-expression< / label >
< md-select required name = "mqttDeviceNameExpression_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.nameExp" ng-change = "changeNameExpression(map.converter)" >
< md-option ng-repeat = "(key, value) in deviceNameExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['mqttDeviceNameExpression_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "map.converter.nameExp == 'deviceNameJsonExpression'" flex = "60" class = "md-block" md-is-error = "theForm['mqttJsonNameExp_' + brokerIndex + mapIndex].$touched && theForm['mqttJsonNameExp_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.json-name-expression< / label >
< input required name = "mqttJsonNameExp_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.deviceNameJsonExpression" >
< div ng-messages = "theForm['mqttJsonNameExp_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "map.converter.nameExp == 'deviceNameTopicExpression'" flex = "60" class = "md-block" md-is-error = "theForm['mqttTopicNameExp_' + brokerIndex + mapIndex].$touched && theForm['mqttTopicNameExp_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.topic-name-expression< / label >
< input required name = "mqttTopicNameExp_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.deviceNameTopicExpression" >
< div ng-messages = "theForm['mqttTopicNameExp_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttDeviceTypeExpression_' + brokerIndex + mapIndex].$touched && theForm['mqttDeviceTypeExpression_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.device-type-expression< / label >
< md-select required name = "mqttDeviceTypeExpression_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.typeExp" ng-change = "changeTypeExpression(map.converter)" >
< md-option ng-repeat = "(key, value) in deviceTypeExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['mqttDeviceTypeExpression_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "map.converter.typeExp == 'deviceTypeJsonExpression'" flex = "60" class = "md-block" md-is-error = "theForm['mqttJsonTypeExp_' + brokerIndex + mapIndex].$touched && theForm['mqttJsonTypeExp_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.json-type-expression< / label >
< input required name = "mqttJsonTypeExp_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.deviceTypeJsonExpression" >
< div ng-messages = "theForm['mqttJsonTypeExp_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "map.converter.typeExp == 'deviceTypeTopicExpression'" flex = "60" class = "md-block" md-is-error = "theForm['mqttTopicTypeExp_' + brokerIndex + mapIndex].$touched && theForm['mqttTopicTypeExp_' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.topic-type-expression< / label >
< input required name = "mqttTopicTypeExp_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.deviceTypeTopicExpression" >
< div ng-messages = "theForm['mqttTopicTypeExp_' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" >
< label translate > extension.timeout< / label >
< input type = "number" name = "mqttTimeout_{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.timeout" parse-to-null >
< / md-input-container >
< md-input-container flex = "60" class = "md-block" md-is-error = "theForm['mqttFilterExpression' + brokerIndex + mapIndex].$touched && theForm['mqttFilterExpression' + brokerIndex + mapIndex].$invalid" >
< label translate > extension.filter-expression< / label >
< input required name = "mqttFilterExpression{{brokerIndex}}{{mapIndex}}" ng-model = "map.converter.filterExpression" >
< div ng-messages = "theForm['mqttFilterExpression' + brokerIndex + mapIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< / div >
< div ng-if = 'map.converterType == "custom"' >
< div class = "md-caption" style = "padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate > extension.transformer-json< / div >
< div flex class = "tb-extension-custom-transformer-panel" >
< div flex class = "tb-extension-custom-transformer"
ui-ace="extensionCustomConverterOptions"
ng-model="map.converter"
name="mqttCustomConverter_{{brokerIndex}}{{mapIndex}}"
ng-change='validateCustomConverter(map.converter, "mqttCustomConverter_" + brokerIndex + mapIndex)'
required>
< / div >
< / div >
< div class = "tb-error-messages" ng-messages = "theForm['mqttCustomConverter_' + brokerIndex + mapIndex].$error" role = "alert" >
< div ng-message = "required" class = "tb-error-message" translate > extension.converter-json-required< / div >
< div ng-message = "converterJSON" class = "tb-error-message" translate > extension.converter-json-parse< / div >
< / div >
< / div >
< v-accordion ng-if = 'map.converterType =="json"' id = "mqtt-attributes-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-attributes-pane" >
< v-pane-header >
{{ 'extension.attributes' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "map.converter.attributes.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(attributeIndex, attribute) in map.converter.attributes" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(attribute, map.converter.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" md-is-error = "theForm['mqttAttributeKey_' + brokerIndex + mapIndex + attributeIndex].$touched && theForm['mqttAttributeKey_' + brokerIndex + mapIndex + attributeIndex].$invalid" >
< label translate > extension.key< / label >
< input required name = "mqttAttributeKey_{{brokerIndex}}{{mapIndex}}{{attributeIndex}}" ng-model = "attribute.key" >
< div ng-messages = "theForm['mqttAttributeKey_' + brokerIndex + mapIndex + attributeIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttAttributeType_' + brokerIndex + mapIndex + attributeIndex].$touched && theForm['mqttAttributeType_' + brokerIndex + mapIndex + attributeIndex].$invalid" >
< label translate > extension.type< / label >
< md-select required name = "mqttAttributeType_{{brokerIndex}}{{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['mqttAttributeType_' + brokerIndex + mapIndex + attributeIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< md-input-container class = "md-block" md-is-error = "theForm['mqttAttributeValue_' + brokerIndex + mapIndex + attributeIndex].$touched && theForm['mqttAttributeValue_' + brokerIndex + mapIndex + attributeIndex].$invalid" >
< label translate > extension.value< / label >
< input required name = "mqttAttributeValue_{{brokerIndex}}{{mapIndex}}{{attributeIndex}}" ng-model = "attribute.value" >
< div ng-messages = "theForm['mqttAttributeValue_' + brokerIndex + mapIndex + attributeIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / 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="addAttribute(map.converter.attributes)" aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-attribute< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion ng-if = 'map.converterType =="json"' id = "mqtt-timeseries-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-timeseries-pane" >
< v-pane-header >
{{ 'extension.timeseries' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "map.converter.timeseries.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(timeseriesIndex, timeseries) in map.converter.timeseries" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(timeseries, map.converter.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" md-is-error = "theForm['mqttTimeseriesKey_' + brokerIndex + mapIndex + timeseriesIndex].$touched && theForm['mqttTimeseriesKey_' + brokerIndex + mapIndex + timeseriesIndex].$invalid" >
< label translate > extension.key< / label >
< input required name = "mqttTimeseriesKey_{{brokerIndex}}{{mapIndex}}{{timeseriesIndex}}" ng-model = "timeseries.key" >
< div ng-messages = "theForm['mqttTimeseriesKey_' + brokerIndex + mapIndex + timeseriesIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['mqttTimeseriesType_' + brokerIndex + mapIndex + timeseriesIndex].$touched && theForm['mqttTimeseriesType_' + brokerIndex + mapIndex + timeseriesIndex].$invalid" >
< label translate > extension.type< / label >
< md-select required name = "mqttTimeseriesType_{{brokerIndex}}{{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['mqttTimeseriesType_' + brokerIndex + mapIndex + timeseriesIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< md-input-container class = "md-block" md-is-error = "theForm['mqttTimeseriesValue_' + brokerIndex + mapIndex + timeseriesIndex].$touched && theForm['mqttTimeseriesValue_' + brokerIndex + mapIndex + timeseriesIndex].$invalid" >
< label translate > extension.value< / label >
< input required name = "mqttTimeseriesValue_{{brokerIndex}}{{mapIndex}}{{timeseriesIndex}}" ng-model = "timeseries.value" >
< div ng-messages = "theForm['mqttTimeseriesValue_' + brokerIndex + mapIndex + timeseriesIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / 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="addAttribute(map.converter.timeseries)" aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-timeseries< / 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(broker.mapping)" aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-map< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "mqtt-connect-requests-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-connect-requests-pane" >
< v-pane-header >
{{ 'extension.connect-requests' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.connectRequests.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(connectRequestIndex, connectRequest) in broker.connectRequests" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(connectRequest, broker.connectRequests)" >
< 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 >
< md-input-container class = "md-block" >
< label translate > extension.topic-filter< / label >
< input required name = "conRequestTopicFilter_{{brokerIndex}}{{connectRequestIndex}}" ng-model = "connectRequest.topicFilter" >
< div ng-messages = "theForm['conRequestTopicFilter_' + brokerIndex + connectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['connectDeviceNameExpression_' + brokerIndex + connectRequestIndex].$touched && theForm['connectDeviceNameExpression_' + brokerIndex + connectRequestIndex].$invalid" >
< label translate > extension.device-name-expression< / label >
< md-select required name = "connectDeviceNameExpression_{{brokerIndex}}{{connectRequestIndex}}" ng-model = "connectRequest.nameExp" ng-change = "changeNameExpression(connectRequest, 'connect')" >
< md-option ng-repeat = "(key, value) in deviceNameExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['connectDeviceNameExpression_' + brokerIndex + connectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "connectRequest.nameExp == 'deviceNameJsonExpression'" flex = "60" class = "md-block" >
< label translate > extension.json-name-expression< / label >
< input required name = "connectJsonNameExp_{{brokerIndex}}{{connectRequestIndex}}" ng-model = "connectRequest.deviceNameJsonExpression" >
< div ng-messages = "theForm['connectJsonNameExp_' + brokerIndex + connectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "connectRequest.nameExp == 'deviceNameTopicExpression'" flex = "60" class = "md-block" >
< label translate > extension.topic-name-expression< / label >
< input required name = "connectTopicNameExp_{{brokerIndex}}{{connectRequestIndex}}" ng-model = "connectRequest.deviceNameTopicExpression" >
< div ng-messages = "theForm['connectTopicNameExp_' + brokerIndex + connectRequestIndex].$error" >
< div translate ng-message = "required" > extension.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='addConnectRequest(broker.connectRequests, "connect")' aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-connect-request< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "mqtt-disconnect-requests-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-disconnect-requests-pane" >
< v-pane-header >
{{ 'extension.disconnect-requests' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.disconnectRequests.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(disconnectRequestIndex, disconnectRequest) in broker.disconnectRequests" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(disconnectRequest, broker.disconnectRequests)" >
< 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 >
< md-input-container class = "md-block" >
< label translate > extension.topic-filter< / label >
< input required name = "disconRequestTopicFilter_{{brokerIndex}}{{disconnectRequestIndex}}" ng-model = "disconnectRequest.topicFilter" >
< div ng-messages = "theForm['disconRequestTopicFilter_' + brokerIndex + disconnectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['disconnectDeviceNameExpression_' + brokerIndex + disconnectRequestIndex].$touched && theForm['disconnectDeviceNameExpression_' + brokerIndex + disconnectRequestIndex].$invalid" >
< label translate > extension.device-name-expression< / label >
< md-select required name = "disconnectDeviceNameExpression_{{brokerIndex}}{{disconnectRequestIndex}}" ng-model = "disconnectRequest.nameExp" ng-change = "changeNameExpression(disconnectRequest, 'disconnect')" >
< md-option ng-repeat = "(key, value) in deviceNameExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['disconnectDeviceNameExpression_' + brokerIndex + disconnectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "disconnectRequest.nameExp == 'deviceNameJsonExpression'" flex = "60" class = "md-block" >
< label translate > extension.json-name-expression< / label >
< input required name = "disconnectJsonNameExp_{{brokerIndex}}{{disconnectRequestIndex}}" ng-model = "disconnectRequest.deviceNameJsonExpression" >
< div ng-messages = "theForm['disconnectJsonNameExp_' + brokerIndex + disconnectRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "disconnectRequest.nameExp == 'deviceNameTopicExpression'" flex = "60" class = "md-block" >
< label translate > extension.topic-name-expression< / label >
< input required name = "disconnectTopicNameExp_{{brokerIndex}}{{disconnectRequestIndex}}" ng-model = "disconnectRequest.deviceNameTopicExpression" >
< div ng-messages = "theForm['disconnectTopicNameExp_' + brokerIndex + disconnectRequestIndex].$error" >
< div translate ng-message = "required" > extension.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='addConnectRequest(broker.disconnectRequests, "disconnect")' aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-disconnect-request< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "mqtt-attribute-requests-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-attribute-requests-pane" >
< v-pane-header >
{{ 'extension.attribute-requests' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.attributeRequests.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(attributeRequestIndex, attributeRequest) in broker.attributeRequests" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(attributeRequest, broker.attributeRequests)" >
< 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 = "80" class = "md-block" >
< label translate > extension.topic-filter< / label >
< input required name = "attributeRequestTopicFilter_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.topicFilter" >
< div ng-messages = "theForm['attributeRequestTopicFilter_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "20" class = "md-block" >
< md-checkbox flex aria-label = "{{ 'extension.client-scope' | translate }}"
ng-model="attributeRequest.clientScope">{{ 'extension.client-scope' | translate }}
< / md-checkbox >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['attrRequestDeviceNameExpression_' + brokerIndex + attributeRequestIndex].$touched && theForm['attrRequestDeviceNameExpression_' + brokerIndex + attributeRequestIndex].$invalid" >
< label translate > extension.device-name-expression< / label >
< md-select required name = "attrRequestDeviceNameExpression_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.nameExp" ng-change = "changeNameExpression(attributeRequest, 'attribute')" >
< md-option ng-repeat = "(key, value) in deviceNameExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['attrRequestDeviceNameExpression_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.nameExp == 'deviceNameJsonExpression'" flex = "60" class = "md-block" >
< label translate > extension.json-name-expression< / label >
< input required name = "attrRequestJsonNameExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.deviceNameJsonExpression" >
< div ng-messages = "theForm['attrRequestJsonNameExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.nameExp == 'deviceNameTopicExpression'" flex = "60" class = "md-block" >
< label translate > extension.topic-name-expression< / label >
< input required name = "attrRequestTopicNameExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.deviceNameTopicExpression" >
< div ng-messages = "theForm['attrRequestTopicNameExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['attrRequestAttributeKeyExpression_' + brokerIndex + attributeRequestIndex].$touched && theForm['attrRequestAttributeKeyExpression_' + brokerIndex + attributeRequestIndex].$invalid" >
< label translate > extension.attribute-key-expression< / label >
< md-select required name = "attrRequestAttributeKeyExpression_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.attrKey" ng-change = "changeAttrKeyExpression(attributeRequest)" >
< md-option ng-repeat = "(key, value) in attributeKeyExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['attrRequestAttributeKeyExpression_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.attrKey == 'attributeKeyJsonExpression'" flex = "60" class = "md-block" >
< label translate > extension.attr-json-key-expression< / label >
< input required name = "attrRequestJsonKeyExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.attributeKeyJsonExpression" >
< div ng-messages = "theForm['attrRequestJsonKeyExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.attrKey == 'attributeKeyTopicExpression'" flex = "60" class = "md-block" >
< label translate > extension.attr-topic-key-expression< / label >
< input required name = "attrRequestTopicKeyExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.attributeKeyTopicExpression" >
< div ng-messages = "theForm['attrRequestTopicKeyExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< section flex layout = "row" >
< md-input-container flex = "40" class = "md-block" md-is-error = "theForm['attrRequestIdExpression_' + brokerIndex + attributeRequestIndex].$touched && theForm['attrRequestIdExpression_' + brokerIndex + attributeRequestIndex].$invalid" >
< label translate > extension.request-id-expression< / label >
< md-select required name = "attrRequestIdExpression_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.requestId" ng-change = "changeRequestIdExpression(attributeRequest)" >
< md-option ng-repeat = "(key, value) in requestIdExpressions" ng-value = 'key' >
{{value | translate}}
< / md-option >
< / md-select >
< div ng-messages = "theForm['attrRequestIdExpression_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.requestId == 'requestIdJsonExpression'" flex = "60" class = "md-block" >
< label translate > extension.request-id-json-expression< / label >
< input required name = "attrRequestJsonIdExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.requestIdJsonExpression" >
< div ng-messages = "theForm['attrRequestJsonIdExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container ng-if = "attributeRequest.requestId == 'requestIdTopicExpression'" flex = "60" class = "md-block" >
< label translate > extension.request-id-topic-expression< / label >
< input required name = "attrRequestTopicIdExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.requestIdTopicExpression" >
< div ng-messages = "theForm['attrRequestTopicIdExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< md-input-container class = "md-block" >
< label translate > extension.response-topic-expression< / label >
< input required name = "attributeRequestResponseTopicExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.responseTopicExpression" >
< div ng-messages = "theForm['attributeRequestResponseTopicExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container class = "md-block" >
< label translate > extension.value-expression< / label >
< input required name = "attributeRequestValueExp_{{brokerIndex}}{{attributeRequestIndex}}" ng-model = "attributeRequest.valueExpression" >
< div ng-messages = "theForm['attributeRequestValueExp_' + brokerIndex + attributeRequestIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / 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="addAttributeRequest(broker.attributeRequests)" aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-attribute-request< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "mqtt-attribute-updates-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-attribute-updates-pane" >
< v-pane-header >
{{ 'extension.attribute-updates' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.attributeUpdates.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(attributeUpdateIndex, attributeUpdate) in broker.attributeUpdates" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(attributeUpdate, broker.attributeUpdates)" >
< 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 = "50" class = "md-block" >
< label translate > extension.device-name-filter< / label >
< input required name = "attributeUpdateDeviceNameFilter_{{brokerIndex}}{{attributeUpdateIndex}}" ng-model = "attributeUpdate.deviceNameFilter" >
< div ng-messages = "theForm['attributeUpdateDeviceNameFilter_' + brokerIndex + attributeUpdateIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.attribute-filter< / label >
< input required name = "attributeUpdateAttributeFilter_{{brokerIndex}}{{attributeUpdateIndex}}" ng-model = "attributeUpdate.attributeFilter" >
< div ng-messages = "theForm['attributeUpdateAttributeFilter_' + brokerIndex + attributeUpdateIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< md-input-container class = "md-block" >
< label translate > extension.topic-expression< / label >
< input required name = "attributeUpdateTopicExp_{{brokerIndex}}{{attributeUpdateIndex}}" ng-model = "attributeUpdate.topicExpression" >
< div ng-messages = "theForm['attributeUpdateTopicExp_' + brokerIndex + attributeUpdateIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container class = "md-block" >
< label translate > extension.value-expression< / label >
< input required name = "attributeUpdateValueExp_{{brokerIndex}}{{attributeUpdateIndex}}" ng-model = "attributeUpdate.valueExpression" >
< div ng-messages = "theForm['attributeUpdateValueExp_' + brokerIndex + attributeUpdateIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / 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='addAttributeUpdate(broker.attributeUpdates)' aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-attribute-update< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
< v-accordion id = "mqtt-server-side-rpc-accordion" class = "vAccordion--default" >
< v-pane id = "mqtt-server-side-rpc-pane" >
< v-pane-header >
{{ 'extension.server-side-rpc' | translate }}
< / v-pane-header >
< v-pane-content >
< div ng-if = "broker.serverSideRpc.length > 0" >
< ol class = "list-group" >
< li class = "list-group-item" ng-repeat = "(rpcIndex, rpc) in broker.serverSideRpc" >
< md-button aria-label = "{{ 'action.remove' | translate }}" class = "md-icon-button" ng-click = "removeAttribute(rpc, broker.serverSideRpc)" >
< 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 = "50" class = "md-block" >
< label translate > extension.device-name-filter< / label >
< input required name = "serverSideRpcDeviceNameFilter_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.deviceNameFilter" >
< div ng-messages = "theForm['serverSideRpcDeviceNameFilter_' + brokerIndex + rpcIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.method-filter< / label >
< input required name = "serverSideRpcMethodFilter_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.methodFilter" >
< div ng-messages = "theForm['serverSideRpcMethodFilter_' + brokerIndex + rpcIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< / section >
< md-input-container class = "md-block" >
< label translate > extension.request-topic-expression< / label >
< input required name = "serverSideRpcRequestTopicExp_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.requestTopicExpression" >
< div ng-messages = "theForm['serverSideRpcRequestTopicExp_' + brokerIndex + rpcIndex].$error" >
< div translate ng-message = "required" > extension.field-required< / div >
< / div >
< / md-input-container >
< md-input-container class = "md-block" >
< label translate > extension.response-topic-expression< / label >
< input name = "serverSideRpcResponseTopicExp_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.responseTopicExpression" parse-to-null >
< / md-input-container >
< section flex layout = "row" >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.response-timeout< / label >
< input type = "number" name = "serverSideRpcResponseTimeout_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.responseTimeout" parse-to-null >
< / md-input-container >
< md-input-container flex = "50" class = "md-block" >
< label translate > extension.value-expression< / label >
< input required name = "serverSideRpcValueExp_{{brokerIndex}}{{rpcIndex}}" ng-model = "rpc.valueExpression" >
< div ng-messages = "theForm['serverSideRpcValueExp_' + brokerIndex + rpcIndex].$error" >
< div translate ng-message = "required" > extension.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='addServerSideRpc(broker.serverSideRpc)' aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-server-side-rpc-request< / 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="addBroker()" aria-label="{{ 'action.add' | translate }}">
< md-icon class = "material-icons" > add< / md-icon >
< span translate > extension.add-broker< / span >
< / md-button >
< / div >
< / v-pane-content >
< / v-pane >
< / v-accordion >
<!-- <pre>
{{config | json}}
< / pre > -->
< / md-card-content >
< / md-card >