You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2017/03/02 09:05:43 UTC

[08/15] ignite git commit: IGNITE-4659 Migration to Webpack 2. Upgrade template engine from jade to pug.

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug
new file mode 100644
index 0000000..e0c2357
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug
@@ -0,0 +1,73 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var model = 'backupItem'
+-var form = 'failoverSpi'
+-var failoverSpi = model + '.failoverSpi'
+-var failoverCustom = 'model.kind === "Custom"'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
+        ignite-form-panel-chevron
+        label Failover configuration
+        ignite-form-field-tooltip.tipLabel
+            | Failover SPI provides ability to supply custom logic for handling failed execution of a grid job#[br]
+            | #[a(href="https://apacheignite.readme.io/docs/fault-tolerance" target="_blank") More info]
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .panel-body(ng-if=`ui.isPanelLoaded('${form}')`)
+            .col-sm-6
+                .settings-row(ng-init='failoverSpiTbl={type: "failoverSpi", model: "failoverSpi", focusId: "kind", ui: "failover-table"}')
+                    +ignite-form-group()
+                        ignite-form-field-label
+                            | Failover SPI configurations
+                        ignite-form-group-tooltip
+                            | Failover SPI configurations
+                        ignite-form-group-add(ng-click='tableNewItem(failoverSpiTbl)')
+                            | Add failover SPI
+                        .group-content-empty(ng-if=`!(${failoverSpi} && ${failoverSpi}.length > 0)`)
+                            | Not defined
+                        .group-content(ng-show=`${failoverSpi} && ${failoverSpi}.length > 0` ng-repeat=`model in ${failoverSpi} track by $index`)
+                            hr(ng-if='$index != 0')
+                            .settings-row
+                                +dropdown-required-autofocus('Failover SPI:', 'model.kind', '"failoverKind" + $index', 'true', 'true', 'Choose Failover SPI', '[\
+                                        {value: "JobStealing", label: "Job stealing"},\
+                                        {value: "Never", label: "Never"},\
+                                        {value: "Always", label: "Always"},\
+                                        {value: "Custom", label: "Custom"}\
+                                    ]', 'Provides ability to supply custom logic for handling failed execution of a grid job\
+                                    <ul>\
+                                        <li>Job stealing - Supports job stealing from over-utilized nodes to under-utilized nodes</li>\
+                                        <li>Never - Jobs are ordered as they arrived</li>\
+                                        <li>Always - Jobs are first ordered by their priority</li>\
+                                        <li>Custom - Jobs are activated immediately on arrival to mapped node</li>\
+                                        <li>Default - Default FailoverSpi implementation</li>\
+                                    </ul>')
+
+                                    +table-remove-button(failoverSpi, 'Remove Failover SPI')
+                            .settings-row(ng-show='model.kind === "JobStealing"')
+                                +number('Maximum failover attempts:', 'model.JobStealing.maximumFailoverAttempts', '"jsMaximumFailoverAttempts" + $index', 'true', '5', '0',
+                                    'Maximum number of attempts to execute a failed job on another node')
+                            .settings-row(ng-show='model.kind === "Always"')
+                                +number('Maximum failover attempts:', 'model.Always.maximumFailoverAttempts', '"alwaysMaximumFailoverAttempts" + $index', 'true', '5', '0',
+                                    'Maximum number of attempts to execute a failed job on another node')
+                            .settings-row(ng-show=failoverCustom)
+                                +java-class('SPI implementation', 'model.Custom.class', '"failoverSpiClass" + $index', 'true', failoverCustom,
+                                    'Custom FailoverSpi implementation class name.', failoverCustom)
+            .col-sm-6
+                +preview-xml-java(model, 'clusterFailover')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
deleted file mode 100644
index b2ce71f..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
+++ /dev/null
@@ -1,76 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var form = 'general'
--var model = 'backupItem'
--var modelDiscoveryKind = model + '.discovery.kind'
-
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label General
-        ignite-form-field-tooltip.tipLabel
-            | Common cluster configuration#[br]
-            | #[a(href="https://apacheignite.readme.io/docs/clustering" target="_blank") More info]
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body
-            .col-sm-6
-                .settings-row
-                    +text('Name:', model + '.name', '"clusterName"', 'true', 'Input name', 'Grid name allows to indicate to what grid this particular grid instance belongs to')
-                .settings-row
-                    +caches(model, 'Select caches to start in cluster or add a new cache')
-                .settings-row
-                    +text-ip-address('Local host:', model + '.localHost', '"localHost"', 'true', '0.0.0.0',
-                        'System-wide local address or host for all Ignite components to bind to<br/>\
-                        If not defined then Ignite tries to use local wildcard address<br/>\
-                        That means that all services will be available on all network interfaces of the host machine')
-                .settings-row
-                    +dropdown('Discovery:', model + '.discovery.kind', '"discovery"', 'true', 'Choose discovery', 'discoveries',
-                        'Discovery allows to discover remote nodes in grid\
-                        <ul>\
-                            <li>Static IPs - IP Finder which works only with pre configured list of IP addresses specified</li>\
-                            <li>Multicast - Multicast based IP finder</li>\
-                            <li>AWS S3 - AWS S3 based IP finder that automatically discover cluster nodes on Amazon EC2 cloud</li>\
-                            <li>Apache jclouds - Apache jclouds multi cloud toolkit based IP finder for cloud platforms with unstable IP addresses</li>\
-                            <li>Google cloud storage - Google Cloud Storage based IP finder that automatically discover cluster nodes on Google Compute Engine cluster</li>\
-                            <li>JDBC - JDBC based IP finder that use database to store node IP addres</li>\
-                            <li>Shared filesystem - Shared filesystem based IP finder that use file to store node IP address</li>\
-                            <li>Apache ZooKeeper - Apache ZooKeeper based IP finder when you use ZooKeeper to coordinate your distributed environment</li>\
-                        </ul>')
-                .settings-row
-                    .panel-details
-                        div(ng-if='#{modelDiscoveryKind} === "Cloud"')
-                            include ./general/discovery/cloud.jade
-                        div(ng-if='#{modelDiscoveryKind} === "GoogleStorage"')
-                            include ./general/discovery/google.jade
-                        div(ng-if='#{modelDiscoveryKind} === "Jdbc"')
-                            include ./general/discovery/jdbc.jade
-                        div(ng-if='#{modelDiscoveryKind} === "Multicast"')
-                            include ./general/discovery/multicast.jade
-                        div(ng-if='#{modelDiscoveryKind} === "S3"')
-                            include ./general/discovery/s3.jade
-                        div(ng-if='#{modelDiscoveryKind} === "SharedFs"')
-                            include ./general/discovery/shared.jade
-                        div(ng-if='#{modelDiscoveryKind} === "Vm"')
-                            include ./general/discovery/vm.jade
-                        div(ng-if='#{modelDiscoveryKind} === "ZooKeeper"')
-                            include ./general/discovery/zookeeper.jade
-            .col-sm-6
-                -var model = 'backupItem'
-                +preview-xml-java(model, 'clusterCaches', 'caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug
new file mode 100644
index 0000000..be56a6c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug
@@ -0,0 +1,76 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var form = 'general'
+-var model = 'backupItem'
+-var modelDiscoveryKind = model + '.discovery.kind'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label General
+        ignite-form-field-tooltip.tipLabel
+            | Common cluster configuration#[br]
+            | #[a(href="https://apacheignite.readme.io/docs/clustering" target="_blank") More info]
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .panel-body
+            .col-sm-6
+                .settings-row
+                    +text('Name:', `${model}.name`, '"clusterName"', 'true', 'Input name', 'Grid name allows to indicate to what grid this particular grid instance belongs to')
+                .settings-row
+                    +caches(model, 'Select caches to start in cluster or add a new cache')
+                .settings-row
+                    +text-ip-address('Local host:', `${model}.localHost`, '"localHost"', 'true', '0.0.0.0',
+                        'System-wide local address or host for all Ignite components to bind to<br/>\
+                        If not defined then Ignite tries to use local wildcard address<br/>\
+                        That means that all services will be available on all network interfaces of the host machine')
+                .settings-row
+                    +dropdown('Discovery:', `${model}.discovery.kind`, '"discovery"', 'true', 'Choose discovery', 'discoveries',
+                        'Discovery allows to discover remote nodes in grid\
+                        <ul>\
+                            <li>Static IPs - IP Finder which works only with pre configured list of IP addresses specified</li>\
+                            <li>Multicast - Multicast based IP finder</li>\
+                            <li>AWS S3 - AWS S3 based IP finder that automatically discover cluster nodes on Amazon EC2 cloud</li>\
+                            <li>Apache jclouds - Apache jclouds multi cloud toolkit based IP finder for cloud platforms with unstable IP addresses</li>\
+                            <li>Google cloud storage - Google Cloud Storage based IP finder that automatically discover cluster nodes on Google Compute Engine cluster</li>\
+                            <li>JDBC - JDBC based IP finder that use database to store node IP addres</li>\
+                            <li>Shared filesystem - Shared filesystem based IP finder that use file to store node IP address</li>\
+                            <li>Apache ZooKeeper - Apache ZooKeeper based IP finder when you use ZooKeeper to coordinate your distributed environment</li>\
+                        </ul>')
+                .settings-row
+                    .panel-details
+                        div(ng-if=`${modelDiscoveryKind} === 'Cloud'`)
+                            include ./general/discovery/cloud
+                        div(ng-if=`${modelDiscoveryKind} === 'GoogleStorage'`)
+                            include ./general/discovery/google
+                        div(ng-if=`${modelDiscoveryKind} === 'Jdbc'`)
+                            include ./general/discovery/jdbc
+                        div(ng-if=`${modelDiscoveryKind} === 'Multicast'`)
+                            include ./general/discovery/multicast
+                        div(ng-if=`${modelDiscoveryKind} === 'S3'`)
+                            include ./general/discovery/s3
+                        div(ng-if=`${modelDiscoveryKind} === 'SharedFs'`)
+                            include ./general/discovery/shared
+                        div(ng-if=`${modelDiscoveryKind} === 'Vm'`)
+                            include ./general/discovery/vm
+                        div(ng-if=`${modelDiscoveryKind} === 'ZooKeeper'`)
+                            include ./general/discovery/zookeeper
+            .col-sm-6
+                -var model = 'backupItem'
+                +preview-xml-java(model, 'clusterCaches', 'caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
deleted file mode 100644
index 52fb21b..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
+++ /dev/null
@@ -1,134 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var discoveryKind = 'Cloud'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.Cloud'
--var regions = model + '.regions'
--var zones = model + '.zones'
--var formRegions = 'discoveryCloudRegions'
--var formZones = 'discoveryCloudZones'
-
-div
-    .details-row
-        +text('Credential:', model + '.credential', '"credential"', 'false', 'Input cloud credential',
-            'Credential that is used during authentication on the cloud<br/>\
-            Depending on a cloud platform it can be a password or access key')
-    .details-row
-        +text('Path to credential:', model + '.credentialPath', '"credentialPath"', 'false', 'Input pathto credential',
-            'Path to a credential that is used during authentication on the cloud<br/>\
-            Access key or private key should be stored in a plain or PEM file without a passphrase')
-    .details-row
-        +text('Identity:', model + '.identity', '"' + discoveryKind + 'Identity"', required, 'Input identity',
-            'Identity that is used as a user name during a connection to the cloud<br/>\
-            Depending on a cloud platform it can be an email address, user name, etc')
-    .details-row
-        +text('Provider:', model + '.provider', '"' + discoveryKind + 'Provider"', required, 'Input provider', 'Cloud provider to use')
-    .details-row
-        -var form = formRegions;
-        +ignite-form-group(ng-model=regions ng-form=form)
-            -var uniqueTip = 'Such region already exists!'
-
-            ignite-form-field-label
-                | Regions
-            ignite-form-group-tooltip
-                | List of regions where VMs are located#[br]
-                | If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation#[br]
-                | Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers regions are redundant
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new region
-
-            .group-content(ng-if='#{regions}.length')
-                -var model = 'field.model';
-                -var name = '"edit" + $index'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = regions + '[$index] = ' + model
-
-                div(ng-repeat='model in #{regions} track by $index')
-                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
-                        .indexField
-                            | {{ $index+1 }})
-                        +table-remove-button(regions, 'Remove region')
-                        span(ng-hide='field.edit')
-                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
-                        span(ng-if='field.edit')
-                            +table-text-field(name, model, regions, valid, save, 'Region name', false)
-                                +table-save-button(valid, save, false)
-                                +unique-feedback(name, uniqueTip)
-
-            .group-content(ng-repeat='field in group.add')
-                -var model = 'field.new';
-                -var name = '"new"'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = regions + '.push(' + model + ')'
-
-                div
-                    label.col-xs-12.col-sm-12.col-md-12
-                        +table-text-field(name, model, regions, valid, save, 'Region name', true)
-                            +table-save-button(valid, save, false)
-                            +unique-feedback(name, uniqueTip)
-
-            .group-content-empty(ng-if='!(#{regions}.length) && !group.add.length')
-                | Not defined
-    .details-row
-        -var form = formZones;
-        +ignite-form-group(ng-model=zones ng-form=form)
-            -var uniqueTip = 'Such zone already exists!'
-
-            ignite-form-field-label
-                | Zones
-            ignite-form-group-tooltip
-                | List of zones where VMs are located#[br]
-                | If the zones are not set then every zone from specified regions, will be taken into account#[br]
-                | Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers zones are redundant
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new zone
-
-            -var form = formZones;
-            .group-content(ng-if='#{zones}.length')
-                -var model = 'field.model';
-                -var name = '"edit" + $index'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = zones + '[$index] = ' + model
-
-                div(ng-repeat='model in #{zones} track by $index')
-                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
-                        .indexField
-                            | {{ $index+1 }})
-                        +table-remove-button(zones, 'Remove zone')
-                        span(ng-hide='field.edit')
-                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
-                        span(ng-if='field.edit')
-                            +table-text-field(name, model, zones, valid, save, 'Zone name', false)
-                                +table-save-button(valid, save, false)
-                                +unique-feedback(name, uniqueTip)
-
-            .group-content(ng-repeat='field in group.add')
-                -var model = 'field.new';
-                -var name = '"new"'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = zones + '.push(' + model + ')'
-
-                div
-                    label.col-xs-12.col-sm-12.col-md-12
-                        +table-text-field(name, model, zones, valid, save, 'Zone name', true)
-                            +table-save-button(valid, save, true)
-                            +unique-feedback(name, uniqueTip)
-
-            .group-content-empty(ng-if='!(#{zones}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.pug
new file mode 100644
index 0000000..b127a4c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.pug
@@ -0,0 +1,134 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var discoveryKind = 'Cloud'
+-var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
+-var model = 'backupItem.discovery.Cloud'
+-var regions = `${model}.regions`
+-var zones = `${model}.zones`
+-var formRegions = 'discoveryCloudRegions'
+-var formZones = 'discoveryCloudZones'
+
+div
+    .details-row
+        +text('Credential:', `${model}.credential`, '"credential"', 'false', 'Input cloud credential',
+            'Credential that is used during authentication on the cloud<br/>\
+            Depending on a cloud platform it can be a password or access key')
+    .details-row
+        +text('Path to credential:', `${model}.credentialPath`, '"credentialPath"', 'false', 'Input pathto credential',
+            'Path to a credential that is used during authentication on the cloud<br/>\
+            Access key or private key should be stored in a plain or PEM file without a passphrase')
+    .details-row
+        +text('Identity:', `${model}.identity`, '"' + discoveryKind + 'Identity"', required, 'Input identity',
+            'Identity that is used as a user name during a connection to the cloud<br/>\
+            Depending on a cloud platform it can be an email address, user name, etc')
+    .details-row
+        +text('Provider:', `${model}.provider`, '"' + discoveryKind + 'Provider"', required, 'Input provider', 'Cloud provider to use')
+    .details-row
+        -var form = formRegions;
+        +ignite-form-group(ng-model=`${regions}` ng-form=form)
+            -var uniqueTip = 'Such region already exists!'
+
+            ignite-form-field-label
+                | Regions
+            ignite-form-group-tooltip
+                | List of regions where VMs are located#[br]
+                | If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation#[br]
+                | Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers regions are redundant
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new region
+
+            .group-content(ng-if=`${regions}.length`)
+                -var model = 'field.model';
+                -var name = '"edit" + $index'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${regions}[$index] = ${model}`
+
+                div(ng-repeat=`model in ${regions} track by $index`)
+                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(regions, 'Remove region')
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click=`field.edit = true; ${model} = model;`) {{ model }}
+                        span(ng-if='field.edit')
+                            +table-text-field(name, model, regions, valid, save, 'Region name', false)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'field.new';
+                -var name = '"new"'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${regions}.push(${model})`
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-text-field(name, model, regions, valid, save, 'Region name', true)
+                            +table-save-button(valid, save, false)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if=`!(${regions}.length) && !group.add.length`)
+                | Not defined
+    .details-row
+        -var form = formZones;
+        +ignite-form-group(ng-model=zones ng-form=form)
+            -var uniqueTip = 'Such zone already exists!'
+
+            ignite-form-field-label
+                | Zones
+            ignite-form-group-tooltip
+                | List of zones where VMs are located#[br]
+                | If the zones are not set then every zone from specified regions, will be taken into account#[br]
+                | Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers zones are redundant
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new zone
+
+            -var form = formZones;
+            .group-content(ng-if=`${zones}.length`)
+                -var model = 'field.model';
+                -var name = '"edit" + $index'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${zones}[$index] = ${model}`
+
+                div(ng-repeat=`model in ${zones} track by $index`)
+                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(zones, 'Remove zone')
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click=`field.edit = true; ${model} = model;`) {{ model }}
+                        span(ng-if='field.edit')
+                            +table-text-field(name, model, zones, valid, save, 'Zone name', false)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'field.new';
+                -var name = '"new"'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${zones}.push(${model})`
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-text-field(name, model, zones, valid, save, 'Zone name', true)
+                            +table-save-button(valid, save, true)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if=`!(${zones}.length) && !group.add.length`)
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
deleted file mode 100644
index c12bd04..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
+++ /dev/null
@@ -1,38 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
-
--var discoveryKind = 'GoogleStorage'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.GoogleStorage'
-
-div
-    .details-row
-        +text('Project name:', model + '.projectName', '"' + discoveryKind + 'ProjectName"', required, 'Input project name', '' +
-            'Google Cloud Platforms project name<br/>\
-            Usually this is an auto generated project number(ex. 208709979073) that can be found in "Overview" section of Google Developer Console')
-    .details-row
-        +text('Bucket name:', model + '.bucketName', '"' + discoveryKind + 'BucketName"', required, 'Input bucket name',
-            'Google Cloud Storage bucket name<br/>\
-            If the bucket does not exist Ignite will automatically create it<br/>\
-            However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation')
-    .details-row
-        +text('Private key path:', model + '.serviceAccountP12FilePath', '"' + discoveryKind + 'ServiceAccountP12FilePath"', required, 'Input private key path',
-            'Full path to the private key in PKCS12 format of the Service Account')
-    .details-row
-        +text('Account id:', model + '.serviceAccountId', '"' + discoveryKind + 'ServiceAccountId"', required, 'Input account id', 'Service account ID (typically an e-mail address)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.pug
new file mode 100644
index 0000000..929350e
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.pug
@@ -0,0 +1,38 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+
+-var discoveryKind = 'GoogleStorage'
+-var required = `backupItem.discovery.kind == '${discoveryKind}'`
+-var model = 'backupItem.discovery.GoogleStorage'
+
+div
+    .details-row
+        +text('Project name:', `${model}.projectName`, `'${discoveryKind}ProjectName'`, required, 'Input project name', '' +
+            'Google Cloud Platforms project name<br/>\
+            Usually this is an auto generated project number(ex. 208709979073) that can be found in "Overview" section of Google Developer Console')
+    .details-row
+        +text('Bucket name:', `${model}.bucketName`, `'${discoveryKind}BucketName'`, required, 'Input bucket name',
+            'Google Cloud Storage bucket name<br/>\
+            If the bucket does not exist Ignite will automatically create it<br/>\
+            However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation')
+    .details-row
+        +text('Private key path:', `${model}.serviceAccountP12FilePath`, `'${discoveryKind}ServiceAccountP12FilePath'`, required, 'Input private key path',
+            'Full path to the private key in PKCS12 format of the Service Account')
+    .details-row
+        +text('Account id:', `${model}.serviceAccountId`, `'${discoveryKind}ServiceAccountId'`, required, 'Input account id', 'Service account ID (typically an e-mail address)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
deleted file mode 100644
index 4e4246d..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
+++ /dev/null
@@ -1,31 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.Jdbc'
--var required = 'backupItem.discovery.kind === "Jdbc"'
-
-div
-    .details-row
-        +checkbox('DB schema should be initialized by Ignite', model + '.initSchema', '"initSchema"',
-            'Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user')
-    .details-row
-        +text('Data source bean name:', model + '.dataSourceBean',
-            '"dataSourceBean"', required, 'Input bean name', 'Name of the data source bean in Spring context')
-    .details-row
-        +dialect('Dialect:', model + '.dialect', '"dialect"', required,
-            'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect', 'Choose JDBC dialect')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.pug
new file mode 100644
index 0000000..4e9a430
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.pug
@@ -0,0 +1,31 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var model = 'backupItem.discovery.Jdbc'
+-var required = 'backupItem.discovery.kind === "Jdbc"'
+
+div
+    .details-row
+        +checkbox('DB schema should be initialized by Ignite', `${model}.initSchema`, '"initSchema"',
+            'Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user')
+    .details-row
+        +text('Data source bean name:', `${model}.dataSourceBean`,
+            '"dataSourceBean"', required, 'Input bean name', 'Name of the data source bean in Spring context')
+    .details-row
+        +dialect('Dialect:', `${model}.dialect`, '"dialect"', required,
+            'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect', 'Choose JDBC dialect')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
deleted file mode 100644
index 6a7e9fa..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
+++ /dev/null
@@ -1,99 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var form = 'general'
--var model = 'backupItem.discovery.Multicast'
--var addresses = model + '.addresses'
-
-div
-    .details-row
-        +text-ip-address('IP address:', model + '.multicastGroup', '"multicastGroup"', 'true', '228.1.2.4', 'IP address of multicast group')
-    .details-row
-        +number-min-max('Port number:', model + '.multicastPort', '"multicastPort"', 'true', '47400', '0', '65535', 'Port number which multicast messages are sent to')
-    .details-row
-        +number('Waits for reply:', model + '.responseWaitTime', '"responseWaitTime"', 'true', '500', '0',
-            'Time in milliseconds IP finder waits for reply to multicast address request')
-    .details-row
-        +number('Attempts count:', model + '.addressRequestAttempts', '"addressRequestAttempts"', 'true', '2', '0',
-            'Number of attempts to send multicast address request<br/>\
-            IP finder re - sends request only in case if no reply for previous request is received')
-    .details-row
-        +text-ip-address('Local address:', model + '.localAddress', '"localAddress"', 'true', '0.0.0.0',
-            'Local host address used by this IP finder<br/>\
-            If provided address is non - loopback then multicast socket is bound to this interface<br/>\
-            If local address is not set or is any local address then IP finder creates multicast sockets for all found non - loopback addresses')
-    .details-row
-        -var form = 'discoveryMulticastAddresses';
-
-        +ignite-form-group(ng-model=addresses ng-form=form)
-            -var uniqueTip = 'Such IP address already exists!'
-            -var ipAddressTip = 'Invalid IP address!'
-
-            ignite-form-field-label
-                | Addresses
-            ignite-form-group-tooltip
-                | Addresses may be represented as follows:#[br]
-                ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
-                    li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
-                    li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
-                    li Hostname (e.g. host1.com, host2, etc)
-                    li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
-                    li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
-                | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
-                | If port range is provided (e.g. host:port1..port2) the following should be considered:#[br]
-                ul: li port1 &lt; port2 should be true
-                    li Both port1 and port2 should be greater than 0
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new address
-
-            .group-content(ng-if='#{addresses}.length')
-                -var model = 'obj.model';
-                -var name = '"edit" + $index'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = addresses + '[$index] = ' + model
-
-                div(ng-repeat='model in #{addresses} track by $index' ng-init='obj = {}')
-                    label.col-xs-12.col-sm-12.col-md-12
-                        .indexField
-                            | {{ $index+1 }})
-                        +table-remove-button(addresses, 'Remove address')
-
-                        +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-                        +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-
-                        span(ng-hide='field.edit')
-                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
-                        span(ng-if='field.edit')
-                            +table-address-field(name, model, addresses, valid, save, false, true)
-                                +table-save-button(valid, save, false)
-                                +unique-feedback(name, uniqueTip)
-
-            .group-content(ng-repeat='field in group.add')
-                -var model = 'new';
-                -var name = '"new"'
-                -var valid = form + '[' + name + '].$valid'
-                -var save = addresses + '.push(' + model + ')'
-
-                div
-                    label.col-xs-12.col-sm-12.col-md-12
-                        +table-address-field(name, model, addresses, valid, save, true, true)
-                            +table-save-button(valid, save, true)
-                            +unique-feedback(name, uniqueTip)
-
-            .group-content-empty(ng-if='!(#{addresses}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.pug
new file mode 100644
index 0000000..f865fd3
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.pug
@@ -0,0 +1,99 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var form = 'general'
+-var model = 'backupItem.discovery.Multicast'
+-var addresses = model + '.addresses'
+
+div
+    .details-row
+        +text-ip-address('IP address:', `${model}.multicastGroup`, '"multicastGroup"', 'true', '228.1.2.4', 'IP address of multicast group')
+    .details-row
+        +number-min-max('Port number:', `${model}.multicastPort`, '"multicastPort"', 'true', '47400', '0', '65535', 'Port number which multicast messages are sent to')
+    .details-row
+        +number('Waits for reply:', `${model}.responseWaitTime`, '"responseWaitTime"', 'true', '500', '0',
+            'Time in milliseconds IP finder waits for reply to multicast address request')
+    .details-row
+        +number('Attempts count:', `${model}.addressRequestAttempts`, '"addressRequestAttempts"', 'true', '2', '0',
+            'Number of attempts to send multicast address request<br/>\
+            IP finder re - sends request only in case if no reply for previous request is received')
+    .details-row
+        +text-ip-address('Local address:', `${model}.localAddress`, '"localAddress"', 'true', '0.0.0.0',
+            'Local host address used by this IP finder<br/>\
+            If provided address is non - loopback then multicast socket is bound to this interface<br/>\
+            If local address is not set or is any local address then IP finder creates multicast sockets for all found non - loopback addresses')
+    .details-row
+        -var form = 'discoveryMulticastAddresses';
+
+        +ignite-form-group(ng-model=`${addresses}` ng-form=form)
+            -var uniqueTip = 'Such IP address already exists!'
+            -var ipAddressTip = 'Invalid IP address!'
+
+            ignite-form-field-label
+                | Addresses
+            ignite-form-group-tooltip
+                | Addresses may be represented as follows:#[br]
+                ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
+                    li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
+                    li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
+                    li Hostname (e.g. host1.com, host2, etc)
+                    li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
+                    li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
+                | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
+                | If port range is provided (e.g. host:port1..port2) the following should be considered:#[br]
+                ul: li port1 &lt; port2 should be true
+                    li Both port1 and port2 should be greater than 0
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new address
+
+            .group-content(ng-if=`${addresses}.length`)
+                -var model = 'obj.model';
+                -var name = '"edit" + $index'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${addresses}[$index] = ${model}`
+
+                div(ng-repeat=`model in ${addresses} track by $index` ng-init='obj = {}')
+                    label.col-xs-12.col-sm-12.col-md-12
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(addresses, 'Remove address')
+
+                        +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+                        +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click=`field.edit = true; ${model} = model;`) {{ model }}
+                        span(ng-if='field.edit')
+                            +table-address-field(name, model, addresses, valid, save, false, true)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'new';
+                -var name = '"new"'
+                -var valid = `${form}[${name}].$valid`
+                -var save = `${addresses}.push(${model})`
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-address-field(name, model, addresses, valid, save, true, true)
+                            +table-save-button(valid, save, true)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if=`!(${addresses}.length) && !group.add.length`)
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
deleted file mode 100644
index e5eaff3..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
+++ /dev/null
@@ -1,27 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var discoveryKind = 'S3'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.S3'
-
-div
-    .details-row
-        +text('Bucket name:', model + '.bucketName', '"' + discoveryKind + 'BucketName"', required, 'Input bucket name', 'Bucket name for IP finder')
-    .details-row
-        label Note, AWS credentials will be generated as stub

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.pug
new file mode 100644
index 0000000..ed6e20e
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.pug
@@ -0,0 +1,27 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var discoveryKind = 'S3'
+-var required = `backupItem.discovery.kind == '${discoveryKind}'`
+-var model = 'backupItem.discovery.S3'
+
+div
+    .details-row
+        +text('Bucket name:', `${model}.bucketName`, `${discoveryKind}BucketName'`, required, 'Input bucket name', 'Bucket name for IP finder')
+    .details-row
+        label Note, AWS credentials will be generated as stub

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
deleted file mode 100644
index ddd9bfa..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
+++ /dev/null
@@ -1,23 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.SharedFs'
-
-div
-    .details-row
-        +text('File path:', model + '.path', '"path"', 'false', 'disco/tcp', 'Shared path')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.pug
new file mode 100644
index 0000000..8eb9736
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.pug
@@ -0,0 +1,23 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var model = 'backupItem.discovery.SharedFs'
+
+div
+    .details-row
+        +text('File path:', `${model}.path`, '"path"', 'false', 'disco/tcp', 'Shared path')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
deleted file mode 100644
index 46ebae0..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
+++ /dev/null
@@ -1,79 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.Vm'
--var addresses = model + '.addresses'
--var form = 'discoveryVmAddresses'
-
-.details-row
-    +ignite-form-group(ng-form=form ng-model=addresses)
-        -var uniqueTip = 'Such IP address already exists!'
-
-        ignite-form-field-label
-            | Addresses
-        ignite-form-group-tooltip
-            | Addresses may be represented as follows:
-            ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
-                li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
-                li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
-                li Hostname (e.g. host1.com, host2, etc)
-                li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
-                li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
-            | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
-            | If port range is provided (e.g. host:port1..port2) the following should be considered:
-            ul: li port1 &lt; port2 should be true
-                li Both port1 and port2 should be greater than 0
-        ignite-form-group-add(ng-click='group.add = [{}]')
-            | Add new address
-
-        .group-content(ng-if='#{addresses}.length')
-            -var model = 'obj.model';
-            -var name = '"edit" + $index'
-            -var valid = form + '[' + name + '].$valid'
-            -var save = addresses + '[$index] = ' + model
-
-            div(ng-repeat='model in #{addresses} track by $index' ng-init='obj = {}')
-                label.col-xs-12.col-sm-12.col-md-12
-                    .indexField
-                        | {{ $index+1 }})
-                    +table-remove-button(addresses, 'Remove address')
-
-                    +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-                    +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-
-                    span(ng-hide='field.edit')
-                        a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
-                    span(ng-if='field.edit')
-                        +table-address-field(name, model, addresses, valid, save, false, true)
-                            +table-save-button(valid, save, false)
-                            +unique-feedback(name, uniqueTip)
-
-        .group-content(ng-repeat='field in group.add')
-            -var model = 'new';
-            -var name = '"new"'
-            -var valid = form + '[' + name + '].$valid'
-            -var save = addresses + '.push(' + model + ')'
-
-            div
-                label.col-xs-12.col-sm-12.col-md-12
-                    +table-address-field(name, model, addresses, valid, save, true, true)
-                        +table-save-button(valid, save, true)
-                        +unique-feedback(name, uniqueTip)
-
-        .group-content-empty(id='addresses' ng-if='!(#{addresses}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.pug
new file mode 100644
index 0000000..9205c72
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.pug
@@ -0,0 +1,79 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var model = 'backupItem.discovery.Vm'
+-var addresses = model + '.addresses'
+-var form = 'discoveryVmAddresses'
+
+.details-row
+    +ignite-form-group(ng-form=form ng-model=`${addresses}`)
+        -var uniqueTip = 'Such IP address already exists!'
+
+        ignite-form-field-label
+            | Addresses
+        ignite-form-group-tooltip
+            | Addresses may be represented as follows:
+            ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
+                li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
+                li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
+                li Hostname (e.g. host1.com, host2, etc)
+                li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
+                li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
+            | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
+            | If port range is provided (e.g. host:port1..port2) the following should be considered:
+            ul: li port1 &lt; port2 should be true
+                li Both port1 and port2 should be greater than 0
+        ignite-form-group-add(ng-click='group.add = [{}]')
+            | Add new address
+
+        .group-content(ng-if=`${addresses}.length`)
+            -var model = 'obj.model';
+            -var name = '"edit" + $index'
+            -var valid = `${form}[${name}].$valid`
+            -var save = `${addresses}[$index] = ${model}`
+
+            div(ng-repeat=`model in ${addresses} track by $index` ng-init='obj = {}')
+                label.col-xs-12.col-sm-12.col-md-12
+                    .indexField
+                        | {{ $index+1 }})
+                    +table-remove-button(addresses, 'Remove address')
+
+                    +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+                    +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+
+                    span(ng-hide='field.edit')
+                        a.labelFormField(ng-click=`field.edit = true; ${model} = model;`) {{ model }}
+                    span(ng-if='field.edit')
+                        +table-address-field(name, model, addresses, valid, save, false, true)
+                            +table-save-button(valid, save, false)
+                            +unique-feedback(name, uniqueTip)
+
+        .group-content(ng-repeat='field in group.add')
+            -var model = 'new';
+            -var name = '"new"'
+            -var valid = `${form}[${name}].$valid`
+            -var save = `${addresses}.push(${model})`
+
+            div
+                label.col-xs-12.col-sm-12.col-md-12
+                    +table-address-field(name, model, addresses, valid, save, true, true)
+                        +table-save-button(valid, save, true)
+                        +unique-feedback(name, uniqueTip)
+
+        .group-content-empty(id='addresses' ng-if=`!(${addresses}.length) && !group.add.length`)
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
deleted file mode 100644
index 48b1776..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
+++ /dev/null
@@ -1,85 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var form = 'general'
--var discoveryKind = 'ZooKeeper'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.ZooKeeper'
--var modelRetryPolicyKind = model + '.retryPolicy.kind'
-
-div
-    .details-row
-        +java-class('Curator:', model + '.curator', '"curator"', 'true', 'false',
-            'The Curator framework in use<br/>\
-            By default generates curator of org.apache.curator. framework.imps.CuratorFrameworkImpl\
-            class with configured connect string, retry policy, and default session and connection timeouts', required)
-    .details-row
-        +text('Connect string:', model + '.zkConnectionString', '"' + discoveryKind + 'ConnectionString"', required, 'host:port[chroot][,host:port[chroot]]',
-            'When "IGNITE_ZK_CONNECTION_STRING" system property is not configured this property will be used')
-    .details-row
-        +dropdown('Retry policy:', model + '.retryPolicy.kind', '"retryPolicy"', 'true', 'Default',
-            '[\
-                {value: "ExponentialBackoff", label: "Exponential backoff"},\
-                {value: "BoundedExponentialBackoff", label: "Bounded exponential backoff"},\
-                {value: "UntilElapsed", label: "Until elapsed"},\
-                {value: "NTimes", label: "Max number of times"},\
-                {value: "OneTime", label: "Only once"},\
-                {value: "Forever", label: "Always allow retry"},\
-                {value: "Custom", label: "Custom"},\
-                {value: undefined, label: "Default"}\
-            ]',
-            'Available retry policies:\
-            <ul>\
-                <li>Exponential backoff - retries a set number of times with increasing sleep time between retries</li>\
-                <li>Bounded exponential backoff - retries a set number of times with an increasing (up to a maximum bound) sleep time between retries</li>\
-                <li>Until elapsed - retries until a given amount of time elapses</li>\
-                <li>Max number of times - retries a max number of times</li>\
-                <li>Only once - retries only once</li>\
-                <li>Always allow retry - retries infinitely</li>\
-                <li>Custom - custom retry policy implementation</li>\
-                <li>Default - exponential backoff retry policy with configured base sleep time equal to 1000ms and max retry count equal to 10</li>\
-            </ul>')
-    .details-row(ng-show='#{model}.retryPolicy.kind')
-        .panel-details
-                div(ng-show='#{modelRetryPolicyKind} === "ExponentialBackoff"')
-                    include ./zookeeper/retrypolicy/exponential-backoff.jade
-                div(ng-show='#{modelRetryPolicyKind} === "BoundedExponentialBackoff"')
-                    include ./zookeeper/retrypolicy/bounded-exponential-backoff.jade
-                div(ng-show='#{modelRetryPolicyKind} === "UntilElapsed"')
-                    include ./zookeeper/retrypolicy/until-elapsed.jade
-                div(ng-show='#{modelRetryPolicyKind} === "NTimes"')
-                    include ./zookeeper/retrypolicy/n-times.jade
-                div(ng-show='#{modelRetryPolicyKind} === "OneTime"')
-                    include ./zookeeper/retrypolicy/one-time.jade
-                div(ng-show='#{modelRetryPolicyKind} === "Forever"')
-                    include ./zookeeper/retrypolicy/forever.jade
-                div(ng-show='#{modelRetryPolicyKind} === "Custom"')
-                    include ./zookeeper/retrypolicy/custom.jade
-    .details-row
-        -var model = 'backupItem.discovery.ZooKeeper'
-
-        +text('Base path:', model + '.basePath', '"basePath"', 'false', '/services', 'Base path for service registration')
-    .details-row
-        +text('Service name:', model + '.serviceName', '"serviceName"', 'false', 'ignite',
-            'Service name to use, as defined by Curator&#39;s ServiceDiscovery recipe<br/>\
-            In physical ZooKeeper terms, it represents the node under basePath, under which services will be registered')
-    .details-row
-        +checkbox('Allow duplicate registrations', model + '.allowDuplicateRegistrations', '"allowDuplicateRegistrations"',
-            'Whether to register each node only once, or if duplicate registrations are allowed<br/>\
-            Nodes will attempt to register themselves, plus those they know about<br/>\
-            By default, duplicate registrations are not allowed, but you might want to set this property to <b>true</b> if you have multiple network interfaces or if you are facing troubles')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.pug
new file mode 100644
index 0000000..91548e4
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.pug
@@ -0,0 +1,85 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var form = 'general'
+-var discoveryKind = 'ZooKeeper'
+-var required = `backupItem.discovery.kind == '${discoveryKind}'`
+-var model = 'backupItem.discovery.ZooKeeper'
+-var modelRetryPolicyKind = `${model}.retryPolicy.kind`
+
+div
+    .details-row
+        +java-class('Curator:', `${model}.curator`, '"curator"', 'true', 'false',
+            'The Curator framework in use<br/>\
+            By default generates curator of org.apache.curator. framework.imps.CuratorFrameworkImpl\
+            class with configured connect string, retry policy, and default session and connection timeouts', required)
+    .details-row
+        +text('Connect string:', `${model}.zkConnectionString`, `'${discoveryKind}ConnectionString'`, required, 'host:port[chroot][,host:port[chroot]]',
+            'When "IGNITE_ZK_CONNECTION_STRING" system property is not configured this property will be used')
+    .details-row
+        +dropdown('Retry policy:', `${model}.retryPolicy.kind`, '"retryPolicy"', 'true', 'Default',
+            '[\
+                {value: "ExponentialBackoff", label: "Exponential backoff"},\
+                {value: "BoundedExponentialBackoff", label: "Bounded exponential backoff"},\
+                {value: "UntilElapsed", label: "Until elapsed"},\
+                {value: "NTimes", label: "Max number of times"},\
+                {value: "OneTime", label: "Only once"},\
+                {value: "Forever", label: "Always allow retry"},\
+                {value: "Custom", label: "Custom"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Available retry policies:\
+            <ul>\
+                <li>Exponential backoff - retries a set number of times with increasing sleep time between retries</li>\
+                <li>Bounded exponential backoff - retries a set number of times with an increasing (up to a maximum bound) sleep time between retries</li>\
+                <li>Until elapsed - retries until a given amount of time elapses</li>\
+                <li>Max number of times - retries a max number of times</li>\
+                <li>Only once - retries only once</li>\
+                <li>Always allow retry - retries infinitely</li>\
+                <li>Custom - custom retry policy implementation</li>\
+                <li>Default - exponential backoff retry policy with configured base sleep time equal to 1000ms and max retry count equal to 10</li>\
+            </ul>')
+    .details-row(ng-show=`${model}.retryPolicy.kind`)
+        .panel-details
+                div(ng-show=`${modelRetryPolicyKind} === 'ExponentialBackoff'`)
+                    include ./zookeeper/retrypolicy/exponential-backoff
+                div(ng-show=`${modelRetryPolicyKind} === 'BoundedExponentialBackoff'`)
+                    include ./zookeeper/retrypolicy/bounded-exponential-backoff
+                div(ng-show=`${modelRetryPolicyKind} === 'UntilElapsed'`)
+                    include ./zookeeper/retrypolicy/until-elapsed
+                div(ng-show=`${modelRetryPolicyKind} === 'NTimes'`)
+                    include ./zookeeper/retrypolicy/n-times
+                div(ng-show=`${modelRetryPolicyKind} === 'OneTime'`)
+                    include ./zookeeper/retrypolicy/one-time
+                div(ng-show=`${modelRetryPolicyKind} === 'Forever'`)
+                    include ./zookeeper/retrypolicy/forever
+                div(ng-show=`${modelRetryPolicyKind} === 'Custom'`)
+                    include ./zookeeper/retrypolicy/custom
+    .details-row
+        -var model = 'backupItem.discovery.ZooKeeper'
+
+        +text('Base path:', `${model}.basePath`, '"basePath"', 'false', '/services', 'Base path for service registration')
+    .details-row
+        +text('Service name:', `${model}.serviceName`, '"serviceName"', 'false', 'ignite',
+            'Service name to use, as defined by Curator&#39;s ServiceDiscovery recipe<br/>\
+            In physical ZooKeeper terms, it represents the node under basePath, under which services will be registered')
+    .details-row
+        +checkbox('Allow duplicate registrations', `${model}.allowDuplicateRegistrations`, '"allowDuplicateRegistrations"',
+            'Whether to register each node only once, or if duplicate registrations are allowed<br/>\
+            Nodes will attempt to register themselves, plus those they know about<br/>\
+            By default, duplicate registrations are not allowed, but you might want to set this property to <b>true</b> if you have multiple network interfaces or if you are facing troubles')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
deleted file mode 100644
index d3c1f9f..0000000
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
+++ /dev/null
@@ -1,27 +0,0 @@
-//-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
-include /app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.BoundedExponentialBackoff'
-
-div
-    .details-row
-        +number('Base interval:', model + '.baseSleepTimeMs', '"beBaseSleepTimeMs"', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
-    .details-row
-        +number('Max interval:', model + '.maxSleepTimeMs', '"beMaxSleepTimeMs"', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')
-    .details-row
-        +number-min-max('Max retries:', model + '.maxRetries', '"beMaxRetries"', 'true', '10', '0', '29', 'Max number of times to retry')

http://git-wip-us.apache.org/repos/asf/ignite/blob/1080e686/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.pug
new file mode 100644
index 0000000..c71be9a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.pug
@@ -0,0 +1,27 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include /app/helpers/jade/mixins
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.BoundedExponentialBackoff'
+
+div
+    .details-row
+        +number('Base interval:', `${model}.baseSleepTimeMs`, '"beBaseSleepTimeMs"', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
+    .details-row
+        +number('Max interval:', `${model}.maxSleepTimeMs`, '"beMaxSleepTimeMs"', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')
+    .details-row
+        +number-min-max('Max retries:', `${model}.maxRetries`, '"beMaxRetries"', 'true', '10', '0', '29', 'Max number of times to retry')