You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2018/04/02 12:24:36 UTC

[13/24] ignite git commit: IGNITE-5466 Web Console: Configuration reworked to cluster centric model: 1. Reworked data model. 2. Implemented migrations. 3. Reworked UI for all screens. 4. Reworked validation. 5. Many refactorings to improve code base

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.pug
index 1eeea84..676234f 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.pug
@@ -17,23 +17,22 @@
 include /app/helpers/jade/mixins
 
 -var form = 'statistics'
--var model = 'backupItem'
+-var model = '$ctrl.clonedCache'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
+.pca-panel(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Statistics
-        ignite-form-field-tooltip.tipLabel
-            | Cache statistics and management settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .panel-body(ng-if=`ui.isPanelLoaded('${form}')`)
-            .col-sm-6
-                .settings-row
+        .pca-panel-heading-title Statistics
+        .pca-panel-heading-description
+            | Cache statistics and management settings.
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+            .pca-form-column-6.pc-form-grid-row
+                .pc-form-grid-col-60
                     +checkbox('Statistics enabled', `${model}.statisticsEnabled`, '"statisticsEnabled"', 'Flag indicating whether statistics gathering is enabled on this cache')
-                .settings-row
+                .pc-form-grid-col-60
                     +checkbox('Management enabled', `${model}.managementEnabled`, '"managementEnabled"',
                     'Flag indicating whether management is enabled on this cache<br/>\
                     If enabled the CacheMXBean for each cache is registered in the platform MBean server')
-            .col-sm-6
+            .pca-form-column-6
                 +preview-xml-java(model, 'cacheStatistics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/caches/store.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/store.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/store.pug
index 0c983a2..4cfbbaf 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/store.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/store.pug
@@ -17,7 +17,7 @@
 include /app/helpers/jade/mixins
 
 -var form = 'store'
--var model = 'backupItem'
+-var model = '$ctrl.clonedCache'
 
 mixin hibernateField(name, model, items, valid, save, newItem)
     -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
@@ -42,169 +42,182 @@ mixin hibernateField(name, model, items, valid, save, newItem)
                 ignite-on-escape=onEscape
             )
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
+.pca-panel(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Store
-        ignite-form-field-tooltip.tipLabel
-            | Cache store settings#[br]
-            | #[a(href="https://apacheignite.readme.io/docs/3rd-party-store" 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
-                    -var storeFactory = `${model}.cacheStoreFactory`;
-                    -var storeFactoryKind = `${storeFactory}.kind`;
-
-                    +dropdown('Store factory:', storeFactoryKind, '"cacheStoreFactory"', 'true', 'Not set',
-                        '[\
-                            {value: "CacheJdbcPojoStoreFactory", label: "JDBC POJO store factory"},\
-                            {value: "CacheJdbcBlobStoreFactory", label: "JDBC BLOB store factory"},\
-                            {value: "CacheHibernateBlobStoreFactory", label: "Hibernate BLOB store factory"},\
-                            {value: null, label: "Not set"}\
-                        ]',
-                        'Factory for persistent storage for cache data\
-                        <ul>\
-                            <li>JDBC POJO store factory - Objects are stored in underlying database by using java beans mapping description via reflection backed by JDBC</li>\
-                            <li>JDBC BLOB store factory - Objects are stored in underlying database in BLOB format backed by JDBC</li>\
-                            <li>Hibernate BLOB store factory - Objects are stored in underlying database in BLOB format backed by Hibernate</li>\
-                        </ul>'
+        .pca-panel-heading-title Store
+        .pca-panel-heading-description
+            | Cache store settings. 
+            | #[a.link-success(href="https://apacheignite.readme.io/docs/3rd-party-store" target="_blank") More info]
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+            .pca-form-column-6.pc-form-grid-row
+                -var storeFactory = `${model}.cacheStoreFactory`;
+                -var storeFactoryKind = `${storeFactory}.kind`;
+                .pc-form-grid-col-60
+                    +sane-ignite-form-field-dropdown({
+                        label: 'Store factory:',
+                        model: storeFactoryKind,
+                        name: '"cacheStoreFactory"',
+                        placeholder: '{{ ::$ctrl.Caches.cacheStoreFactory.kind.default }}',
+                        options: '::$ctrl.Caches.cacheStoreFactory.values',
+                        tip: `Factory for persistent storage for cache data
+                        <ul>
+                            <li>JDBC POJO store factory - Objects are stored in underlying database by using java beans mapping description via reflection backed by JDBC</li>
+                            <li>JDBC BLOB store factory - Objects are stored in underlying database in BLOB format backed by JDBC</li>
+                            <li>Hibernate BLOB store factory - Objects are stored in underlying database in BLOB format backed by Hibernate</li>
+                        </ul>`
+                    })(
+                        ui-validate=`{
+                            writeThroughOn: '$ctrl.Caches.cacheStoreFactory.storeDisabledValueOff(${model}, ${model}.writeThrough)',
+                            readThroughOn: '$ctrl.Caches.cacheStoreFactory.storeDisabledValueOff(${model}, ${model}.readThrough)',
+                            writeBehindOn: '$ctrl.Caches.cacheStoreFactory.storeDisabledValueOff(${model}, ${model}.writeBehindEnabled)'
+                        }`
+                        ui-validate-watch-collection=`"[${model}.readThrough, ${model}.writeThrough, ${model}.writeBehindEnabled]"`
+                        ng-model-options='{allowInvalid: true}'
                     )
-                    span(ng-show=storeFactoryKind ng-init='__.expanded = true')
-                        a.customize(ng-show='__.expanded' ng-click='__.expanded = false') Hide settings
-                        a.customize(ng-hide='__.expanded' ng-click='__.expanded = true') Show settings
-                        .panel-details(ng-show='__.expanded')
-                            div(ng-show=`${storeFactoryKind} === 'CacheJdbcPojoStoreFactory'`)
-                                -var pojoStoreFactory = `${storeFactory}.CacheJdbcPojoStoreFactory`
-                                -var required = `${storeFactoryKind} === 'CacheJdbcPojoStoreFactory'`
-
-                                .details-row
-                                    +text('Data source bean name:', `${pojoStoreFactory}.dataSourceBean`,
-                                        '"pojoDataSourceBean"', required, 'Input bean name',
-                                        'Name of the data source bean in Spring context')
-                                .details-row
-                                    +dialect('Dialect:', `${pojoStoreFactory}.dialect`, '"pojoDialect"', required,
-                                        'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect',
-                                        'Choose JDBC dialect')
-                                .details-row
-                                    +number('Batch size:', `${pojoStoreFactory}.batchSize`, '"pojoBatchSize"', true, '512', '1',
-                                        'Maximum batch size for writeAll and deleteAll operations')
-                                .details-row
-                                    +number('Thread count:', `${pojoStoreFactory}.maximumPoolSize`, '"pojoMaximumPoolSize"', true, 'availableProcessors', '1',
-                                        'Maximum workers thread count.<br/>\
-                                        These threads are responsible for load cache.')
-                                .details-row
-                                    +number('Maximum write attempts:', `${pojoStoreFactory}.maximumWriteAttempts`, '"pojoMaximumWriteAttempts"', true, '2', '0',
-                                        'Maximum write attempts in case of database error')
-                                .details-row
-                                    +number('Parallel load threshold:', `${pojoStoreFactory}.parallelLoadCacheMinimumThreshold`, '"pojoParallelLoadCacheMinimumThreshold"', true, '512', '0',
-                                        'Parallel load cache minimum threshold.<br/>\
-                                        If <b>0</b> then load sequentially.')
-                                .details-row
-                                    +java-class('Hasher', `${pojoStoreFactory}.hasher`, '"pojoHasher"', 'true', 'false', 'Hash calculator', required)
-                                .details-row
-                                    +java-class('Transformer', `${pojoStoreFactory}.transformer`, '"pojoTransformer"', 'true', 'false', 'Types transformer', required)
-                                .details-row
-                                    +checkbox('Escape table and filed names', `${pojoStoreFactory}.sqlEscapeAll`, '"sqlEscapeAll"',
-                                        'If enabled than all schema, table and field names will be escaped with double quotes (for example: "tableName"."fieldName").<br/>\
-                                        This enforces case sensitivity for field names and also allows having special characters in table and field names.<br/>\
-                                        Escaped names will be used for CacheJdbcPojoStore internal SQL queries.')
-                            div(ng-show=`${storeFactoryKind} === 'CacheJdbcBlobStoreFactory'`)
-                                -var blobStoreFactory = `${storeFactory}.CacheJdbcBlobStoreFactory`
-                                -var blobStoreFactoryVia = `${blobStoreFactory}.connectVia`
-
-                                .details-row
-                                    +dropdown('Connect via:', blobStoreFactoryVia, '"connectVia"', 'true', 'Choose connection method',
-                                        '[\
-                                            {value: "URL", label: "URL"},\
-                                            {value: "DataSource", label: "Data source"}\
-                                        ]',
-                                        'You can connect to database via:\
-                                        <ul>\
-                                            <li>JDBC URL, for example: jdbc:h2:mem:myDatabase</li>\
-                                            <li>Configured data source</li>\
-                                        </ul>')
-                                div(ng-show=`${blobStoreFactoryVia} === 'URL'`)
-                                    -var required = `${storeFactoryKind} === 'CacheJdbcBlobStoreFactory' && ${blobStoreFactoryVia} === 'URL'`
-
-                                    .details-row
-                                        +text('Connection URL:', `${blobStoreFactory}.connectionUrl`, '"connectionUrl"', required, 'Input URL',
-                                            'URL for database access, for example: jdbc:h2:mem:myDatabase')
-                                    .details-row
-                                        +text('User:', `${blobStoreFactory}.user`, '"user"', required, 'Input user name', 'User name for database access')
-                                    .details-row
-                                        label Note, password will be generated as stub
-                                div(ng-show=`${blobStoreFactoryVia} !== 'URL'`)
-                                    -var required = `${storeFactoryKind} === 'CacheJdbcBlobStoreFactory' && ${blobStoreFactoryVia} !== 'URL'`
-
-                                    .details-row
-                                        +text('Data source bean name:', `${blobStoreFactory}.dataSourceBean`, '"blobDataSourceBean"', required, 'Input bean name',
-                                            'Name of the data source bean in Spring context')
-                                    .details-row
-                                        +dialect('Database:', `${blobStoreFactory}.dialect`, '"blobDialect"', required, 'Supported databases:', 'Generic database', 'Choose database')
-                                .details-row
-                                    +checkbox('Init schema', `${blobStoreFactory}.initSchema`, '"initSchema"',
-                                        'Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user')
-                                .details-row
-                                    +text('Create query:', `${blobStoreFactory}.createTableQuery`, '"createTableQuery"', 'false', 'SQL for table creation',
-                                        'Query for table creation in underlying database<br/>\
-                                        Default value: create table if not exists ENTRIES (key binary primary key, val binary)')
-                                .details-row
-                                    +text('Load query:', `${blobStoreFactory}.loadQuery`, '"loadQuery"', 'false', 'SQL for load entry',
-                                        'Query for entry load from underlying database<br/>\
-                                        Default value: select * from ENTRIES where key=?')
-                                .details-row
-                                    +text('Insert query:', `${blobStoreFactory}.insertQuery`, '"insertQuery"', 'false', 'SQL for insert entry',
-                                        'Query for insert entry into underlying database<br/>\
-                                        Default value: insert into ENTRIES (key, val) values (?, ?)')
-                                .details-row
-                                    +text('Update query:', `${blobStoreFactory}.updateQuery`, '"updateQuery"', 'false', 'SQL for update entry',
-                                        'Query for update entry in underlying database<br/>\
-                                        Default value: update ENTRIES set val=? where key=?')
-                                .details-row
-                                    +text('Delete query:', `${blobStoreFactory}.deleteQuery`, '"deleteQuery"', 'false', 'SQL for delete entry',
-                                        'Query for delete entry from underlying database<br/>\
-                                        Default value: delete from ENTRIES where key=?')
-
-                            div(ng-show=`${storeFactoryKind} === 'CacheHibernateBlobStoreFactory'`)
-                                -var hibernateStoreFactory = `${storeFactory}.CacheHibernateBlobStoreFactory`
-                                -var hibernateProperties = `${hibernateStoreFactory}.hibernateProperties`
-
-                                .details-row
-                                    +ignite-form-group(ng-form=form ng-model=hibernateProperties)
-                                        ignite-form-field-label
-                                            | Hibernate properties
-                                        ignite-form-group-tooltip
-                                            | List of Hibernate properties#[br]
-                                            | For example: connection.url=jdbc:h2:mem:exampleDb
-                                        ignite-form-group-add(ng-click='tableNewItem(hibernatePropsTbl)')
-                                            | Add new Hibernate property
-
-                                        -var tipUnique = 'Property with such key already exists!'
-                                        -var tipPropertySpecified = 'Property should be present in format key=value!'
-
-                                        .group-content-empty(ng-if=`!((${hibernateProperties} && ${hibernateProperties}.length > 0) || tableNewItemActive(hibernatePropsTbl))`)
-                                            | Not defined
-                                        .group-content(ng-show=`(${hibernateProperties} && ${hibernateProperties}.length > 0) || tableNewItemActive(hibernatePropsTbl)`)
-                                            table.links-edit(id='hibernateProps' st-table=hibernateProperties)
-                                                tbody
-                                                    tr(ng-repeat=`item in ${hibernateProperties}`)
-                                                        td.col-sm-12(ng-hide='tableEditing(hibernatePropsTbl, $index)')
-                                                            a.labelFormField(ng-click='tableStartEdit(backupItem, hibernatePropsTbl, $index)') {{item.name}} = {{item.value}}
-                                                            +btn-remove('tableRemove(backupItem, hibernatePropsTbl, $index)', '"Remove Property"')
-                                                        td.col-sm-12(ng-if='tableEditing(hibernatePropsTbl, $index)')
-                                                            +table-pair-edit('hibernatePropsTbl', 'cur', 'Property name', 'Property value', false, '{{::hibernatePropsTbl.focusId + $index}}', '$index', '=')
-                                                tfoot(ng-show='tableNewItemActive(hibernatePropsTbl)')
-                                                    tr
-                                                        td.col-sm-12
-                                                            +table-pair-edit('hibernatePropsTbl', 'new', 'Property name', 'Property value', false, '{{::hibernatePropsTbl.focusId + $index}}', '-1', '=')
-
-
-                .settings-row
+                        +form-field-feedback(null, 'writeThroughOn', 'Write through is enabled but store is not set')
+                        +form-field-feedback(null, 'readThroughOn', 'Read through is enabled but store is not set')
+                        +form-field-feedback(null, 'writeBehindOn', 'Write-behind is enabled but store is not set')
+                .pc-form-group(ng-if=storeFactoryKind)
+                    .pc-form-grid-row(ng-if=`${storeFactoryKind} === 'CacheJdbcPojoStoreFactory'`)
+                        -var pojoStoreFactory = `${storeFactory}.CacheJdbcPojoStoreFactory`
+                        -var required = `${storeFactoryKind} === 'CacheJdbcPojoStoreFactory'`
+
+                        .pc-form-grid-col-60
+                            +sane-ignite-form-field-text({
+                                label: 'Data source bean name:',
+                                model: `${pojoStoreFactory}.dataSourceBean`,
+                                name: '"pojoDataSourceBean"',
+                                required: required,
+                                placeholder: 'Input bean name',
+                                tip: 'Name of the data source bean in Spring context'
+                            })(
+                                is-valid-java-identifier
+                                not-java-reserved-word
+                            )
+                                +form-field-feedback(null, 'required', 'Data source bean name is required')
+                                +form-field-feedback(null, 'isValidJavaIdentifier', 'Data source bean name is not a valid Java identifier')
+                                +form-field-feedback(null, 'notJavaReservedWord', 'Data source bean name should not be a Java reserved word')
+                        .pc-form-grid-col-60
+                            +dialect('Dialect:', `${pojoStoreFactory}.dialect`, '"pojoDialect"', required,
+                                'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect',
+                                'Choose JDBC dialect')
+                        .pc-form-grid-col-30
+                            +number('Batch size:', `${pojoStoreFactory}.batchSize`, '"pojoBatchSize"', true, '512', '1',
+                                'Maximum batch size for writeAll and deleteAll operations')
+                        .pc-form-grid-col-30
+                            +number('Thread count:', `${pojoStoreFactory}.maximumPoolSize`, '"pojoMaximumPoolSize"', true, 'availableProcessors', '1',
+                                'Maximum workers thread count.<br/>\
+                                These threads are responsible for load cache.')
+                        .pc-form-grid-col-30
+                            +number('Maximum write attempts:', `${pojoStoreFactory}.maximumWriteAttempts`, '"pojoMaximumWriteAttempts"', true, '2', '0',
+                                'Maximum write attempts in case of database error')
+                        .pc-form-grid-col-30
+                            +number('Parallel load threshold:', `${pojoStoreFactory}.parallelLoadCacheMinimumThreshold`, '"pojoParallelLoadCacheMinimumThreshold"', true, '512', '0',
+                                'Parallel load cache minimum threshold.<br/>\
+                                If <b>0</b> then load sequentially.')
+                        .pc-form-grid-col-60
+                            +java-class('Hasher', `${pojoStoreFactory}.hasher`, '"pojoHasher"', 'true', 'false', 'Hash calculator', required)
+                        .pc-form-grid-col-60
+                            +java-class('Transformer', `${pojoStoreFactory}.transformer`, '"pojoTransformer"', 'true', 'false', 'Types transformer', required)
+                        .pc-form-grid-col-60
+                            +checkbox('Escape table and filed names', `${pojoStoreFactory}.sqlEscapeAll`, '"sqlEscapeAll"',
+                                'If enabled than all schema, table and field names will be escaped with double quotes (for example: "tableName"."fieldName").<br/>\
+                                This enforces case sensitivity for field names and also allows having special characters in table and field names.<br/>\
+                                Escaped names will be used for CacheJdbcPojoStore internal SQL queries.')
+                    .pc-form-grid-row(ng-if=`${storeFactoryKind} === 'CacheJdbcBlobStoreFactory'`)
+                        -var blobStoreFactory = `${storeFactory}.CacheJdbcBlobStoreFactory`
+                        -var blobStoreFactoryVia = `${blobStoreFactory}.connectVia`
+
+                        .pc-form-grid-col-60
+                            +dropdown('Connect via:', blobStoreFactoryVia, '"connectVia"', 'true', 'Choose connection method',
+                                '[\
+                                    {value: "URL", label: "URL"},\
+                                    {value: "DataSource", label: "Data source"}\
+                                ]',
+                                'You can connect to database via:\
+                                <ul>\
+                                    <li>JDBC URL, for example: jdbc:h2:mem:myDatabase</li>\
+                                    <li>Configured data source</li>\
+                                </ul>')
+
+                        -var required = `${storeFactoryKind} === 'CacheJdbcBlobStoreFactory' && ${blobStoreFactoryVia} === 'URL'`
+
+                        .pc-form-grid-col-60(ng-if-start=`${blobStoreFactoryVia} === 'URL'`)
+                            +text('Connection URL:', `${blobStoreFactory}.connectionUrl`, '"connectionUrl"', required, 'Input URL',
+                                'URL for database access, for example: jdbc:h2:mem:myDatabase')
+                        .pc-form-grid-col-30
+                            +text('User:', `${blobStoreFactory}.user`, '"user"', required, 'Input user name', 'User name for database access')
+                        .pc-form-grid-col-30(ng-if-end)
+                            .pc-form-grid__text-only-item Password will be generated as stub.
+
+                        -var required = `${storeFactoryKind} === 'CacheJdbcBlobStoreFactory' && ${blobStoreFactoryVia} !== 'URL'`
+
+                        .pc-form-grid-col-60(ng-if-start=`${blobStoreFactoryVia} !== 'URL'`)
+                            +sane-ignite-form-field-text({
+                                label: 'Data source bean name:',
+                                model: `${blobStoreFactory}.dataSourceBean`,
+                                name: '"blobDataSourceBean"',
+                                required: required,
+                                placeholder: 'Input bean name',
+                                tip: 'Name of the data source bean in Spring context'
+                            })(
+                                is-valid-java-identifier
+                                not-java-reserved-word
+                            )
+                                +form-field-feedback(null, 'required', 'Data source bean name is required')
+                                +form-field-feedback(null, 'isValidJavaIdentifier', 'Data source bean name is not a valid Java identifier')
+                                +form-field-feedback(null, 'notJavaReservedWord', 'Data source bean name should not be a Java reserved word')
+                        .pc-form-grid-col-60(ng-if-end)
+                            +dialect('Database:', `${blobStoreFactory}.dialect`, '"blobDialect"', required, 'Supported databases:', 'Generic database', 'Choose database')
+
+                        .pc-form-grid-col-60
+                            +checkbox('Init schema', `${blobStoreFactory}.initSchema`, '"initSchema"',
+                                'Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user')
+                        .pc-form-grid-col-60
+                            +text('Create query:', `${blobStoreFactory}.createTableQuery`, '"createTableQuery"', 'false', 'SQL for table creation',
+                                'Query for table creation in underlying database<br/>\
+                                Default value: create table if not exists ENTRIES (key binary primary key, val binary)')
+                        .pc-form-grid-col-60
+                            +text('Load query:', `${blobStoreFactory}.loadQuery`, '"loadQuery"', 'false', 'SQL for load entry',
+                                'Query for entry load from underlying database<br/>\
+                                Default value: select * from ENTRIES where key=?')
+                        .pc-form-grid-col-60
+                            +text('Insert query:', `${blobStoreFactory}.insertQuery`, '"insertQuery"', 'false', 'SQL for insert entry',
+                                'Query for insert entry into underlying database<br/>\
+                                Default value: insert into ENTRIES (key, val) values (?, ?)')
+                        .pc-form-grid-col-60
+                            +text('Update query:', `${blobStoreFactory}.updateQuery`, '"updateQuery"', 'false', 'SQL for update entry',
+                                'Query for update entry in underlying database<br/>\
+                                Default value: update ENTRIES set val=? where key=?')
+                        .pc-form-grid-col-60
+                            +text('Delete query:', `${blobStoreFactory}.deleteQuery`, '"deleteQuery"', 'false', 'SQL for delete entry',
+                                'Query for delete entry from underlying database<br/>\
+                                Default value: delete from ENTRIES where key=?')
+
+                    .pc-form-grid-row(ng-if=`${storeFactoryKind} === 'CacheHibernateBlobStoreFactory'`)
+                        -var hibernateStoreFactory = `${storeFactory}.CacheHibernateBlobStoreFactory`
+
+                        .pc-form-grid-col-60
+                            .ignite-form-field
+                                +ignite-form-field__label('Hibernate properties:', '"hibernateProperties"')
+                                    +tooltip(`List of Hibernate properties<bt />
+                                        For example: connection.url=jdbc:h2:mem:exampleDb`)
+                                .ignite-form-field__control
+                                    +list-pair-edit({
+                                        items: `${hibernateStoreFactory}.hibernateProperties`,
+                                        keyLbl: 'Property name', 
+                                        valLbl: 'Property value',
+                                        itemName: 'property',
+                                        itemsName: 'properties'
+                                    })
+
+                - form = 'store'
+                .pc-form-grid-col-60
                     +checkbox('Keep binary in store', `${model}.storeKeepBinary`, '"storeKeepBinary"',
                         'Flag indicating that CacheStore implementation is working with binary objects instead of Java objects')
-                .settings-row
+                .pc-form-grid-col-60
                     +checkbox('Load previous value', `${model}.loadPreviousValue`, '"loadPreviousValue"',
                         'Flag indicating whether value should be loaded from store if it is not in the cache for following cache operations: \
                         <ul> \
@@ -216,40 +229,85 @@ mixin hibernateField(name, model, items, valid, save, newItem)
                             <li>IgniteCache.getAndReplace()</li> \
                             <li> IgniteCache.getAndPutIfAbsent()</li>\
                         </ul>')
-                .settings-row
-                    +checkbox('Read-through', `${model}.readThrough`, '"readThrough"', 'Flag indicating whether read-through caching should be used')
-                .settings-row
-                    +checkbox('Write-through', `${model}.writeThrough`, '"writeThrough"', 'Flag indicating whether write-through caching should be used')
-                .settings-row
-                    +ignite-form-group
-                        ignite-form-field-label
-                            | Write-behind
-                        ignite-form-group-tooltip
-                            | Cache write-behind settings#[br]
-                            | Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation
-                        .group-content
-                            -var enabled = `${model}.writeBehindEnabled`
-
-                            .details-row
-                                +checkbox('Enabled', enabled, '"writeBehindEnabled"', 'Flag indicating whether Ignite should use write-behind behaviour for the cache store')
-                            .details-row
-                                +number('Batch size:', `${model}.writeBehindBatchSize`, '"writeBehindBatchSize"', enabled, '512', '1',
-                                    'Maximum batch size for write-behind cache store operations<br/>\
-                                     Store operations(get or remove) are combined in a batch of this size to be passed to cache store')
-                            .details-row
-                                +number('Flush size:', `${model}.writeBehindFlushSize`, '"writeBehindFlushSize"', enabled, '10240', '0',
-                                    'Maximum size of the write-behind cache<br/>\
-                                     If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared')
-                            .details-row
-                                +number('Flush frequency:', `${model}.writeBehindFlushFrequency`, '"writeBehindFlushFrequency"', enabled, '5000', '0',
-                                    'Frequency with which write-behind cache is flushed to the cache store in milliseconds')
-                            .details-row
-                                +number('Flush threads count:', `${model}.writeBehindFlushThreadCount`, '"writeBehindFlushThreadCount"', enabled, '1', '1',
-                                    'Number of threads that will perform cache flushing')
-
-                            //- Since ignite 2.0
-                            .details-row(ng-if='$ctrl.available("2.0.0")')
-                                +checkbox-enabled('Write coalescing', model + '.writeBehindCoalescing', '"WriteBehindCoalescing"', enabled, 'Write coalescing flag for write-behind cache store')
-
-            .col-sm-6
+                .pc-form-grid-col-60
+                    +sane-form-field-checkbox({
+                        label: 'Read-through',
+                        model: `${model}.readThrough`,
+                        name: '"readThrough"',
+                        tip: 'Flag indicating whether read-through caching should be used'
+                    })(
+                        ng-model-options='{allowInvalid: true}'
+                        ui-validate=`{
+                            storeEnabledReadOrWriteOn: '$ctrl.Caches.cacheStoreFactory.storeEnabledReadOrWriteOn(${model})'
+                        }`
+                        ui-validate-watch-collection=`"[${storeFactoryKind}, ${model}.writeThrough, ${model}.readThrough]"`
+                    )
+                        +form-field-feedback(0, 'storeEnabledReadOrWriteOn', 'Read or write through should be turned on when store kind is set')
+                .pc-form-grid-col-60
+                    +sane-form-field-checkbox({
+                        label: 'Write-through',
+                        model: `${model}.writeThrough`,
+                        name: '"writeThrough"',
+                        tip: 'Flag indicating whether write-through caching should be used'
+                    })(
+                        ng-model-options='{allowInvalid: true}'
+                        ui-validate=`{
+                            storeEnabledReadOrWriteOn: '$ctrl.Caches.cacheStoreFactory.storeEnabledReadOrWriteOn(${model})'
+                        }`
+                        ui-validate-watch-collection=`"[${storeFactoryKind}, ${model}.writeThrough, ${model}.readThrough]"`
+                    )
+                        +form-field-feedback(0, 'storeEnabledReadOrWriteOn', 'Read or write through should be turned on when store kind is set')
+
+                -var enabled = `${model}.writeBehindEnabled`
+
+                .pc-form-grid-col-60.pc-form-group__text-title
+                    +sane-form-field-checkbox({
+                        label: 'Write-behind',
+                        model: enabled,
+                        name: '"writeBehindEnabled"',
+                        tip: `
+                            Cache write-behind settings.<br>
+                            Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation.
+                        `
+                    })(
+                        ng-model-options='{allowInvalid: true}'
+                    )
+                        +form-field-feedback(0, 'storeDisabledValueOff', 'Write-behind is enabled but store kind is not set')
+                .pc-form-group.pc-form-grid-row(ng-if=enabled)
+                    .pc-form-grid-col-30
+                        +number('Batch size:', `${model}.writeBehindBatchSize`, '"writeBehindBatchSize"', enabled, '512', '1',
+                            'Maximum batch size for write-behind cache store operations<br/>\
+                             Store operations(get or remove) are combined in a batch of this size to be passed to cache store')
+                    .pc-form-grid-col-30
+                        +sane-ignite-form-field-number({
+                            label: 'Flush size:',
+                            model: `${model}.writeBehindFlushSize`,
+                            name: '"writeBehindFlushSize"',
+                            placeholder: '10240',
+                            min: `{{ $ctrl.Caches.writeBehindFlush.min(${model}) }}`,
+                            tip: `Maximum size of the write-behind cache<br/>
+                             If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared`
+                        })(
+                            ng-model-options='{allowInvalid: true}'
+                        )
+                    .pc-form-grid-col-30
+                        +sane-ignite-form-field-number({
+                            label: 'Flush frequency:',
+                            model: `${model}.writeBehindFlushFrequency`,
+                            name: '"writeBehindFlushFrequency"',
+                            placeholder: '5000',
+                            min: `{{ $ctrl.Caches.writeBehindFlush.min(${model}) }}`,
+                            tip: `Frequency with which write-behind cache is flushed to the cache store in milliseconds`
+                        })(
+                            ng-model-options='{allowInvalid: true}'
+                        )
+                    .pc-form-grid-col-30
+                        +number('Flush threads count:', `${model}.writeBehindFlushThreadCount`, '"writeBehindFlushThreadCount"', enabled, '1', '1',
+                            'Number of threads that will perform cache flushing')
+
+                    //- Since ignite 2.0
+                    .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                        +checkbox-enabled('Write coalescing', model + '.writeBehindCoalescing', '"WriteBehindCoalescing"', enabled, 'Write coalescing flag for write-behind cache store')
+
+            .pca-form-column-6
                 +preview-xml-java(model, 'cacheStore', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.pug
index fea8fad..8994fa6 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.pug
@@ -17,24 +17,23 @@
 include /app/helpers/jade/mixins
 
 -var form = 'atomics'
--var model = 'backupItem.atomicConfiguration'
+-var model = '$ctrl.clonedCluster.atomicConfiguration'
 -var affModel = model + '.affinity'
 -var rendezvousAff = affModel + '.kind === "Rendezvous"'
 -var customAff = affModel + '.kind === "Custom"'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
+.pca-panel.pca-panel-default(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Atomic configuration
-        ignite-form-field-tooltip.tipLabel
-            | Configuration for atomic data structures#[br]
-            | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value#[br]
-            | #[a(href="https://apacheignite.readme.io/docs/atomic-types" 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
+        .pca-panel-heading-title Atomic configuration
+        .pca-panel-heading-description
+            | Configuration for atomic data structures.
+            | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value. 
+            | #[a.link-success(href="https://apacheignite.readme.io/docs/atomic-types" target="_blank") More info]
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target='' id=`${form}`)
+        .pca-panel-body(ng-if=`ui.isPanelLoaded('${form}')`).pca-form-row
+            .pca-form-column-6.pc-form-grid-row
+                .pc-form-grid-col-30
                     +dropdown('Cache mode:', `${model}.cacheMode`, '"cacheMode"', 'true', 'PARTITIONED',
                         '[\
                             {value: "LOCAL", label: "LOCAL"},\
@@ -47,33 +46,33 @@ include /app/helpers/jade/mixins
                             <li>Replicated - in this mode all the keys are distributed to all participating nodes</li>\
                             <li>Local - in this mode caches residing on different grid nodes will not know about each other</li>\
                         </ul>')
-                .settings-row
+                .pc-form-grid-col-30
                     +number('Sequence reserve:', `${model}.atomicSequenceReserveSize`, '"atomicSequenceReserveSize"', 'true', '1000', '0',
                         'Default number of sequence values reserved for IgniteAtomicSequence instances<br/>\
                         After a certain number has been reserved, consequent increments of sequence will happen locally, without communication with other nodes, until the next reservation has to be made')
-                .settings-row(ng-show=`!(${model}.cacheMode && ${model}.cacheMode != "PARTITIONED")`)
+                .pc-form-grid-col-60(ng-show=`!(${model}.cacheMode && ${model}.cacheMode != "PARTITIONED")`)
                     +number('Backups:', model + '.backups', '"backups"', 'true', '0', '0', 'Number of backup nodes')
-                div(ng-if='$ctrl.available("2.1.0")')
-                    .settings-row
-                        +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', 'affinityFunction',
-                            'Key topology resolver to provide mapping from keys to nodes\
-                            <ul>\
-                                <li>Rendezvous - Based on Highest Random Weight algorithm<br/></li>\
-                                <li>Custom - Custom implementation of key affinity function<br/></li>\
-                                <li>Default - By default rendezvous affinity function  with 1024 partitions is used<br/></li>\
-                            </ul>')
-                    .panel-details(ng-if=rendezvousAff)
-                        .details-row
+
+                .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.1.0")')
+                    +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', '$ctrl.Clusters.affinityFunctions',
+                        'Key topology resolver to provide mapping from keys to nodes\
+                        <ul>\
+                            <li>Rendezvous - Based on Highest Random Weight algorithm<br/></li>\
+                            <li>Custom - Custom implementation of key affinity function<br/></li>\
+                            <li>Default - By default rendezvous affinity function  with 1024 partitions is used<br/></li>\
+                        </ul>')
+                .pc-form-group(ng-if-end ng-if=rendezvousAff + ' || ' + customAff)
+                    .pc-form-grid-row
+                        .pc-form-grid-col-30(ng-if-start=rendezvousAff)
                             +number-required('Partitions', `${affModel}.Rendezvous.partitions`, '"RendPartitions"', 'true', rendPartitionsRequired, '1024', '1', 'Number of partitions')
-                        .details-row
+                        .pc-form-grid-col-30
                             +java-class('Backup filter', `${affModel}.Rendezvous.affinityBackupFilter`, '"RendAffinityBackupFilter"', 'true', 'false',
                                 'Backups will be selected from all nodes that pass this filter')
-                        .details-row
+                        .pc-form-grid-col-60(ng-if-end)
                             +checkbox('Exclude neighbors', `${affModel}.Rendezvous.excludeNeighbors`, '"RendExcludeNeighbors"',
                                 'Exclude same - host - neighbors from being backups of each other and specified number of backups')
-                    .panel-details(ng-if=customAff)
-                        .details-row
+                        .pc-form-grid-col-60(ng-if=customAff)
                             +java-class('Class name:', `${affModel}.Custom.className`, '"AffCustomClassName"', 'true', customAff,
                                 'Custom key affinity function implementation class name')
-            .col-sm-6
+            .pca-form-column-6
                 +preview-xml-java(model, 'clusterAtomics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.pug
index beb0739..edff038 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.pug
@@ -17,41 +17,28 @@
 include /app/helpers/jade/mixins
 
 -var form = 'attributes'
--var model = 'backupItem'
--var userAttributes = model + '.attributes'
+-var model = '$ctrl.clonedCluster'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
+.pca-panel.pca-panel-default(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label User attributes
-        ignite-form-field-tooltip.tipLabel
-            | Configuration for Ignite user attributes
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .panel-body(ng-if=`ui.isPanelLoaded('${form}')`)
-            .col-sm-6
-                .settings-row
-                    +ignite-form-group(ng-model=`${userAttributes}` ng-form=form)
-                        ignite-form-field-label
-                            | User attributes
-                        ignite-form-group-tooltip
-                            | User-defined attributes to add to node
-                        ignite-form-group-add(ng-click='tableNewItem(attributesTbl)')
-                            | Add user attribute
-                        .group-content-empty(ng-if=`!((${userAttributes} && ${userAttributes}.length > 0) || tableNewItemActive(attributesTbl))`)
-                            | Not defined
-                        .group-content(ng-show=`(${userAttributes} && ${userAttributes}.length > 0) || tableNewItemActive(attributesTbl)`)
-                            table.links-edit(id='attributes' st-table=userAttributes)
-                                tbody
-                                    tr(ng-repeat=`item in ${userAttributes} track by $index`)
-                                        td.col-sm-12(ng-hide='tableEditing(attributesTbl, $index)')
-                                            a.labelFormField(ng-click='tableStartEdit(backupItem, attributesTbl, $index)') {{item.name}} = {{item.value}}
-                                            +btn-remove('tableRemove(backupItem, attributesTbl, $index)', '"Remove attribute"')
-                                        td.col-sm-12(ng-show='tableEditing(attributesTbl, $index)')
-                                            +table-pair-edit('attributesTbl', 'cur', 'Attribute name', 'Attribute value', false, '{{::attributesTbl.focusId + $index}}', '$index', '=')
-                                tfoot(ng-show='tableNewItemActive(attributesTbl)')
-                                    tr
-                                        td.col-sm-12
-                                            +table-pair-edit('attributesTbl', 'new', 'Attribute name', 'Attribute value', false, '{{::attributesTbl.focusId + $index}}', '-1', '=')
-            .col-sm-6
+        .pca-panel-heading-title User attributes
+        .pca-panel-heading-description
+            | Configuration for Ignite user attributes.
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body(ng-if=`ui.isPanelLoaded('${form}')`).pca-form-row
+            .pca-form-column-6
+                .ignite-form-field
+                    +ignite-form-field__label('User attributes:', '"userAttributes"')
+                        +tooltip(`User-defined attributes to add to node`)
+                    .ignite-form-field__control
+                        +list-pair-edit({
+                            items: `${model}.attributes`,
+                            keyLbl: 'Attribute name', 
+                            valLbl: 'Attribute value',
+                            itemName: 'attribute',
+                            itemsName: 'attributes'
+                        })
+
+            .pca-form-column-6
                 +preview-xml-java(model, 'clusterUserAttributes')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.pug
index 2e14e7f..9c3a48d 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.pug
@@ -17,61 +17,67 @@
 include /app/helpers/jade/mixins
 
 -var form = 'binary'
--var model = 'backupItem.binaryConfiguration'
--var types = model + '.typeConfigurations'
+-var model = '$ctrl.clonedCluster.binaryConfiguration'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
+.pca-panel.pca-panel-default(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Binary configuration
-        ignite-form-field-tooltip.tipLabel
-            | Configuration of specific binary types#[br]
-            | #[a(href="https://apacheignite.readme.io/docs/binary-marshaller" 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
+        .pca-panel-heading-title Binary configuration
+        .pca-panel-heading-description
+            | Configuration of specific binary types. 
+            | #[a.link-success(href="https://apacheignite.readme.io/docs/binary-marshaller" target="_blank") More info]
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body(ng-if=`ui.isPanelLoaded('${form}')`).pca-form-row
+            .pca-form-column-6.pc-form-grid-row
+                .pc-form-grid-col-60
                     +java-class('ID mapper:', model + '.idMapper', '"idMapper"', 'true', 'false',
                         'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
                         Ignite never writes full strings for field or type names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
-                .settings-row
+                .pc-form-grid-col-60
                     +java-class('Name mapper:', model + '.nameMapper', '"nameMapper"', 'true', 'false', 'Maps type/class and field names to different names')
-                .settings-row
+                .pc-form-grid-col-60
                     +java-class('Serializer:', model + '.serializer', '"serializer"', 'true', 'false', 'Class with custom serialization logic for binary objects')
-                .settings-row
-                    +ignite-form-group()
-                        ignite-form-field-label
-                            | Type configurations
-                        ignite-form-group-tooltip
-                            | Configuration properties for binary types
-                        ignite-form-group-add(ng-click=`${types}.push({})`)
-                            | Add new type configuration.
-                        .group-content-empty(ng-if=`!${types}.length`)
-                            | Not defined
-                        .group-content(ng-repeat=`model in ${types} track by $index`)
-                            hr(ng-if='$index !== 0')
-                            .settings-row
-                                +java-class-autofocus('Type name:', 'model.typeName', '"typeName" + $index', 'true', 'true', 'true', 'Type name')
-                                    +table-remove-button(types, 'Remove type configuration')
-                            .settings-row
-                                +java-class('ID mapper:', 'model.idMapper', '"idMapper" + $index', 'true', 'false',
-                                    'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
-                                    Ignite never writes full strings for field or type/class names.\
-                                    Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names.\
-                                    It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and,\
-                                    to gain performance, it is safe to work with hash codes.\
-                                    For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
-                            .settings-row
-                                +java-class('Name mapper:', 'model.nameMapper', '"nameMapper" + $index', 'true', 'false',
-                                    'Maps type/class and field names to different names')
-                            .settings-row
-                                +java-class('Serializer:', 'model.serializer', '"serializer" + $index', 'true', 'false',
-                                    'Class with custom serialization logic for binary object')
-                            .settings-row
-                                +checkbox('Enum', 'model.enum', 'enum', 'Flag indicating that this type is the enum')
+                .pc-form-grid-col-60
+                    .ignite-form-field
+                        +ignite-form-field__label('Type configurations:', '"typeŠ”onfigurations"')
+                            +tooltip(`Configuration properties for binary types`)
+                        .ignite-form-field__control
+                            -var items = model + '.typeConfigurations'
+                            list-editable(ng-model=items name='typeŠ”onfigurations')
+                                list-editable-item-edit.pc-form-grid-row
+                                    - form = '$parent.form'
+                                    .pc-form-grid-col-60
+                                        +java-class-autofocus('Type name:', '$item.typeName', '"typeName"', 'true', 'true', 'true', 'Type name')(
+                                            ignite-unique=items
+                                            ignite-unique-property='typeName'
+                                        )
+                                            +unique-feedback(`$item.typeName`, 'Type name should be unique.')
+                                    .pc-form-grid-col-60
+                                        +java-class('ID mapper:', '$item.idMapper', '"idMapper"', 'true', 'false',
+                                            'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
+                                            Ignite never writes full strings for field or type/class names.\
+                                            Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names.\
+                                            It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and,\
+                                            to gain performance, it is safe to work with hash codes.\
+                                            For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
+                                    .pc-form-grid-col-60
+                                        +java-class('Name mapper:', '$item.nameMapper', '"nameMapper"', 'true', 'false',
+                                            'Maps type/class and field names to different names')
+                                    .pc-form-grid-col-60
+                                        +java-class('Serializer:', '$item.serializer', '"serializer"', 'true', 'false',
+                                            'Class with custom serialization logic for binary object')
+                                    .pc-form-grid-col-60
+                                        +checkbox('Enum', '$item.enum', 'enum', 'Flag indicating that this type is the enum')
 
-                .settings-row
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`$ctrl.Clusters.addBinaryTypeConfiguration($ctrl.clonedCluster)`
+                                        label-single='configuration'
+                                        label-multiple='configurations'
+                                    )
+
+                - form = 'binary'
+                .pc-form-grid-col-60
                     +checkbox('Compact footer', model + '.compactFooter', '"compactFooter"', 'When enabled, Ignite will not write fields metadata when serializing objects (this will increase serialization performance), because internally <b>BinaryMarshaller</b> already distribute metadata inside cluster')
-            .col-sm-6
+            .pca-form-column-6
                 +preview-xml-java(model, 'clusterBinary')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.pug
index c2926f5..577d66c 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.pug
@@ -17,34 +17,50 @@
 include /app/helpers/jade/mixins
 
 -var form = 'cacheKeyCfg'
--var model = 'backupItem.cacheKeyConfiguration'
+-var model = '$ctrl.clonedCluster.cacheKeyConfiguration'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
+.pca-panel.pca-panel-default(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Cache key configuration
-        ignite-form-field-tooltip.tipLabel
-            | Cache key configuration allows to collocate objects in a partitioned cache based on field in cache key without explicit usage of annotations on user classes
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .panel-body(ng-if=`ui.isPanelLoaded('${form}')`)
-            .col-sm-6
-                .settings-row
-                    +ignite-form-group()
-                        ignite-form-field-label
-                            | Cache key configuration
-                        ignite-form-group-tooltip
-                            | Cache key configuration
-                        ignite-form-group-add(ng-click=`${model}.push({})`)
-                            | Add new cache key configuration
-                        .group-content-empty(ng-if=`!${model}.length`)
-                            | Not defined
-                        .group-content(ng-repeat=`model in ${model} track by $index`)
-                            hr(ng-if='$index !== 0')
-                            .settings-row
-                                +java-class-autofocus('Type name:', 'model.typeName', '"cacheKeyTypeName" + $index', 'true', 'true', 'true', 'Type name')
-                                    +table-remove-button(model, 'Remove cache key configuration')
-                            .settings-row
-                                +text('Affinity key field name:', 'model.affinityKeyFieldName', '"affinityKeyFieldName" + $index', true, 'Enter field name', 'Affinity key field name')
-            .col-sm-6
+        .pca-panel-heading-title Cache key configuration
+        .pca-panel-heading-description
+            | Cache key configuration allows to collocate objects in a partitioned cache based on field in cache key without explicit usage of annotations on user classes.
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body(ng-if=`ui.isPanelLoaded('${form}')`).pca-form-row
+            .pca-form-column-6
+                mixin clusters-cache-key-cfg
+                    .ignite-form-field
+                        +ignite-form-field__label('Cache key configuration:', '"cacheKeyConfiguration"')
+                        .ignite-form-field__control
+                            -let items = model
+                            list-editable(ng-model=items name='cacheKeyConfiguration')
+                                list-editable-item-edit.pc-form-grid-row
+                                    - form = '$parent.form'
+                                    .pc-form-grid-col-60
+                                        +java-class-autofocus('Type name:', '$item.typeName', '"cacheKeyTypeName"', 'true', 'true', 'true', 'Type name')(
+                                            ignite-unique=items
+                                            ignite-unique-property='typeName'
+                                        )
+                                            +unique-feedback(`cacheKeyTypeName`, 'Type name should be unique.')
+                                    .pc-form-grid-col-60
+                                        +sane-ignite-form-field-text({
+                                            label: 'Affinity key field name:',
+                                            model: '$item.affinityKeyFieldName',
+                                            name: '"affinityKeyFieldName"',
+                                            disabled: 'false',
+                                            placeholder: 'Enter field name',
+                                            tip: 'Affinity key field name',
+                                            required: true
+                                        })
+
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`(${items} = ${items} || []).push({})`
+                                        label-single='configuration'
+                                        label-multiple='configurations'
+                                    )
+
+                +clusters-cache-key-cfg
+
+            .pca-form-column-6
                 +preview-xml-java(model, 'clusterCacheKeyConfiguration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint.pug
index 76778a1..5adb29c 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint.pug
@@ -17,70 +17,69 @@
 include /app/helpers/jade/mixins
 
 -var form = 'checkpoint'
--var model = 'backupItem.checkpointSpi'
--var CustomCheckpoint = 'model.kind === "Custom"'
--var CacheCheckpoint = 'model.kind === "Cache"'
+-var model = '$ctrl.clonedCluster.checkpointSpi'
+-var CustomCheckpoint = '$checkpointSPI.kind === "Custom"'
+-var CacheCheckpoint = '$checkpointSPI.kind === "Cache"'
 
-.panel.panel-default(ng-form=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
+.pca-panel.pca-panel-default(ng-form=form novalidate)
+    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
         ignite-form-panel-chevron
-        label Checkpointing
-        ignite-form-field-tooltip.tipLabel
-            | Checkpointing provides an ability to save an intermediate job state#[br]
-            | #[a(href="https://apacheignite.readme.io/docs/checkpointing" 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='checkpointSpiTbl={type: "checkpointSpi", model: "checkpointSpi", focusId: "kind", ui: "checkpoint-table"}')
-                    +ignite-form-group()
-                        ignite-form-field-label
-                            | Checkpoint SPI configurations
-                        ignite-form-group-tooltip
-                            | Checkpoint SPI configurations
-                        ignite-form-group-add(ng-click='tableNewItem(checkpointSpiTbl)')
-                            | Add checkpoint SPI
-                        .group-content-empty(ng-if=`!(${model} && ${model}.length > 0)`)
-                            | Not defined
-                        .group-content(ng-show=`${model} && ${model}.length > 0` ng-repeat=`model in ${model} track by $index`)
-                            hr(ng-if='$index != 0')
-                            .settings-row
-                                +dropdown-required-autofocus('Checkpoint SPI:', 'model.kind', '"checkpointKind" + $index', 'true', 'true', 'Choose checkpoint configuration variant', '[\
-                                        {value: "FS", label: "File System"},\
-                                        {value: "Cache", label: "Cache"},\
-                                        {value: "S3", label: "Amazon S3"},\
-                                        {value: "JDBC", label: "Database"},\
-                                        {value: "Custom", label: "Custom"}\
-                                    ]',
-                                    'Provides an ability to save an intermediate job state\
-                                    <ul>\
-                                        <li>File System - Uses a shared file system to store checkpoints</li>\
-                                        <li>Cache - Uses a cache to store checkpoints</li>\
-                                        <li>Amazon S3 - Uses Amazon S3 to store checkpoints</li>\
-                                        <li>Database - Uses a database to store checkpoints</li>\
-                                        <li>Custom - Custom checkpoint SPI implementation</li>\
-                                    </ul>')
-                                    +table-remove-button(model, 'Remove Checkpoint SPI')
+        .pca-panel-heading-title Checkpointing
+        .pca-panel-heading-description
+            | Checkpointing provides an ability to save an intermediate job state. 
+            | #[a.link-success(href="https://apacheignite.readme.io/docs/checkpointing" target="_blank") More info]
+    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
+        .pca-panel-body(ng-i_f=`ui.isPanelLoaded('${form}')`).pca-form-row
+            .pca-form-column-6.pc-form-grid-row
+                .pc-form-grid-col-60
+                    .ignite-form-field
+                        +ignite-form-field__label('Checkpoint SPI configurations:', '"checkpointSPIConfigurations"')
+                        .ignite-form-field__control
+                            list-editable(ng-model=model name='checkpointSPIConfigurations')
+                                list-editable-item-edit(item-name='$checkpointSPI').pc-form-grid-row
+                                    .pc-form-grid-col-60
+                                        +dropdown-required('Checkpoint SPI:', '$checkpointSPI.kind', '"checkpointKind"', 'true', 'true', 'Choose checkpoint configuration variant', '[\
+                                                {value: "FS", label: "File System"},\
+                                                {value: "Cache", label: "Cache"},\
+                                                {value: "S3", label: "Amazon S3"},\
+                                                {value: "JDBC", label: "Database"},\
+                                                {value: "Custom", label: "Custom"}\
+                                            ]',
+                                            'Provides an ability to save an intermediate job state\
+                                            <ul>\
+                                                <li>File System - Uses a shared file system to store checkpoints</li>\
+                                                <li>Cache - Uses a cache to store checkpoints</li>\
+                                                <li>Amazon S3 - Uses Amazon S3 to store checkpoints</li>\
+                                                <li>Database - Uses a database to store checkpoints</li>\
+                                                <li>Custom - Custom checkpoint SPI implementation</li>\
+                                            </ul>')
 
-                            div(ng-show='model.kind === "FS"')
-                                include ./checkpoint/fs
+                                    include ./checkpoint/fs
 
-                            div(ng-show=CacheCheckpoint)
-                                .settings-row
-                                    +dropdown-required-empty('Cache:', 'model.Cache.cache', '"checkpointCacheCache" + $index', 'true', CacheCheckpoint,
-                                        'Choose cache', 'No caches configured for current cluster', 'clusterCaches', 'Cache to use for storing checkpoints')
-                                .settings-row
-                                    +java-class('Listener:', 'model.Cache.checkpointListener', '"checkpointCacheListener" + $index', 'true', 'false',
-                                        'Checkpoint listener implementation class name', CacheCheckpoint)
+                                    .pc-form-grid-col-60(ng-if-start=CacheCheckpoint)
+                                        +dropdown-required-empty('Cache:', '$checkpointSPI.Cache.cache', '"checkpointCacheCache"', 'true', CacheCheckpoint,
+                                            'Choose cache', 'No caches configured for current cluster', '$ctrl.cachesMenu', 'Cache to use for storing checkpoints')(
+                                            pc-is-in-collection='$ctrl.clonedCluster.caches'
+                                        )
+                                            +form-field-feedback(form, 'isInCollection', `Cluster doesn't have such a cache`)
+                                    .pc-form-grid-col-60(ng-if-end)
+                                        +java-class('Listener:', '$checkpointSPI.Cache.checkpointListener', '"checkpointCacheListener"', 'true', 'false',
+                                            'Checkpoint listener implementation class name', CacheCheckpoint)
 
-                            div(ng-show='model.kind === "S3"')
-                                include ./checkpoint/s3
+                                    include ./checkpoint/s3
 
-                            div(ng-show='model.kind === "JDBC"')
-                                include ./checkpoint/jdbc
+                                    include ./checkpoint/jdbc
 
-                            .settings-row(ng-show=CustomCheckpoint)
-                                +java-class('Class name:', 'model.Custom.className', '"checkpointCustomClassName" + $index', 'true', CustomCheckpoint,
-                                'Custom CheckpointSpi implementation class', CustomCheckpoint)
-            .col-sm-6
-                +preview-xml-java('backupItem', 'clusterCheckpoint', 'caches')
+                                    .pc-form-grid-col-60(ng-if=CustomCheckpoint)
+                                        +java-class('Class name:', '$checkpointSPI.Custom.className', '"checkpointCustomClassName"', 'true', CustomCheckpoint,
+                                        'Custom CheckpointSpi implementation class', CustomCheckpoint)
+
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`$edit($ctrl.Clusters.addCheckpointSPI($ctrl.clonedCluster))`
+                                        label-single='checkpoint SPI configuration'
+                                        label-multiple='checkpoint SPI configurations'
+                                    )
+            
+            .pca-form-column-6
+                +preview-xml-java('$ctrl.clonedCluster', 'clusterCheckpoint', '$ctrl.caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/fs.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/fs.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/fs.pug
index 04cc7fb..0359cf3 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/fs.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/fs.pug
@@ -16,51 +16,21 @@
 
 include /app/helpers/jade/mixins
 
--var form = 'checkpointFsPaths'
--var dirPaths = 'model.FS.directoryPaths'
-
-.details-row
-    +ignite-form-group(ng-form=form ng-model=dirPaths)
-        -var uniqueTip = 'Such path already exists!'
-
-        ignite-form-field-label
-            | Paths
-        ignite-form-group-tooltip
-            | Paths to a shared directory where checkpoints will be stored
-        ignite-form-group-add(ng-click='(group.add = [{}])')
-            | Add new path
-
-        .group-content(ng-if=`${dirPaths}.length`)
-            -var model = 'obj.model';
-            -var name = '"edit" + $index'
-            -var valid = `${form}[${name}].$valid`
-            -var save = dirPaths + '[$index] = ' + model
-
-            div(ng-repeat=`item in ${dirPaths} track by $index` ng-init='obj = {}')
-                label.col-xs-12.col-sm-12.col-md-12
-                    .indexField
-                        | {{ $index+1 }})
-                    +table-remove-conditional-button(dirPaths, 'true', 'Remove path', 'item')
-                    span(ng-hide='field.edit')
-                        a.labelFormField(ng-click=`(field.edit = true) && (${model} = item)`) {{ item }}
-                    span(ng-if='field.edit')
-                        +table-text-field(name, model, dirPaths, valid, save, 'Input directory path', false)
-                            +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 = dirPaths + '.push(' + model + ')'
-
-            div
-                label.col-xs-12.col-sm-12.col-md-12
-                    +table-text-field(name, model, dirPaths, valid, save, 'Input directory path', true)
-                        +table-save-button(valid, save, true)
-                        +unique-feedback(name, uniqueTip)
-        .group-content-empty(ng-if=`!(${dirPaths}.length) && !group.add.length`)
-            | Not defined
-
-.settings-row
-    +java-class('Listener:', 'model.FS.checkpointListener', '"checkpointFsListener" + $index', 'true', 'false',
-        'Checkpoint listener implementation class name', 'model.kind === "FS"')
+.pc-form-grid-col-60(ng-if-start='$checkpointSPI.kind === "FS"')
+    .ignite-form-field
+        +list-text-field({
+            items: `$checkpointSPI.FS.directoryPaths`,
+            lbl: 'Directory path',
+            name: 'directoryPath',
+            itemName: 'path',
+            itemsName: 'paths'
+        })(
+            list-editable-cols=`::[{
+                name: 'Paths:',
+                tip: 'Paths to a shared directory where checkpoints will be stored'
+            }]`
+        )
+            +unique-feedback(_, 'Such path already exists!')
+
+.pc-form-grid-col-60(ng-if-end)
+    +java-class('Listener:', '$checkpointSPI.FS.checkpointListener', '"checkpointFsListener"', 'true', 'false', 'Checkpoint listener implementation class name', '$checkpointSPI.kind === "FS"')

http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/jdbc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/jdbc.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/jdbc.pug
index ea67977..d1d202d 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/jdbc.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/checkpoint/jdbc.pug
@@ -16,33 +16,32 @@
 
 include /app/helpers/jade/mixins
 
--var jdbcCheckpoint = 'model.kind === "JDBC"'
+-var jdbcCheckpoint = '$checkpointSPI.kind === "JDBC"'
 
-.settings-row
-    +text('Data source bean name:', 'model.JDBC.dataSourceBean', '"checkpointJdbcDataSourceBean" + $index', jdbcCheckpoint, 'Input bean name',
+.pc-form-grid-col-30(ng-if-start='$checkpointSPI.kind === "JDBC"')
+    +text('Data source bean name:', '$checkpointSPI.JDBC.dataSourceBean', '"checkpointJdbcDataSourceBean"', jdbcCheckpoint, 'Input bean name',
     'Name of the data source bean in Spring context')
-.settings-row
-    +dialect('Dialect:', 'model.JDBC.dialect', '"checkpointJdbcDialect" + $index', jdbcCheckpoint,
+.pc-form-grid-col-30
+    +dialect('Dialect:', '$checkpointSPI.JDBC.dialect', '"checkpointJdbcDialect"', jdbcCheckpoint,
     'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect', 'Choose JDBC dialect')
-.settings-row
-    +java-class('Listener:', 'model.JDBC.checkpointListener', '"checkpointJdbcListener" + $index', 'true', 'false',
+.pc-form-grid-col-60
+    +java-class('Listener:', '$checkpointSPI.JDBC.checkpointListener', '"checkpointJdbcListener"', 'true', 'false',
         'Checkpoint listener implementation class name', jdbcCheckpoint)
-+showHideLink('jdbcExpanded', 'settings')
-    .details-row
-        +text('User:', 'model.JDBC.user', '"checkpointJdbcUser" + $index', 'false', 'Input user name', 'Checkpoint jdbc user name')
-    .details-row
-        +text('Table name:', 'model.JDBC.checkpointTableName', '"checkpointJdbcCheckpointTableName" + $index', 'false', 'CHECKPOINTS', 'Checkpoint table name')
-    .details-row
-        +text('Key field name:', 'model.JDBC.keyFieldName', '"checkpointJdbcKeyFieldName" + $index', 'false', 'NAME', 'Checkpoint key field name')
-    .details-row
-        +dropdown('Key field type:', 'model.JDBC.keyFieldType', '"checkpointJdbcKeyFieldType" + $index', 'true', 'VARCHAR', 'supportedJdbcTypes', 'Checkpoint key field type')
-    .details-row
-        +text('Value field name:', 'model.JDBC.valueFieldName', '"checkpointJdbcValueFieldName" + $index', 'false', 'VALUE', 'Checkpoint value field name')
-    .details-row
-        +dropdown('Value field type:', 'model.JDBC.valueFieldType', '"checkpointJdbcValueFieldType" + $index', 'true', 'BLOB', 'supportedJdbcTypes', 'Checkpoint value field type')
-    .details-row
-        +text('Expire date field name:', 'model.JDBC.expireDateFieldName', '"checkpointJdbcExpireDateFieldName" + $index', 'false', 'EXPIRE_DATE', 'Checkpoint expire date field name')
-    .details-row
-        +dropdown('Expire date field type:', 'model.JDBC.expireDateFieldType', '"checkpointJdbcExpireDateFieldType"', 'true', 'DATETIME', 'supportedJdbcTypes', 'Checkpoint expire date field type')
-    .details-row
-        +number('Number of retries:', 'model.JDBC.numberOfRetries', '"checkpointJdbcNumberOfRetries"', 'true', '2', '0', 'Number of retries in case of DB failure')
+.pc-form-grid-col-60
+    +text('User:', '$checkpointSPI.JDBC.user', '"checkpointJdbcUser"', 'false', 'Input user name', 'Checkpoint jdbc user name')
+.pc-form-grid-col-30
+    +text('Table name:', '$checkpointSPI.JDBC.checkpointTableName', '"checkpointJdbcCheckpointTableName"', 'false', 'CHECKPOINTS', 'Checkpoint table name')
+.pc-form-grid-col-30
+    +text('Key field name:', '$checkpointSPI.JDBC.keyFieldName', '"checkpointJdbcKeyFieldName"', 'false', 'NAME', 'Checkpoint key field name')
+.pc-form-grid-col-30
+    +dropdown('Key field type:', '$checkpointSPI.JDBC.keyFieldType', '"checkpointJdbcKeyFieldType"', 'true', 'VARCHAR', '::$ctrl.supportedJdbcTypes', 'Checkpoint key field type')
+.pc-form-grid-col-30
+    +text('Value field name:', '$checkpointSPI.JDBC.valueFieldName', '"checkpointJdbcValueFieldName"', 'false', 'VALUE', 'Checkpoint value field name')
+.pc-form-grid-col-30
+    +dropdown('Value field type:', '$checkpointSPI.JDBC.valueFieldType', '"checkpointJdbcValueFieldType"', 'true', 'BLOB', '::$ctrl.supportedJdbcTypes', 'Checkpoint value field type')
+.pc-form-grid-col-30
+    +text('Expire date field name:', '$checkpointSPI.JDBC.expireDateFieldName', '"checkpointJdbcExpireDateFieldName"', 'false', 'EXPIRE_DATE', 'Checkpoint expire date field name')
+.pc-form-grid-col-30
+    +dropdown('Expire date field type:', '$checkpointSPI.JDBC.expireDateFieldType', '"checkpointJdbcExpireDateFieldType"', 'true', 'DATETIME', '::$ctrl.supportedJdbcTypes', 'Checkpoint expire date field type')
+.pc-form-grid-col-30(ng-if-end)
+    +number('Number of retries:', '$checkpointSPI.JDBC.numberOfRetries', '"checkpointJdbcNumberOfRetries"', 'true', '2', '0', 'Number of retries in case of DB failure')