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/05 07:09:35 UTC

[1/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Repository: ignite
Updated Branches:
  refs/heads/master ca75df181 -> d24dab813


http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.pug
index 7d5052e..a8194c2 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.pug
@@ -19,22 +19,19 @@ include /app/helpers/jade/mixins
 -var form = 'fragmentizer'
 -var model = 'backupItem'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Fragmentizer
-    .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 enabled = `${model}.fragmentizerEnabled`
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Fragmentizer
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            -var enabled = `${model}.fragmentizerEnabled`
 
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', enabled, '"fragmentizerEnabled"', 'Fragmentizer enabled flag')
-                .pc-form-grid-col-30
-                    +number('Concurrent files:', `${model}.fragmentizerConcurrentFiles`, '"fragmentizerConcurrentFiles"', enabled, '0', '0', 'Number of files to process concurrently by fragmentizer')
-                .pc-form-grid-col-30
-                    +number('Throttling block length:', `${model}.fragmentizerThrottlingBlockLength`, '"fragmentizerThrottlingBlockLength"', enabled, '16777216', '1', 'Length of file chunk to transmit before throttling is delayed')
-                .pc-form-grid-col-60
-                    +number('Throttling delay:', `${model}.fragmentizerThrottlingDelay`, '"fragmentizerThrottlingDelay"', enabled, '200', '0', 'Delay in milliseconds for which fragmentizer is paused')
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsFragmentizer')
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"fragmentizerEnabled"', 'Fragmentizer enabled flag')
+            .pc-form-grid-col-30
+                +number('Concurrent files:', `${model}.fragmentizerConcurrentFiles`, '"fragmentizerConcurrentFiles"', enabled, '0', '0', 'Number of files to process concurrently by fragmentizer')
+            .pc-form-grid-col-30
+                +number('Throttling block length:', `${model}.fragmentizerThrottlingBlockLength`, '"fragmentizerThrottlingBlockLength"', enabled, '16777216', '1', 'Length of file chunk to transmit before throttling is delayed')
+            .pc-form-grid-col-60
+                +number('Throttling delay:', `${model}.fragmentizerThrottlingDelay`, '"fragmentizerThrottlingDelay"', enabled, '200', '0', 'Delay in milliseconds for which fragmentizer is paused')
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsFragmentizer')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/general.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/general.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/general.pug
index 9f65f41..b9eb8fc 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/general.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/general.pug
@@ -19,57 +19,54 @@ include /app/helpers/jade/mixins
 -var form = 'general'
 -var model = 'backupItem'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title General
-        .pca-panel-heading-description
-            | General IGFS configuration. 
-            a.link-success(href="https://apacheignite-fs.readme.io/docs/in-memory-file-system" target="_blank") More info
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id='general')
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +sane-ignite-form-field-text({
-                        label: 'Name:',
-                        model: `${model}.name`,
-                        name: '"igfsName"',
-                        placeholder: 'Input name',
-                        required: true
-                    })(
-                        ignite-unique='$ctrl.igfss'
-                        ignite-unique-property='name'
-                        ignite-unique-skip=`["_id", ${model}]`
-                    )
-                        +unique-feedback(`${model}.name`, 'IGFS name should be unique.')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-dropdown({
-                        label: 'IGFS mode:',
-                        model: `${model}.defaultMode`,
-                        name: '"defaultMode"',
-                        placeholder: '{{::$ctrl.IGFSs.defaultMode.default}}',
-                        options: '{{::$ctrl.IGFSs.defaultMode.values}}',
-                        tip: `
-                        Mode to specify how IGFS interacts with Hadoop file system
-                        <ul>
-                            <li>PRIMARY - in this mode IGFS will not delegate to secondary Hadoop file system and will cache all the files in memory only</li>
-                            <li>PROXY - in this mode IGFS will not cache any files in memory and will only pass them through to secondary file system</li>
-                            <li>DUAL_SYNC - in this mode IGFS will cache files locally and also <b>synchronously</b> write them through to secondary file system</li>
-                            <li>DUAL_ASYNC - in this mode IGFS will cache files locally and also <b> asynchronously </b> write them through to secondary file system</li>
-                        </ul>
-                        `
-                    })
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Group size:',
-                        model: `${model}.affinnityGroupSize`,
-                        name: '"affinnityGroupSize"',
-                        placeholder: '{{::$ctrl.IGFSs.affinnityGroupSize.default}}',
-                        min: '{{::$ctrl.IGFSs.affinnityGroupSize.min}}',
-                        tip: `
-                            Size of the group in blocks<br/>
-                            Required for construction of affinity mapper in IGFS data cache
-                        `
-                    })
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsGeneral')
+panel-collapsible(opened=`::true` ng-form=form)
+    panel-title General
+    panel-description
+        | General IGFS configuration. 
+        a.link-success(href="https://apacheignite-fs.readme.io/docs/in-memory-file-system" target="_blank") More info
+    panel-content.pca-form-row
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +sane-ignite-form-field-text({
+                    label: 'Name:',
+                    model: `${model}.name`,
+                    name: '"igfsName"',
+                    placeholder: 'Input name',
+                    required: true
+                })(
+                    ignite-unique='$ctrl.igfss'
+                    ignite-unique-property='name'
+                    ignite-unique-skip=`["_id", ${model}]`
+                )
+                    +unique-feedback(`${model}.name`, 'IGFS name should be unique.')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-dropdown({
+                    label: 'IGFS mode:',
+                    model: `${model}.defaultMode`,
+                    name: '"defaultMode"',
+                    placeholder: '{{::$ctrl.IGFSs.defaultMode.default}}',
+                    options: '{{::$ctrl.IGFSs.defaultMode.values}}',
+                    tip: `
+                    Mode to specify how IGFS interacts with Hadoop file system
+                    <ul>
+                        <li>PRIMARY - in this mode IGFS will not delegate to secondary Hadoop file system and will cache all the files in memory only</li>
+                        <li>PROXY - in this mode IGFS will not cache any files in memory and will only pass them through to secondary file system</li>
+                        <li>DUAL_SYNC - in this mode IGFS will cache files locally and also <b>synchronously</b> write them through to secondary file system</li>
+                        <li>DUAL_ASYNC - in this mode IGFS will cache files locally and also <b> asynchronously </b> write them through to secondary file system</li>
+                    </ul>
+                    `
+                })
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Group size:',
+                    model: `${model}.affinnityGroupSize`,
+                    name: '"affinnityGroupSize"',
+                    placeholder: '{{::$ctrl.IGFSs.affinnityGroupSize.default}}',
+                    min: '{{::$ctrl.IGFSs.affinnityGroupSize.min}}',
+                    tip: `
+                        Size of the group in blocks<br/>
+                        Required for construction of affinity mapper in IGFS data cache
+                    `
+                })
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.pug
index e123b3c..ef024b4 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.pug
@@ -19,40 +19,37 @@ include /app/helpers/jade/mixins
 -var form = 'ipc'
 -var model = 'backupItem'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title IPC
-        .pca-panel-heading-description IGFS Inter-process communication properties.
-    .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 ipcEndpointConfiguration = `${model}.ipcEndpointConfiguration`
-                -var enabled = `${model}.ipcEndpointEnabled`
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title IPC
+    panel-description IGFS Inter-process communication properties.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            -var ipcEndpointConfiguration = `${model}.ipcEndpointConfiguration`
+            -var enabled = `${model}.ipcEndpointEnabled`
 
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', enabled, '"ipcEndpointEnabled"', 'IPC endpoint enabled flag')
-                .pc-form-grid-col-60
-                    +dropdown('Type:', `${ipcEndpointConfiguration}.type`, '"ipcEndpointConfigurationType"', enabled, 'TCP',
-                        '[\
-                            {value: "SHMEM", label: "SHMEM"},\
-                            {value: "TCP", label: "TCP"}\
-                        ]',
-                        'IPC endpoint type\
-                        <ul>\
-                            <li>SHMEM - shared memory endpoint</li>\
-                            <li>TCP - TCP endpoint</li>\
-                        </ul>')
-                .pc-form-grid-col-30
-                    +text-ip-address('Host:', `${ipcEndpointConfiguration}.host`, '"ipcEndpointConfigurationHost"', enabled, '127.0.0.1', 'Host endpoint is bound to')
-                .pc-form-grid-col-30
-                    +number-min-max('Port:', `${ipcEndpointConfiguration}.port`, '"ipcEndpointConfigurationPort"', enabled, '10500', '1', '65535', 'Port endpoint is bound to')
-                .pc-form-grid-col-30
-                    +number('Memory size:', `${ipcEndpointConfiguration}.memorySize`, '"ipcEndpointConfigurationMemorySize"', enabled, '262144', '1', 'Shared memory size in bytes allocated for endpoint communication')
-                .pc-form-grid-col-30
-                    +number('Thread count:', `${ipcEndpointConfiguration}.threadCount`, '"ipcEndpointConfigurationThreadCount"', enabled, 'availableProcessors', '1',
-                        'Number of threads used by this endpoint to process incoming requests')
-                .pc-form-grid-col-60
-                    +text-enabled('Token directory:', `${ipcEndpointConfiguration}.tokenDirectoryPath`, '"ipcEndpointConfigurationTokenDirectoryPath"', enabled, 'false', 'ipc/shmem', 'Directory where shared memory tokens are stored')
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsIPC')
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"ipcEndpointEnabled"', 'IPC endpoint enabled flag')
+            .pc-form-grid-col-60
+                +dropdown('Type:', `${ipcEndpointConfiguration}.type`, '"ipcEndpointConfigurationType"', enabled, 'TCP',
+                    '[\
+                        {value: "SHMEM", label: "SHMEM"},\
+                        {value: "TCP", label: "TCP"}\
+                    ]',
+                    'IPC endpoint type\
+                    <ul>\
+                        <li>SHMEM - shared memory endpoint</li>\
+                        <li>TCP - TCP endpoint</li>\
+                    </ul>')
+            .pc-form-grid-col-30
+                +text-ip-address('Host:', `${ipcEndpointConfiguration}.host`, '"ipcEndpointConfigurationHost"', enabled, '127.0.0.1', 'Host endpoint is bound to')
+            .pc-form-grid-col-30
+                +number-min-max('Port:', `${ipcEndpointConfiguration}.port`, '"ipcEndpointConfigurationPort"', enabled, '10500', '1', '65535', 'Port endpoint is bound to')
+            .pc-form-grid-col-30
+                +number('Memory size:', `${ipcEndpointConfiguration}.memorySize`, '"ipcEndpointConfigurationMemorySize"', enabled, '262144', '1', 'Shared memory size in bytes allocated for endpoint communication')
+            .pc-form-grid-col-30
+                +number('Thread count:', `${ipcEndpointConfiguration}.threadCount`, '"ipcEndpointConfigurationThreadCount"', enabled, 'availableProcessors', '1',
+                    'Number of threads used by this endpoint to process incoming requests')
+            .pc-form-grid-col-60
+                +text-enabled('Token directory:', `${ipcEndpointConfiguration}.tokenDirectoryPath`, '"ipcEndpointConfigurationTokenDirectoryPath"', enabled, 'false', 'ipc/shmem', 'Directory where shared memory tokens are stored')
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsIPC')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.pug
index 63e5e46..9a39b3a 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.pug
@@ -20,94 +20,91 @@ include /app/helpers/jade/mixins
 -var model = 'backupItem'
 -var pathModes = `${model}.pathModes`
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Miscellaneous
-        .pca-panel-heading-description Various miscellaneous IGFS 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
-                    +number('Block size:', `${model}.blockSize`, '"blockSize"', 'true', '65536', '0', 'File data block size in bytes')
-
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +number('Buffer size:', `${model}.streamBufferSize`, '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes')
-
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Stream buffer size:', `${model}.streamBufferSize`, '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes')
-                .pc-form-grid-col-60(ng-if-end)
-                    +number('Maximum space size:', `${model}.maxSpaceSize`, '"maxSpaceSize"', 'true', '0', '0', 'Maximum space available for data cache to store file system entries')
-
-                .pc-form-grid-col-30
-                    +number('Maximum task range length:', `${model}.maximumTaskRangeLength`, '"maximumTaskRangeLength"', 'true', '0', '0', 'Maximum default range size of a file being split during IGFS task execution')
-                .pc-form-grid-col-30
-                    +number-min-max('Management port:', `${model}.managementPort`, '"managementPort"', 'true', '11400', '0', '65535', 'Port number for management endpoint')
-                .pc-form-grid-col-30
-                    +number('Per node batch size:', `${model}.perNodeBatchSize`, '"perNodeBatchSize"', 'true', '100', '0', 'Number of file blocks collected on local node before sending batch to remote node')
-                .pc-form-grid-col-30
-                    +number('Per node parallel batch count:', `${model}.perNodeParallelBatchCount`, '"perNodeParallelBatchCount"', 'true', '8', '0', 'Number of file block batches that can be concurrently sent to remote node')
-                .pc-form-grid-col-60
-                    +number('Prefetch blocks:', `${model}.prefetchBlocks`, '"prefetchBlocks"', 'true', '0', '0', 'Number of pre-fetched blocks if specific file chunk is requested')
-                .pc-form-grid-col-60
-                    +number('Sequential reads before prefetch:', `${model}.sequentialReadsBeforePrefetch`, '"sequentialReadsBeforePrefetch"', 'true', '0', '0', 'Amount of sequential block reads before prefetch is triggered')
-
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Trash purge timeout:', `${model}.trashPurgeTimeout`, '"trashPurgeTimeout"', 'true', '1000', '0', 'Maximum timeout awaiting for trash purging in case data cache oversize is detected')
-
-                .pc-form-grid-col-60
-                    +checkbox('Colocate metadata', `${model}.colocateMetadata`, '"colocateMetadata"', 'Whether to co-locate metadata on a single node')
-                .pc-form-grid-col-60
-                    +checkbox('Relaxed consistency', `${model}.relaxedConsistency`, '"relaxedConsistency"',
-                        'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks<br/>\
-                        It is recommended to set this flag to <b>false</b> if your application has conflicting\
-                        operations, or you do not know how exactly users will use your system')
-
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +checkbox('Update file length on flush', model + '.updateFileLengthOnFlush', '"updateFileLengthOnFlush"', 'Update file length on flush flag')
-
-                .pc-form-grid-col-60
-                    mixin igfs-misc-path-modes
-                        .ignite-form-field
-                            +ignite-form-field__label('Path modes:', '"pathModes"')
-                                +tooltip(`Map of path prefixes to IGFS modes used for them`)
-                            .ignite-form-field__control
-                                -let items = pathModes
-
-                                list-editable(ng-model=items)
-                                    list-editable-item-view
-                                        | {{ $item.path + " [" + $item.mode + "]"}}
-
-                                    list-editable-item-edit
-                                        - form = '$parent.form'
-
-                                        .pc-form-grid-row
-                                            .pc-form-grid-col-30
-                                                +ignite-form-field-text('Path:', '$item.path', '"path"', false, true, 'Enter path')(ignite-auto-focus)
-                                            .pc-form-grid-col-30
-                                                +sane-ignite-form-field-dropdown({
-                                                    label: 'Mode:',
-                                                    model: `$item.mode`,
-                                                    name: '"mode"',
-                                                    required: true,
-                                                    placeholder: 'Choose igfs mode',
-                                                    options: '{{::$ctrl.IGFSs.defaultMode.values}}'
-                                                })(
-                                                    ng-model-options='{allowInvalid: true}'
-                                                )
-
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${items} = ${items} || []).push({}))`
-                                            label-single='path mode'
-                                            label-multiple='path modes'
-                                        )
-
-                    +igfs-misc-path-modes
-
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsMisc')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Miscellaneous
+    panel-description Various miscellaneous IGFS settings.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +number('Block size:', `${model}.blockSize`, '"blockSize"', 'true', '65536', '0', 'File data block size in bytes')
+
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +number('Buffer size:', `${model}.streamBufferSize`, '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes')
+
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Stream buffer size:', `${model}.streamBufferSize`, '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes')
+            .pc-form-grid-col-60(ng-if-end)
+                +number('Maximum space size:', `${model}.maxSpaceSize`, '"maxSpaceSize"', 'true', '0', '0', 'Maximum space available for data cache to store file system entries')
+
+            .pc-form-grid-col-30
+                +number('Maximum task range length:', `${model}.maximumTaskRangeLength`, '"maximumTaskRangeLength"', 'true', '0', '0', 'Maximum default range size of a file being split during IGFS task execution')
+            .pc-form-grid-col-30
+                +number-min-max('Management port:', `${model}.managementPort`, '"managementPort"', 'true', '11400', '0', '65535', 'Port number for management endpoint')
+            .pc-form-grid-col-30
+                +number('Per node batch size:', `${model}.perNodeBatchSize`, '"perNodeBatchSize"', 'true', '100', '0', 'Number of file blocks collected on local node before sending batch to remote node')
+            .pc-form-grid-col-30
+                +number('Per node parallel batch count:', `${model}.perNodeParallelBatchCount`, '"perNodeParallelBatchCount"', 'true', '8', '0', 'Number of file block batches that can be concurrently sent to remote node')
+            .pc-form-grid-col-60
+                +number('Prefetch blocks:', `${model}.prefetchBlocks`, '"prefetchBlocks"', 'true', '0', '0', 'Number of pre-fetched blocks if specific file chunk is requested')
+            .pc-form-grid-col-60
+                +number('Sequential reads before prefetch:', `${model}.sequentialReadsBeforePrefetch`, '"sequentialReadsBeforePrefetch"', 'true', '0', '0', 'Amount of sequential block reads before prefetch is triggered')
+
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Trash purge timeout:', `${model}.trashPurgeTimeout`, '"trashPurgeTimeout"', 'true', '1000', '0', 'Maximum timeout awaiting for trash purging in case data cache oversize is detected')
+
+            .pc-form-grid-col-60
+                +checkbox('Colocate metadata', `${model}.colocateMetadata`, '"colocateMetadata"', 'Whether to co-locate metadata on a single node')
+            .pc-form-grid-col-60
+                +checkbox('Relaxed consistency', `${model}.relaxedConsistency`, '"relaxedConsistency"',
+                    'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks<br/>\
+                    It is recommended to set this flag to <b>false</b> if your application has conflicting\
+                    operations, or you do not know how exactly users will use your system')
+
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +checkbox('Update file length on flush', model + '.updateFileLengthOnFlush', '"updateFileLengthOnFlush"', 'Update file length on flush flag')
+
+            .pc-form-grid-col-60
+                mixin igfs-misc-path-modes
+                    .ignite-form-field
+                        +ignite-form-field__label('Path modes:', '"pathModes"')
+                            +tooltip(`Map of path prefixes to IGFS modes used for them`)
+                        .ignite-form-field__control
+                            -let items = pathModes
+
+                            list-editable(ng-model=items)
+                                list-editable-item-view
+                                    | {{ $item.path + " [" + $item.mode + "]"}}
+
+                                list-editable-item-edit
+                                    - form = '$parent.form'
+
+                                    .pc-form-grid-row
+                                        .pc-form-grid-col-30
+                                            +ignite-form-field-text('Path:', '$item.path', '"path"', false, true, 'Enter path')(ignite-auto-focus)
+                                        .pc-form-grid-col-30
+                                            +sane-ignite-form-field-dropdown({
+                                                label: 'Mode:',
+                                                model: `$item.mode`,
+                                                name: '"mode"',
+                                                required: true,
+                                                placeholder: 'Choose igfs mode',
+                                                options: '{{::$ctrl.IGFSs.defaultMode.values}}'
+                                            })(
+                                                ng-model-options='{allowInvalid: true}'
+                                            )
+
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`$editLast((${items} = ${items} || []).push({}))`
+                                        label-single='path mode'
+                                        label-multiple='path modes'
+                                    )
+
+                +igfs-misc-path-modes
+
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsMisc')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.pug
index da34596..92c8210 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.pug
@@ -19,40 +19,37 @@ include /app/helpers/jade/mixins
 -var form = 'secondaryFileSystem'
 -var model = 'backupItem'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Secondary file system
-        .pca-panel-heading-description
-            | Secondary file system is provided for pass-through, write-through, and read-through purposes. 
-            a.link-success(href="https://apacheignite-fs.readme.io/docs/secondary-file-system" 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 enabled = `${model}.secondaryFileSystemEnabled`
-                -var secondaryFileSystem = `${model}.secondaryFileSystem`
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Secondary file system
+    panel-description
+        | Secondary file system is provided for pass-through, write-through, and read-through purposes. 
+        a.link-success(href="https://apacheignite-fs.readme.io/docs/secondary-file-system" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            -var enabled = `${model}.secondaryFileSystemEnabled`
+            -var secondaryFileSystem = `${model}.secondaryFileSystem`
 
-                .pc-form-grid-col-60
-                    +sane-form-field-checkbox({
-                        label: 'Enabled',
-                        name: '"secondaryFileSystemEnabled"',
-                        model: enabled
-                    })(
-                        ng-model-options='{allowInvalid: true}'
-                        ui-validate=`{
-                            requiredWhenIGFSProxyMode: '$ctrl.IGFSs.secondaryFileSystemEnabled.requiredWhenIGFSProxyMode(${model})',
-                            requiredWhenPathModeProxyMode: '$ctrl.IGFSs.secondaryFileSystemEnabled.requiredWhenPathModeProxyMode(${model})'
-                        }`
-                        ui-validate-watch-collection=`"[${model}.defaultMode, ${model}.pathModes]"`
-                        ui-validate-watch-object-equality='true'
-                    )
-                        +form-field-feedback(null, 'requiredWhenIGFSProxyMode', 'Secondary file system should be configured for "PROXY" IGFS mode')
-                        +form-field-feedback(null, 'requiredWhenPathModeProxyMode', 'Secondary file system should be configured for "PROXY" path mode')
-                .pc-form-grid-col-60
-                    +text-enabled('URI:', `${secondaryFileSystem}.uri`, '"hadoopURI"', enabled, 'false', 'hdfs://[namenodehost]:[port]/[path]', 'URI of file system')
-                .pc-form-grid-col-60
-                    +text-enabled('Config path:', `${secondaryFileSystem}.cfgPath`, '"cfgPath"', enabled, 'false', 'Path to additional config', 'Additional path to Hadoop configuration')
-                .pc-form-grid-col-60
-                    +text-enabled('User name:', `${secondaryFileSystem}.userName`, '"userName"', enabled, 'false', 'Input user name', 'User name')
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsSecondFS')
+            .pc-form-grid-col-60
+                +sane-form-field-checkbox({
+                    label: 'Enabled',
+                    name: '"secondaryFileSystemEnabled"',
+                    model: enabled
+                })(
+                    ng-model-options='{allowInvalid: true}'
+                    ui-validate=`{
+                        requiredWhenIGFSProxyMode: '$ctrl.IGFSs.secondaryFileSystemEnabled.requiredWhenIGFSProxyMode(${model})',
+                        requiredWhenPathModeProxyMode: '$ctrl.IGFSs.secondaryFileSystemEnabled.requiredWhenPathModeProxyMode(${model})'
+                    }`
+                    ui-validate-watch-collection=`"[${model}.defaultMode, ${model}.pathModes]"`
+                    ui-validate-watch-object-equality='true'
+                )
+                    +form-field-feedback(null, 'requiredWhenIGFSProxyMode', 'Secondary file system should be configured for "PROXY" IGFS mode')
+                    +form-field-feedback(null, 'requiredWhenPathModeProxyMode', 'Secondary file system should be configured for "PROXY" path mode')
+            .pc-form-grid-col-60
+                +text-enabled('URI:', `${secondaryFileSystem}.uri`, '"hadoopURI"', enabled, 'false', 'hdfs://[namenodehost]:[port]/[path]', 'URI of file system')
+            .pc-form-grid-col-60
+                +text-enabled('Config path:', `${secondaryFileSystem}.cfgPath`, '"cfgPath"', enabled, 'false', 'Path to additional config', 'Additional path to Hadoop configuration')
+            .pc-form-grid-col-60
+                +text-enabled('User name:', `${secondaryFileSystem}.userName`, '"userName"', enabled, 'false', 'Input user name', 'User name')
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsSecondFS')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/package-lock.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package-lock.json b/modules/web-console/frontend/package-lock.json
index f7f313d..071dec0 100644
--- a/modules/web-console/frontend/package-lock.json
+++ b/modules/web-console/frontend/package-lock.json
@@ -39,6 +39,15 @@
         "@types/angular": "1.6.43"
       }
     },
+    "@types/angular-mocks": {
+      "version": "1.5.11",
+      "resolved": "https://registry.npmjs.org/@types/angular-mocks/-/angular-mocks-1.5.11.tgz",
+      "integrity": "sha512-C8ipXVKQvw+w64kH97Npa3a7uZB7ZL9Kr4+sOe33oYIyxeg09M8bzAWCIYCmPRRV0px6ozFTZeSVjBXDikz2zw==",
+      "dev": true,
+      "requires": {
+        "@types/angular": "1.6.43"
+      }
+    },
     "@types/angular-strap": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/@types/angular-strap/-/angular-strap-2.3.1.tgz",
@@ -85,12 +94,41 @@
       "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==",
       "dev": true
     },
+    "@types/node": {
+      "version": "9.6.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.2.tgz",
+      "integrity": "sha512-UWkRY9X7RQHp5OhhRIIka58/gVVycL1zHZu0OTsT5LI86ABaMOSbUjAl+b0FeDhQcxclrkyft3kW5QWdMRs8wQ==",
+      "dev": true
+    },
     "@types/sinon": {
       "version": "4.3.1",
       "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.1.tgz",
       "integrity": "sha512-DK4YtH30I67k4klURIBS4VAe1aBISfS9lgNlHFkibSmKem2tLQc5VkKoJreT3dCJAd+xRyCS8bx1o97iq3yUVg==",
       "dev": true
     },
+    "@types/tapable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.1.tgz",
+      "integrity": "sha512-zRc13uGALq6rmLOYmpdI8X5TK6ATuf9jITC7iKTxaHqb/se7vBdiC8BEp1vM2VJQVSt3N53kDDzJOYeVkUKO/Q==",
+      "dev": true
+    },
+    "@types/uglify-js": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.1.tgz",
+      "integrity": "sha512-eWwNO88HxJonNKyxZ3dR62yle3N+aBPIsjTrPtoMcldLXGeIKAIlewNIWT4cxjZ4gy3YdBobkaKSv74HJXSzRg==",
+      "dev": true,
+      "requires": {
+        "source-map": "0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
     "@types/ui-grid": {
       "version": "0.0.38",
       "resolved": "https://registry.npmjs.org/@types/ui-grid/-/ui-grid-0.0.38.tgz",
@@ -101,6 +139,35 @@
         "@types/jquery": "3.3.1"
       }
     },
+    "@types/webpack": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.1.3.tgz",
+      "integrity": "sha512-NoGVTCumOsyFfuy3934f3ktiJi+wcXHJFxT47tby3iCpuo6M/WjFA9VqT5bYO+FE46i3R0N00RpJX75HxHKDaQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "9.6.2",
+        "@types/tapable": "1.0.1",
+        "@types/uglify-js": "3.0.1",
+        "source-map": "0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "@types/webpack-merge": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/@types/webpack-merge/-/webpack-merge-4.1.3.tgz",
+      "integrity": "sha512-VdmNuYIvIouYlCI73NLKOE1pOVAxv5m5eupvTemojZz9dqghoQXmeEveI6CqeuWpCH6x6FLp6+tXM2sls20/MA==",
+      "dev": true,
+      "requires": {
+        "@types/webpack": "4.1.3"
+      }
+    },
     "@uirouter/angularjs": {
       "version": "1.0.15",
       "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.15.tgz",
@@ -323,6 +390,12 @@
       "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.6.9.tgz",
       "integrity": "sha512-/2xvG6vDC+Us8h0baSa1siDKwPj5R2A7LldxxhK2339HInc09bq9shMVCUy9zqnuvwnDUJ/DSgkSaBoSHSZrqg=="
     },
+    "angular-mocks": {
+      "version": "1.6.9",
+      "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.6.9.tgz",
+      "integrity": "sha512-5aEwXmfd5DQvb64pOgP2W2D3ozAQSARkB6q+6NQfUJvJs9bD2YcExrUc1P4EbiIuyWag2OQM+pIKUNojVi3SBg==",
+      "dev": true
+    },
     "angular-motion": {
       "version": "0.4.4",
       "resolved": "https://registry.npmjs.org/angular-motion/-/angular-motion-0.4.4.tgz",

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
index 32d9262..3b42a61 100644
--- a/modules/web-console/frontend/package.json
+++ b/modules/web-console/frontend/package.json
@@ -116,12 +116,16 @@
   "devDependencies": {
     "@types/angular": "^1.6.32",
     "@types/angular-animate": "^1.5.8",
+    "@types/angular-mocks": "^1.5.11",
     "@types/angular-strap": "^2.3.1",
-    "@types/chai": "^4.0.4",
+    "@types/chai": "^4.1.2",
     "@types/lodash": "^4.14.77",
-    "@types/mocha": "^2.2.44",
+    "@types/mocha": "^2.2.48",
     "@types/sinon": "^4.0.0",
     "@types/ui-grid": "0.0.38",
+    "@types/webpack": "^4.1.2",
+    "@types/webpack-merge": "^4.1.3",
+    "angular-mocks": "^1.6.9",
     "app-root-path": "2.0.1",
     "chai": "4.1.0",
     "chalk": "2.1.0",
@@ -131,7 +135,7 @@
     "jasmine-core": "2.6.4",
     "karma": "2.0.0",
     "karma-babel-preprocessor": "6.0.1",
-    "karma-chrome-launcher": "2.2.0",
+    "karma-chrome-launcher": "^2.2.0",
     "karma-mocha": "1.3.0",
     "karma-mocha-reporter": "2.2.3",
     "karma-teamcity-reporter": "1.0.0",

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/test/karma.conf.babel.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/karma.conf.babel.js b/modules/web-console/frontend/test/karma.conf.babel.js
index 48104c8..b192594 100644
--- a/modules/web-console/frontend/test/karma.conf.babel.js
+++ b/modules/web-console/frontend/test/karma.conf.babel.js
@@ -83,6 +83,14 @@ export default (config) => {
             ChromeHeadlessNoSandbox: {
                 base: 'ChromeHeadless',
                 flags: ['--no-sandbox']
+            },
+            ChromeDebug: {
+                base: 'Chrome',
+                flags: [
+                    '--start-maximized',
+                    '--auto-open-devtools-for-tabs'
+                ],
+                debug: true
             }
         },
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/webpack/webpack.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/webpack/webpack.test.js b/modules/web-console/frontend/webpack/webpack.test.js
index f906d0d..2ade625 100644
--- a/modules/web-console/frontend/webpack/webpack.test.js
+++ b/modules/web-console/frontend/webpack/webpack.test.js
@@ -38,10 +38,9 @@ export default merge(commonCfg, {
         }
     },
     module: {
+        exprContextCritical: false,
         rules: [
-            {test: /\.scss$/, use: ['ignore-loader']},
-            {test: /\.css$/, use: ['ignore-loader']},
-            {test: /\.pug$/, use: ['ignore-loader']}
+            {test: /\.s?css$/, use: ['ignore-loader']}
         ]
     }
 });


[4/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.pug
index 64bdc74..35bd5e8 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.pug
@@ -19,82 +19,79 @@ include /app/helpers/jade/mixins
 -var form = 'discovery'
 -var model = '$ctrl.clonedCluster.discovery'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Discovery
-        .pca-panel-heading-description
-            | TCP/IP discovery configuration. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/cluster-config" 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-20
-                    +text-ip-address('Local address:', `${model}.localAddress`, '"discoLocalAddress"', 'true', '228.1.2.4',
-                        'Local host IP address that discovery SPI uses<br/>\
-                        If not provided a first found non-loopback address will be used')
-                .pc-form-grid-col-20
-                    +number-min-max('Local port:', `${model}.localPort`, '"discoLocalPort"', 'true', '47500', '1024', '65535', 'Local port which node uses')
-                .pc-form-grid-col-20
-                    +number('Local port range:', `${model}.localPortRange`, '"discoLocalPortRange"', 'true', '100', '1', 'Local port range')
-                .pc-form-grid-col-60
-                    +java-class('Address resolver:', `${model}.addressResolver`, '"discoAddressResolver"', 'true', 'false',
-                        'Provides resolution between external and internal addresses')
-                .pc-form-grid-col-30
-                    +number('Socket timeout:', `${model}.socketTimeout`, '"socketTimeout"', 'true', '5000', '0', 'Socket operations timeout')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Acknowledgement timeout:',
-                        model: `${model}.ackTimeout`,
-                        name: '"ackTimeout"',
-                        disabled: 'false',
-                        placeholder: '5000',
-                        min: '0',
-                        max: `{{ ${model}.maxAckTimeout || 600000 }}`,
-                        tip: 'Message acknowledgement timeout'
-                    })
-                        +form-field-feedback('"ackTimeout"', 'max', `Acknowledgement timeout should be less than max acknowledgement timeout ({{ ${model}.maxAckTimeout || 60000 }}).`)
-                .pc-form-grid-col-30
-                    +number('Max acknowledgement timeout:', `${model}.maxAckTimeout`, '"maxAckTimeout"', 'true', '600000', '0', 'Maximum message acknowledgement timeout')
-                .pc-form-grid-col-30
-                    +number('Network timeout:', `${model}.networkTimeout`, '"discoNetworkTimeout"', 'true', '5000', '1', 'Timeout to use for network operations')
-                .pc-form-grid-col-30
-                    +number('Join timeout:', `${model}.joinTimeout`, '"joinTimeout"', 'true', '0', '0',
-                        'Join timeout<br/>' +
-                        '0 means wait forever')
-                .pc-form-grid-col-30
-                    +number('Thread priority:', `${model}.threadPriority`, '"threadPriority"', 'true', '10', '1', 'Thread priority for all threads started by SPI')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Discovery
+    panel-description
+        | TCP/IP discovery configuration. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/cluster-config" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-20
+                +text-ip-address('Local address:', `${model}.localAddress`, '"discoLocalAddress"', 'true', '228.1.2.4',
+                    'Local host IP address that discovery SPI uses<br/>\
+                    If not provided a first found non-loopback address will be used')
+            .pc-form-grid-col-20
+                +number-min-max('Local port:', `${model}.localPort`, '"discoLocalPort"', 'true', '47500', '1024', '65535', 'Local port which node uses')
+            .pc-form-grid-col-20
+                +number('Local port range:', `${model}.localPortRange`, '"discoLocalPortRange"', 'true', '100', '1', 'Local port range')
+            .pc-form-grid-col-60
+                +java-class('Address resolver:', `${model}.addressResolver`, '"discoAddressResolver"', 'true', 'false',
+                    'Provides resolution between external and internal addresses')
+            .pc-form-grid-col-30
+                +number('Socket timeout:', `${model}.socketTimeout`, '"socketTimeout"', 'true', '5000', '0', 'Socket operations timeout')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Acknowledgement timeout:',
+                    model: `${model}.ackTimeout`,
+                    name: '"ackTimeout"',
+                    disabled: 'false',
+                    placeholder: '5000',
+                    min: '0',
+                    max: `{{ ${model}.maxAckTimeout || 600000 }}`,
+                    tip: 'Message acknowledgement timeout'
+                })
+                    +form-field-feedback('"ackTimeout"', 'max', `Acknowledgement timeout should be less than max acknowledgement timeout ({{ ${model}.maxAckTimeout || 60000 }}).`)
+            .pc-form-grid-col-30
+                +number('Max acknowledgement timeout:', `${model}.maxAckTimeout`, '"maxAckTimeout"', 'true', '600000', '0', 'Maximum message acknowledgement timeout')
+            .pc-form-grid-col-30
+                +number('Network timeout:', `${model}.networkTimeout`, '"discoNetworkTimeout"', 'true', '5000', '1', 'Timeout to use for network operations')
+            .pc-form-grid-col-30
+                +number('Join timeout:', `${model}.joinTimeout`, '"joinTimeout"', 'true', '0', '0',
+                    'Join timeout<br/>' +
+                    '0 means wait forever')
+            .pc-form-grid-col-30
+                +number('Thread priority:', `${model}.threadPriority`, '"threadPriority"', 'true', '10', '1', 'Thread priority for all threads started by SPI')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Heartbeat frequency:', `${model}.heartbeatFrequency`, '"heartbeatFrequency"', 'true', '2000', '1', 'Heartbeat messages issuing frequency')
-                .pc-form-grid-col-30
-                    +number('Max heartbeats miss w/o init:', `${model}.maxMissedHeartbeats`, '"maxMissedHeartbeats"', 'true', '1', '1',
-                        'Max heartbeats count node can miss without initiating status check')
-                .pc-form-grid-col-30(ng-if-end)
-                    +number('Max missed client heartbeats:', `${model}.maxMissedClientHeartbeats`, '"maxMissedClientHeartbeats"', 'true', '5', '1',
-                        'Max heartbeats count node can miss without failing client node')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Heartbeat frequency:', `${model}.heartbeatFrequency`, '"heartbeatFrequency"', 'true', '2000', '1', 'Heartbeat messages issuing frequency')
+            .pc-form-grid-col-30
+                +number('Max heartbeats miss w/o init:', `${model}.maxMissedHeartbeats`, '"maxMissedHeartbeats"', 'true', '1', '1',
+                    'Max heartbeats count node can miss without initiating status check')
+            .pc-form-grid-col-30(ng-if-end)
+                +number('Max missed client heartbeats:', `${model}.maxMissedClientHeartbeats`, '"maxMissedClientHeartbeats"', 'true', '5', '1',
+                    'Max heartbeats count node can miss without failing client node')
 
-                .pc-form-grid-col-60
-                    +number('Topology history:', `${model}.topHistorySize`, '"topHistorySize"', 'true', '1000', '0', 'Size of topology snapshots history')
-                .pc-form-grid-col-60
-                    +java-class('Discovery listener:', `${model}.listener`, '"discoListener"', 'true', 'false', 'Listener for grid node discovery events')
-                .pc-form-grid-col-60
-                    +java-class('Data exchange:', `${model}.dataExchange`, '"dataExchange"', 'true', 'false', 'Class name of handler for initial data exchange between Ignite nodes')
-                .pc-form-grid-col-60
-                    +java-class('Metrics provider:', `${model}.metricsProvider`, '"metricsProvider"', 'true', 'false', 'Class name of metric provider to discovery SPI')
-                .pc-form-grid-col-30
-                    +number('Reconnect count:', `${model}.reconnectCount`, '"discoReconnectCount"', 'true', '10', '1', 'Reconnect attempts count')
-                .pc-form-grid-col-30
-                    +number('Statistics frequency:', `${model}.statisticsPrintFrequency`, '"statisticsPrintFrequency"', 'true', '0', '1', 'Statistics print frequency')
-                .pc-form-grid-col-60
-                    +number('IP finder clean frequency:', `${model}.ipFinderCleanFrequency`, '"ipFinderCleanFrequency"', 'true', '60000', '1', 'IP finder clean frequency')
-                .pc-form-grid-col-60
-                    +java-class('Node authenticator:', `${model}.authenticator`, '"authenticator"', 'true', 'false', 'Class name of node authenticator implementation')
-                .pc-form-grid-col-60
-                    +checkbox('Force server mode', `${model}.forceServerMode`, '"forceServerMode"', 'Force start TCP/IP discovery in server mode')
-                .pc-form-grid-col-60
-                    +checkbox('Client reconnect disabled', `${model}.clientReconnectDisabled`, '"clientReconnectDisabled"',
-                        'Disable try of client to reconnect after server detected client node failure')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterDiscovery')
+            .pc-form-grid-col-60
+                +number('Topology history:', `${model}.topHistorySize`, '"topHistorySize"', 'true', '1000', '0', 'Size of topology snapshots history')
+            .pc-form-grid-col-60
+                +java-class('Discovery listener:', `${model}.listener`, '"discoListener"', 'true', 'false', 'Listener for grid node discovery events')
+            .pc-form-grid-col-60
+                +java-class('Data exchange:', `${model}.dataExchange`, '"dataExchange"', 'true', 'false', 'Class name of handler for initial data exchange between Ignite nodes')
+            .pc-form-grid-col-60
+                +java-class('Metrics provider:', `${model}.metricsProvider`, '"metricsProvider"', 'true', 'false', 'Class name of metric provider to discovery SPI')
+            .pc-form-grid-col-30
+                +number('Reconnect count:', `${model}.reconnectCount`, '"discoReconnectCount"', 'true', '10', '1', 'Reconnect attempts count')
+            .pc-form-grid-col-30
+                +number('Statistics frequency:', `${model}.statisticsPrintFrequency`, '"statisticsPrintFrequency"', 'true', '0', '1', 'Statistics print frequency')
+            .pc-form-grid-col-60
+                +number('IP finder clean frequency:', `${model}.ipFinderCleanFrequency`, '"ipFinderCleanFrequency"', 'true', '60000', '1', 'IP finder clean frequency')
+            .pc-form-grid-col-60
+                +java-class('Node authenticator:', `${model}.authenticator`, '"authenticator"', 'true', 'false', 'Class name of node authenticator implementation')
+            .pc-form-grid-col-60
+                +checkbox('Force server mode', `${model}.forceServerMode`, '"forceServerMode"', 'Force start TCP/IP discovery in server mode')
+            .pc-form-grid-col-60
+                +checkbox('Client reconnect disabled', `${model}.clientReconnectDisabled`, '"clientReconnectDisabled"',
+                    'Disable try of client to reconnect after server detected client node failure')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterDiscovery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/events.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/events.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/events.pug
index 45e0936..a41999e 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/events.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/events.pug
@@ -23,47 +23,44 @@ include /app/helpers/jade/mixins
 -var eventStorageMemory = modelEventStorageKind + ' === "Memory"'
 -var eventStorageCustom = modelEventStorageKind + ' === "Custom"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Events
-        .pca-panel-heading-description
-            | Grid events are used for notification about what happens within the grid. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/events" 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(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +dropdown('Event storage:', modelEventStorageKind, '"eventStorageKind"', 'true', 'Disabled', '$ctrl.eventStorage',
-                    'Regulate how grid store events locally on node\
-                    <ul>\
-                        <li>Memory - All events are kept in the FIFO queue in-memory</li>\
-                        <li>Custom - Custom implementation of event storage SPI</li>\
-                    </ul>')
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +dropdown('Event storage:', modelEventStorageKind, '"eventStorageKind"', 'true', 'Disabled', '$ctrl.eventStorage',
-                    'Regulate how grid store events locally on node\
-                    <ul>\
-                        <li>Memory - All events are kept in the FIFO queue in-memory</li>\
-                        <li>Custom - Custom implementation of event storage SPI</li>\
-                        <li>Disabled - Events are not collected</li>\
-                    </ul>')
-                .pc-form-group.pc-form-grid-row(ng-if=modelEventStorageKind)
-                    .pc-form-grid-col-30(ng-if-start=eventStorageMemory)
-                        +number('Events expiration time:', `${modelEventStorage}.Memory.expireAgeMs`, '"EventStorageExpireAgeMs"', 'true', 'Long.MAX_VALUE', '1', 'All events that exceed this value will be removed from the queue when next event comes')
-                    .pc-form-grid-col-30
-                        +number('Events queue size:', `${modelEventStorage}.Memory.expireCount`, '"EventStorageExpireCount"', 'true', '10000', '1', 'Events will be filtered out when new request comes')
-                    .pc-form-grid-col-60(ng-if-end)
-                        +java-class('Filter:', `${modelEventStorage}.Memory.filter`, '"EventStorageFilter"', 'true', 'false',
-                        'Filter for events to be recorded<br/>\
-                        Should be implementation of o.a.i.lang.IgnitePredicate&lt;o.a.i.events.Event&gt;', eventStorageMemory)
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Events
+    panel-description
+        | Grid events are used for notification about what happens within the grid. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/events" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +dropdown('Event storage:', modelEventStorageKind, '"eventStorageKind"', 'true', 'Disabled', '$ctrl.eventStorage',
+                'Regulate how grid store events locally on node\
+                <ul>\
+                    <li>Memory - All events are kept in the FIFO queue in-memory</li>\
+                    <li>Custom - Custom implementation of event storage SPI</li>\
+                </ul>')
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +dropdown('Event storage:', modelEventStorageKind, '"eventStorageKind"', 'true', 'Disabled', '$ctrl.eventStorage',
+                'Regulate how grid store events locally on node\
+                <ul>\
+                    <li>Memory - All events are kept in the FIFO queue in-memory</li>\
+                    <li>Custom - Custom implementation of event storage SPI</li>\
+                    <li>Disabled - Events are not collected</li>\
+                </ul>')
+            .pc-form-group.pc-form-grid-row(ng-if=modelEventStorageKind)
+                .pc-form-grid-col-30(ng-if-start=eventStorageMemory)
+                    +number('Events expiration time:', `${modelEventStorage}.Memory.expireAgeMs`, '"EventStorageExpireAgeMs"', 'true', 'Long.MAX_VALUE', '1', 'All events that exceed this value will be removed from the queue when next event comes')
+                .pc-form-grid-col-30
+                    +number('Events queue size:', `${modelEventStorage}.Memory.expireCount`, '"EventStorageExpireCount"', 'true', '10000', '1', 'Events will be filtered out when new request comes')
+                .pc-form-grid-col-60(ng-if-end)
+                    +java-class('Filter:', `${modelEventStorage}.Memory.filter`, '"EventStorageFilter"', 'true', 'false',
+                    'Filter for events to be recorded<br/>\
+                    Should be implementation of o.a.i.lang.IgnitePredicate&lt;o.a.i.events.Event&gt;', eventStorageMemory)
 
-                    .pc-form-grid-col-60(ng-if=eventStorageCustom)
-                        +java-class('Class:', `${modelEventStorage}.Custom.className`, '"EventStorageCustom"', 'true', eventStorageCustom, 'Event storage implementation class name', eventStorageCustom)
+                .pc-form-grid-col-60(ng-if=eventStorageCustom)
+                    +java-class('Class:', `${modelEventStorage}.Custom.className`, '"EventStorageCustom"', 'true', eventStorageCustom, 'Event storage implementation class name', eventStorageCustom)
 
-                    .pc-form-grid-col-60
-                        +dropdown-multiple('Include type:', `${model}.includeEventTypes`, '"includeEventTypes"', true, 'Choose recorded event types', '', '$ctrl.eventGroups',
-                        'Array of event types, which will be recorded by GridEventStorageManager#record(Event)<br/>\
-                        Note, that either the include event types or the exclude event types can be established')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterEvents')
+                .pc-form-grid-col-60
+                    +dropdown-multiple('Include type:', `${model}.includeEventTypes`, '"includeEventTypes"', true, 'Choose recorded event types', '', '$ctrl.eventGroups',
+                    'Array of event types, which will be recorded by GridEventStorageManager#record(Event)<br/>\
+                    Note, that either the include event types or the exclude event types can be established')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterEvents')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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
index 2f6dbed..2e92f83 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.pug
@@ -21,72 +21,69 @@ include /app/helpers/jade/mixins
 -var failoverSpi = model + '.failoverSpi'
 -var failoverCustom = '$item.kind === "Custom"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Failover configuration
-        .pca-panel-heading-description
-            | Failover SPI provides ability to supply custom logic for handling failed execution of a grid job. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/fault-tolerance" 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
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.0.0")')
-                    +number('Failure detection timeout:', model + '.failureDetectionTimeout', '"failureDetectionTimeout"', 'true',
-                        '10000', '1', 'Failure detection timeout is used to determine how long the communication or discovery SPIs should wait before considering a remote connection failed')
-                .pc-form-grid-col-60(ng-if-end)
-                    +number('Client failure detection timeout:', model + '.clientFailureDetectionTimeout', '"clientFailureDetectionTimeout"', 'true',
-                        '30000', '1', 'Failure detection timeout is used to determine how long the communication or discovery SPIs should wait before considering a remote connection failed')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Failover configuration
+    panel-description
+        | Failover SPI provides ability to supply custom logic for handling failed execution of a grid job. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/fault-tolerance" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.0.0")')
+                +number('Failure detection timeout:', model + '.failureDetectionTimeout', '"failureDetectionTimeout"', 'true',
+                    '10000', '1', 'Failure detection timeout is used to determine how long the communication or discovery SPIs should wait before considering a remote connection failed')
+            .pc-form-grid-col-60(ng-if-end)
+                +number('Client failure detection timeout:', model + '.clientFailureDetectionTimeout', '"clientFailureDetectionTimeout"', 'true',
+                    '30000', '1', 'Failure detection timeout is used to determine how long the communication or discovery SPIs should wait before considering a remote connection failed')
 
-                .pc-form-grid-col-60(ng-init='failoverSpiTbl={type: "failoverSpi", model: "failoverSpi", focusId: "kind", ui: "failover-table"}')
-                    mixin clusters-failover-spi
-                        .ignite-form-field
-                            +ignite-form-field__label('Failover SPI configurations:', '"failoverSpi"')
-                                +tooltip(`Failover SPI configurations`)
-                            .ignite-form-field__control
-                                -let items = failoverSpi
+            .pc-form-grid-col-60(ng-init='failoverSpiTbl={type: "failoverSpi", model: "failoverSpi", focusId: "kind", ui: "failover-table"}')
+                mixin clusters-failover-spi
+                    .ignite-form-field
+                        +ignite-form-field__label('Failover SPI configurations:', '"failoverSpi"')
+                            +tooltip(`Failover SPI configurations`)
+                        .ignite-form-field__control
+                            -let items = failoverSpi
 
-                                list-editable(ng-model=items name='failoverSpi')
-                                    list-editable-item-edit
-                                        - form = '$parent.form'
-                                        .settings-row
-                                            +sane-ignite-form-field-dropdown({
-                                                required: true,
-                                                label: 'Failover SPI:',
-                                                model: '$item.kind',
-                                                name: '"failoverKind"',
-                                                placeholder: 'Choose Failover SPI',
-                                                options: '::$ctrl.Clusters.failoverSpis',
-                                                tip: `
-                                                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>`
-                                            })
+                            list-editable(ng-model=items name='failoverSpi')
+                                list-editable-item-edit
+                                    - form = '$parent.form'
+                                    .settings-row
+                                        +sane-ignite-form-field-dropdown({
+                                            required: true,
+                                            label: 'Failover SPI:',
+                                            model: '$item.kind',
+                                            name: '"failoverKind"',
+                                            placeholder: 'Choose Failover SPI',
+                                            options: '::$ctrl.Clusters.failoverSpis',
+                                            tip: `
+                                            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>`
+                                        })
 
-                                        .settings-row(ng-show='$item.kind === "JobStealing"')
-                                            +number('Maximum failover attempts:', '$item.JobStealing.maximumFailoverAttempts', '"jsMaximumFailoverAttempts"', 'true', '5', '0',
-                                                'Maximum number of attempts to execute a failed job on another node')
-                                        .settings-row(ng-show='$item.kind === "Always"')
-                                            +number('Maximum failover attempts:', '$item.Always.maximumFailoverAttempts', '"alwaysMaximumFailoverAttempts"', 'true', '5', '0',
-                                                'Maximum number of attempts to execute a failed job on another node')
-                                        .settings-row(ng-show=failoverCustom)
-                                            +java-class('SPI implementation', '$item.Custom.class', '"failoverSpiClass"', 'true', failoverCustom,
-                                                'Custom FailoverSpi implementation class name.', failoverCustom)
+                                    .settings-row(ng-show='$item.kind === "JobStealing"')
+                                        +number('Maximum failover attempts:', '$item.JobStealing.maximumFailoverAttempts', '"jsMaximumFailoverAttempts"', 'true', '5', '0',
+                                            'Maximum number of attempts to execute a failed job on another node')
+                                    .settings-row(ng-show='$item.kind === "Always"')
+                                        +number('Maximum failover attempts:', '$item.Always.maximumFailoverAttempts', '"alwaysMaximumFailoverAttempts"', 'true', '5', '0',
+                                            'Maximum number of attempts to execute a failed job on another node')
+                                    .settings-row(ng-show=failoverCustom)
+                                        +java-class('SPI implementation', '$item.Custom.class', '"failoverSpiClass"', 'true', failoverCustom,
+                                            'Custom FailoverSpi implementation class name.', failoverCustom)
 
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`(${items} = ${items} || []).push({})`
-                                            label-single='failover SPI'
-                                            label-multiple='failover SPIs'
-                                        )
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`(${items} = ${items} || []).push({})`
+                                        label-single='failover SPI'
+                                        label-multiple='failover SPIs'
+                                    )
 
-                    +clusters-failover-spi
+                +clusters-failover-spi
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterFailover')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterFailover')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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
index d31eba6..86f6384 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.pug
@@ -30,63 +30,60 @@ include ./general/discovery/vm
 include ./general/discovery/zookeeper
 include ./general/discovery/kubernetes
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title General
-        .pca-panel-heading-description
-            | Common cluster configuration.
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/clustering" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-text({
-                        label: 'Name:',
-                        model: `${model}.name`,
-                        name: '"clusterName"',
-                        disabled: 'false',
-                        placeholder: 'Input name',
-                        required: true,
-                        tip: 'Instance name allows to indicate to what grid this particular grid instance belongs to'
-                    })(
-                        ignite-unique='$ctrl.shortClusters'
-                        ignite-unique-property='name'
-                        ignite-unique-skip=`["_id", ${model}]`
-                    )
-                        +unique-feedback(`${model}.name`, 'Cluster name should be unique.')
+panel-collapsible(opened=`::true` ng-form=form)
+    panel-title General
+    panel-description
+        | Common cluster configuration.
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/clustering" target="_blank") More info]
+    panel-content.pca-form-row
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-text({
+                    label: 'Name:',
+                    model: `${model}.name`,
+                    name: '"clusterName"',
+                    disabled: 'false',
+                    placeholder: 'Input name',
+                    required: true,
+                    tip: 'Instance name allows to indicate to what grid this particular grid instance belongs to'
+                })(
+                    ignite-unique='$ctrl.shortClusters'
+                    ignite-unique-property='name'
+                    ignite-unique-skip=`["_id", ${model}]`
+                )
+                    +unique-feedback(`${model}.name`, 'Cluster name should be unique.')
 
-                .pc-form-grid-col-30
-                    +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')
+            .pc-form-grid-col-30
+                +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')
 
-                .pc-form-grid-col-60
-                    +dropdown('Discovery:', `${model}.discovery.kind`, '"discovery"', 'true', 'Choose discovery', '$ctrl.Clusters.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 address</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>\
-                        <li>Kubernetes - IP finder for automatic lookup of Ignite nodes running in Kubernetes environment</li>\
-                    </ul>')
-                .pc-form-group
-                    +discovery-cloud()(ng-if=`${modelDiscoveryKind} === 'Cloud'`)
-                    +discovery-google()(ng-if=`${modelDiscoveryKind} === 'GoogleStorage'`)
-                    +discovery-jdbc()(ng-if=`${modelDiscoveryKind} === 'Jdbc'`)
-                    +discovery-multicast()(ng-if=`${modelDiscoveryKind} === 'Multicast'`)
-                    +discovery-s3()(ng-if=`${modelDiscoveryKind} === 'S3'`)
-                    +discovery-shared()(ng-if=`${modelDiscoveryKind} === 'SharedFs'`)
-                    +discovery-vm()(ng-if=`${modelDiscoveryKind} === 'Vm'`)
-                    +discovery-zookeeper()(ng-if=`${modelDiscoveryKind} === 'ZooKeeper'`)
-                    +discovery-kubernetes()(ng-if=`${modelDiscoveryKind} === 'Kubernetes'`)
+            .pc-form-grid-col-60
+                +dropdown('Discovery:', `${model}.discovery.kind`, '"discovery"', 'true', 'Choose discovery', '$ctrl.Clusters.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 address</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>\
+                    <li>Kubernetes - IP finder for automatic lookup of Ignite nodes running in Kubernetes environment</li>\
+                </ul>')
+            .pc-form-group
+                +discovery-cloud()(ng-if=`${modelDiscoveryKind} === 'Cloud'`)
+                +discovery-google()(ng-if=`${modelDiscoveryKind} === 'GoogleStorage'`)
+                +discovery-jdbc()(ng-if=`${modelDiscoveryKind} === 'Jdbc'`)
+                +discovery-multicast()(ng-if=`${modelDiscoveryKind} === 'Multicast'`)
+                +discovery-s3()(ng-if=`${modelDiscoveryKind} === 'S3'`)
+                +discovery-shared()(ng-if=`${modelDiscoveryKind} === 'SharedFs'`)
+                +discovery-vm()(ng-if=`${modelDiscoveryKind} === 'Vm'`)
+                +discovery-zookeeper()(ng-if=`${modelDiscoveryKind} === 'ZooKeeper'`)
+                +discovery-kubernetes()(ng-if=`${modelDiscoveryKind} === 'Kubernetes'`)
 
-            .pca-form-column-6
-                -var model = '$ctrl.clonedCluster'
-                +preview-xml-java(model, 'clusterGeneral')
+        .pca-form-column-6
+            -var model = '$ctrl.clonedCluster'
+            +preview-xml-java(model, 'clusterGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/hadoop.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/hadoop.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/hadoop.pug
index 7bfef7e..16a072c 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/hadoop.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/hadoop.pug
@@ -24,68 +24,64 @@ include /app/helpers/jade/mixins
 -var customPlanner = plannerModel + '.kind === "Custom"'
 -var libs = model + '.nativeLibraryNames'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
     -var uniqueTip = 'Such native library already exists!'
 
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Hadoop configuration
-        .pca-panel-heading-description
-            | Hadoop Accelerator configuration.
-    .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
-                    +dropdown('Map reduce planner:', plannerModel + '.kind', '"MapReducePlanner"', 'true', 'Default', '[\
-                        {value: "Weighted", label: "Weighted"},\
-                        {value: "Custom", label: "Custom"},\
-                        {value: null, label: "Default"}\
-                    ]', 'Implementation of map reduce planner\
-                    <ul>\
-                        <li>Weighted - Planner which assigns mappers and reducers based on their "weights"</li>\
-                        <li>Custom - Custom planner implementation</li>\
-                        <li>Default - Default planner implementation</li>\
-                    </ul>')
-                .pc-form-group.pc-form-grid-row(ng-show=weightedPlanner)
-                    .pc-form-grid-col-20
-                        +number('Local mapper weight:', weightedModel + '.localMapperWeight', '"LocalMapperWeight"', 'true', 100, '0',
-                            'This weight is added to a node when a mapper is assigned and it is input split data is located on this node')
-                    .pc-form-grid-col-20
-                        +number('Remote mapper weight:', weightedModel + '.remoteMapperWeight', '"remoteMapperWeight"', 'true', 100, '0',
-                            'This weight is added to a node when a mapper is assigned, but it is input split data is not located on this node')
-                    .pc-form-grid-col-20
-                        +number('Local reducer weight:', weightedModel + '.localReducerWeight', '"localReducerWeight"', 'true', 100, '0',
-                            'This weight is added to a node when a reducer is assigned and the node have at least one assigned mapper')
-                    .pc-form-grid-col-30
-                        +number('Remote reducer weight:', weightedModel + '.remoteReducerWeight', '"remoteReducerWeight"', 'true', 100, '0',
-                            'This weight is added to a node when a reducer is assigned, but the node does not have any assigned mappers')
-                    .pc-form-grid-col-30
-                        +number('Local mapper weight:', weightedModel + '.preferLocalReducerThresholdWeight', '"preferLocalReducerThresholdWeight"', 'true', 200, '0',
-                            "When threshold is reached, a node with mappers is no longer considered as preferred for further reducer assignments")
-                .pc-form-group.pc-form-grid-row(ng-show=customPlanner)
-                    .pc-form-grid-col-60
-                        +java-class('Class name:', plannerModel + '.Custom.className', '"MapReducePlannerCustomClass"', 'true', customPlanner,
-                            'Custom planner implementation')
-                .pc-form-grid-col-30
-                    +number('Finished job info TTL:', model + '.finishedJobInfoTtl', '"finishedJobInfoTtl"', 'true', '30000', '0',
-                        'Finished job info time-to-live in milliseconds')
+    panel-title Hadoop configuration
+    panel-description Hadoop Accelerator configuration.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('Map reduce planner:', plannerModel + '.kind', '"MapReducePlanner"', 'true', 'Default', '[\
+                    {value: "Weighted", label: "Weighted"},\
+                    {value: "Custom", label: "Custom"},\
+                    {value: null, label: "Default"}\
+                ]', 'Implementation of map reduce planner\
+                <ul>\
+                    <li>Weighted - Planner which assigns mappers and reducers based on their "weights"</li>\
+                    <li>Custom - Custom planner implementation</li>\
+                    <li>Default - Default planner implementation</li>\
+                </ul>')
+            .pc-form-group.pc-form-grid-row(ng-show=weightedPlanner)
+                .pc-form-grid-col-20
+                    +number('Local mapper weight:', weightedModel + '.localMapperWeight', '"LocalMapperWeight"', 'true', 100, '0',
+                        'This weight is added to a node when a mapper is assigned and it is input split data is located on this node')
+                .pc-form-grid-col-20
+                    +number('Remote mapper weight:', weightedModel + '.remoteMapperWeight', '"remoteMapperWeight"', 'true', 100, '0',
+                        'This weight is added to a node when a mapper is assigned, but it is input split data is not located on this node')
+                .pc-form-grid-col-20
+                    +number('Local reducer weight:', weightedModel + '.localReducerWeight', '"localReducerWeight"', 'true', 100, '0',
+                        'This weight is added to a node when a reducer is assigned and the node have at least one assigned mapper')
                 .pc-form-grid-col-30
-                    +number('Max parallel tasks:', model + '.maxParallelTasks', '"maxParallelTasks"', 'true', 'availableProcessors * 2', '1',
-                        'Max number of local tasks that may be executed in parallel')
+                    +number('Remote reducer weight:', weightedModel + '.remoteReducerWeight', '"remoteReducerWeight"', 'true', 100, '0',
+                        'This weight is added to a node when a reducer is assigned, but the node does not have any assigned mappers')
                 .pc-form-grid-col-30
-                    +number('Max task queue size:', model + '.maxTaskQueueSize', '"maxTaskQueueSize"', 'true', '8192', '1', 'Max task queue size')
+                    +number('Local mapper weight:', weightedModel + '.preferLocalReducerThresholdWeight', '"preferLocalReducerThresholdWeight"', 'true', 200, '0',
+                        "When threshold is reached, a node with mappers is no longer considered as preferred for further reducer assignments")
+            .pc-form-group.pc-form-grid-row(ng-show=customPlanner)
                 .pc-form-grid-col-60
-                    .ignite-form-field
-                        +list-text-field({
-                            items: libs,
-                            lbl: 'Library name',
-                            name: 'libraryName',
-                            itemName: 'library name',
-                            itemsName: 'library names'
-                        })(
-                            list-editable-cols=`::[{name: 'Native libraries:'}]`
-                        )
-                            +unique-feedback(_, `${uniqueTip}`)
+                    +java-class('Class name:', plannerModel + '.Custom.className', '"MapReducePlannerCustomClass"', 'true', customPlanner,
+                        'Custom planner implementation')
+            .pc-form-grid-col-30
+                +number('Finished job info TTL:', model + '.finishedJobInfoTtl', '"finishedJobInfoTtl"', 'true', '30000', '0',
+                    'Finished job info time-to-live in milliseconds')
+            .pc-form-grid-col-30
+                +number('Max parallel tasks:', model + '.maxParallelTasks', '"maxParallelTasks"', 'true', 'availableProcessors * 2', '1',
+                    'Max number of local tasks that may be executed in parallel')
+            .pc-form-grid-col-30
+                +number('Max task queue size:', model + '.maxTaskQueueSize', '"maxTaskQueueSize"', 'true', '8192', '1', 'Max task queue size')
+            .pc-form-grid-col-60
+                .ignite-form-field
+                    +list-text-field({
+                        items: libs,
+                        lbl: 'Library name',
+                        name: 'libraryName',
+                        itemName: 'library name',
+                        itemsName: 'library names'
+                    })(
+                        list-editable-cols=`::[{name: 'Native libraries:'}]`
+                    )
+                        +unique-feedback(_, `${uniqueTip}`)
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterHadoop')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterHadoop')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.pug
index cfe4d74..c1216a2 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.pug
@@ -19,19 +19,16 @@ include /app/helpers/jade/mixins
 -var form = 'igfs'
 -var model = '$ctrl.clonedCluster'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title IGFS
-        .pca-panel-heading-description
-            | IGFS (Ignite In-Memory File System) configurations assigned to cluster. 
-            | #[a.link-success(href="https://apacheignite-fs.readme.io/docs/in-memory-file-system" 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
-                .settings-row
-                    +dropdown-multiple('<span>IGFS:</span><a ui-sref="base.configuration.edit.advanced.igfs({linkId: linkId()})"> (add)</a>',
-                        `${model}.igfss`, '"igfss"', true, 'Choose IGFS', 'No IGFS configured', 'igfss',
-                        'Select IGFS to start in cluster or add a new IGFS')
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfss', 'igfss')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title IGFS
+    panel-description 
+        | IGFS (Ignite In-Memory File System) configurations assigned to cluster. 
+        | #[a.link-success(href="https://apacheignite-fs.readme.io/docs/in-memory-file-system" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6
+            .settings-row
+                +dropdown-multiple('<span>IGFS:</span><a ui-sref="base.configuration.edit.advanced.igfs({linkId: linkId()})"> (add)</a>',
+                    `${model}.igfss`, '"igfss"', true, 'Choose IGFS', 'No IGFS configured', 'igfss',
+                    'Select IGFS to start in cluster or add a new IGFS')
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfss', 'igfss')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/load-balancing.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/load-balancing.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/load-balancing.pug
index 2f2dd3b..ff817e1 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/load-balancing.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/load-balancing.pug
@@ -22,97 +22,94 @@ include /app/helpers/jade/mixins
 -var loadBalancingCustom = '$item.kind === "Custom"'
 -var loadProbeCustom = '$item.kind === "Adaptive" && $item.Adaptive.loadProbe.kind === "Custom"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Load balancing configuration
-        .pca-panel-heading-description
-            | Load balancing component balances job distribution among cluster nodes. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/load-balancing" 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
-                mixin clusters-load-balancing-spi
-                    .ignite-form-field(ng-init='loadBalancingSpiTbl={type: "loadBalancingSpi", model: "loadBalancingSpi", focusId: "kind", ui: "load-balancing-table"}')
-                        +ignite-form-field__label('Load balancing configurations:', '"loadBalancingConfigurations"')
-                            +tooltip(`Load balancing component balances job distribution among cluster nodes`)
-                        .ignite-form-field__control
-                            -let items = loadBalancingSpi
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Load balancing configuration
+    panel-description
+        | Load balancing component balances job distribution among cluster nodes. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/load-balancing" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6
+            mixin clusters-load-balancing-spi
+                .ignite-form-field(ng-init='loadBalancingSpiTbl={type: "loadBalancingSpi", model: "loadBalancingSpi", focusId: "kind", ui: "load-balancing-table"}')
+                    +ignite-form-field__label('Load balancing configurations:', '"loadBalancingConfigurations"')
+                        +tooltip(`Load balancing component balances job distribution among cluster nodes`)
+                    .ignite-form-field__control
+                        -let items = loadBalancingSpi
 
-                            list-editable(ng-model=items name='loadBalancingConfigurations')
-                                list-editable-item-edit
-                                    - form = '$parent.form'
-                                    .settings-row
-                                        +sane-ignite-form-field-dropdown({
-                                            label: 'Load balancing:',
-                                            model: '$item.kind',
-                                            name: '"loadBalancingKind"',
-                                            required: true,
-                                            options: '::$ctrl.Clusters.loadBalancingKinds',
-                                            tip: `Provides the next best balanced node for job execution
-                                            <ul>
-                                                <li>Round-robin - Iterates through nodes in round-robin fashion and pick the next sequential node</li>
-                                                <li>Adaptive - Adapts to overall node performance</li>
-                                                <li>Random - Picks a random node for job execution</li>
-                                                <li>Custom - Custom load balancing implementation</li>
-                                            </ul>`
-                                        })(
-                                            ignite-unique=`${loadBalancingSpi}`
-                                            ignite-unique-property='kind'
-                                        )
-                                            +unique-feedback('"loadBalancingKind"', 'Load balancing SPI of that type is already configured')
-                                    .settings-row(ng-show='$item.kind === "RoundRobin"')
-                                        +checkbox('Per task', '$item.RoundRobin.perTask', '"loadBalancingRRPerTask"', 'A new round robin order should be created for every task flag')
-                                    .settings-row(ng-show='$item.kind === "Adaptive"')
-                                        +dropdown('Load probe:', '$item.Adaptive.loadProbe.kind', '"loadBalancingAdaptiveLoadProbeKind"', 'true', 'Default', '[\
-                                                {value: "Job", label: "Job count"},\
-                                                {value: "CPU", label: "CPU load"},\
-                                                {value: "ProcessingTime", label: "Processing time"},\
-                                                {value: "Custom", label: "Custom"},\
-                                                {value: null, label: "Default"}\
-                                            ]', 'Implementation of node load probing\
-                                            <ul>\
-                                                <li>Job count - Based on active and waiting job count</li>\
-                                                <li>CPU load - Based on CPU load</li>\
-                                                <li>Processing time - Based on total job processing time</li>\
-                                                <li>Custom - Custom load probing implementation</li>\
-                                                <li>Default - Default load probing implementation</li>\
-                                            </ul>')
-                                    .settings-row(ng-show='$item.kind === "Adaptive" && $item.Adaptive.loadProbe.kind')
-                                        .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "Job"')
-                                            .details-row
-                                                +checkbox('Use average', '$item.Adaptive.loadProbe.Job.useAverage', '"loadBalancingAdaptiveJobUseAverage"', 'Use average CPU load vs. current')
-                                        .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "CPU"')
-                                            .details-row
-                                                +checkbox('Use average', '$item.Adaptive.loadProbe.CPU.useAverage', '"loadBalancingAdaptiveCPUUseAverage"', 'Use average CPU load vs. current')
-                                            .details-row
-                                                +checkbox('Use processors', '$item.Adaptive.loadProbe.CPU.useProcessors', '"loadBalancingAdaptiveCPUUseProcessors"', "divide each node's CPU load by the number of processors on that node")
-                                            .details-row
-                                                +number-min-max-step('Processor coefficient:', '$item.Adaptive.loadProbe.CPU.processorCoefficient',
-                                                    '"loadBalancingAdaptiveCPUProcessorCoefficient"', 'true', '1', '0.001', '1', '0.05', 'Coefficient of every CPU')
-                                        .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "ProcessingTime"')
-                                            .details-row
-                                                +checkbox('Use average', '$item.Adaptive.loadProbe.ProcessingTime.useAverage', '"loadBalancingAdaptiveJobUseAverage"', 'Use average execution time vs. current')
-                                        .panel-details(ng-show=loadProbeCustom)
-                                            .details-row
-                                                +java-class('Load brobe implementation:', '$item.Adaptive.loadProbe.Custom.className', '"loadBalancingAdaptiveJobUseClass"', 'true', loadProbeCustom,
-                                                    'Custom load balancing SPI implementation class name.', loadProbeCustom)
-                                    .settings-row(ng-show='$item.kind === "WeightedRandom"')
-                                        +number('Node weight:', '$item.WeightedRandom.nodeWeight', '"loadBalancingWRNodeWeight"', 'true', 10, '1', 'Weight of node')
-                                    .settings-row(ng-show='$item.kind === "WeightedRandom"')
-                                        +checkbox('Use weights', '$item.WeightedRandom.useWeights', '"loadBalancingWRUseWeights"', 'Node weights should be checked when doing random load balancing')
-                                    .settings-row(ng-show=loadBalancingCustom)
-                                        +java-class('Load balancing SPI implementation:', '$item.Custom.className', '"loadBalancingClass"', 'true', loadBalancingCustom,
-                                            'Custom load balancing SPI implementation class name.', loadBalancingCustom)
-
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$ctrl.Clusters.addLoadBalancingSpi(${model})`
-                                        label-single='load balancing configuration'
-                                        label-multiple='load balancing configurations'
+                        list-editable(ng-model=items name='loadBalancingConfigurations')
+                            list-editable-item-edit
+                                - form = '$parent.form'
+                                .settings-row
+                                    +sane-ignite-form-field-dropdown({
+                                        label: 'Load balancing:',
+                                        model: '$item.kind',
+                                        name: '"loadBalancingKind"',
+                                        required: true,
+                                        options: '::$ctrl.Clusters.loadBalancingKinds',
+                                        tip: `Provides the next best balanced node for job execution
+                                        <ul>
+                                            <li>Round-robin - Iterates through nodes in round-robin fashion and pick the next sequential node</li>
+                                            <li>Adaptive - Adapts to overall node performance</li>
+                                            <li>Random - Picks a random node for job execution</li>
+                                            <li>Custom - Custom load balancing implementation</li>
+                                        </ul>`
+                                    })(
+                                        ignite-unique=`${loadBalancingSpi}`
+                                        ignite-unique-property='kind'
                                     )
+                                        +unique-feedback('"loadBalancingKind"', 'Load balancing SPI of that type is already configured')
+                                .settings-row(ng-show='$item.kind === "RoundRobin"')
+                                    +checkbox('Per task', '$item.RoundRobin.perTask', '"loadBalancingRRPerTask"', 'A new round robin order should be created for every task flag')
+                                .settings-row(ng-show='$item.kind === "Adaptive"')
+                                    +dropdown('Load probe:', '$item.Adaptive.loadProbe.kind', '"loadBalancingAdaptiveLoadProbeKind"', 'true', 'Default', '[\
+                                            {value: "Job", label: "Job count"},\
+                                            {value: "CPU", label: "CPU load"},\
+                                            {value: "ProcessingTime", label: "Processing time"},\
+                                            {value: "Custom", label: "Custom"},\
+                                            {value: null, label: "Default"}\
+                                        ]', 'Implementation of node load probing\
+                                        <ul>\
+                                            <li>Job count - Based on active and waiting job count</li>\
+                                            <li>CPU load - Based on CPU load</li>\
+                                            <li>Processing time - Based on total job processing time</li>\
+                                            <li>Custom - Custom load probing implementation</li>\
+                                            <li>Default - Default load probing implementation</li>\
+                                        </ul>')
+                                .settings-row(ng-show='$item.kind === "Adaptive" && $item.Adaptive.loadProbe.kind')
+                                    .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "Job"')
+                                        .details-row
+                                            +checkbox('Use average', '$item.Adaptive.loadProbe.Job.useAverage', '"loadBalancingAdaptiveJobUseAverage"', 'Use average CPU load vs. current')
+                                    .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "CPU"')
+                                        .details-row
+                                            +checkbox('Use average', '$item.Adaptive.loadProbe.CPU.useAverage', '"loadBalancingAdaptiveCPUUseAverage"', 'Use average CPU load vs. current')
+                                        .details-row
+                                            +checkbox('Use processors', '$item.Adaptive.loadProbe.CPU.useProcessors', '"loadBalancingAdaptiveCPUUseProcessors"', "divide each node's CPU load by the number of processors on that node")
+                                        .details-row
+                                            +number-min-max-step('Processor coefficient:', '$item.Adaptive.loadProbe.CPU.processorCoefficient',
+                                                '"loadBalancingAdaptiveCPUProcessorCoefficient"', 'true', '1', '0.001', '1', '0.05', 'Coefficient of every CPU')
+                                    .panel-details(ng-show='$item.Adaptive.loadProbe.kind === "ProcessingTime"')
+                                        .details-row
+                                            +checkbox('Use average', '$item.Adaptive.loadProbe.ProcessingTime.useAverage', '"loadBalancingAdaptiveJobUseAverage"', 'Use average execution time vs. current')
+                                    .panel-details(ng-show=loadProbeCustom)
+                                        .details-row
+                                            +java-class('Load brobe implementation:', '$item.Adaptive.loadProbe.Custom.className', '"loadBalancingAdaptiveJobUseClass"', 'true', loadProbeCustom,
+                                                'Custom load balancing SPI implementation class name.', loadProbeCustom)
+                                .settings-row(ng-show='$item.kind === "WeightedRandom"')
+                                    +number('Node weight:', '$item.WeightedRandom.nodeWeight', '"loadBalancingWRNodeWeight"', 'true', 10, '1', 'Weight of node')
+                                .settings-row(ng-show='$item.kind === "WeightedRandom"')
+                                    +checkbox('Use weights', '$item.WeightedRandom.useWeights', '"loadBalancingWRUseWeights"', 'Node weights should be checked when doing random load balancing')
+                                .settings-row(ng-show=loadBalancingCustom)
+                                    +java-class('Load balancing SPI implementation:', '$item.Custom.className', '"loadBalancingClass"', 'true', loadBalancingCustom,
+                                        'Custom load balancing SPI implementation class name.', loadBalancingCustom)
+
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$ctrl.Clusters.addLoadBalancingSpi(${model})`
+                                    label-single='load balancing configuration'
+                                    label-multiple='load balancing configurations'
+                                )
 
-                +clusters-load-balancing-spi
+            +clusters-load-balancing-spi
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterLoadBalancing')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterLoadBalancing')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.pug
index d1676fb..7b4b9aa 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.pug
@@ -20,45 +20,41 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster.logger'
 -var kind = model + '.kind'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Logger configuration
-        .pca-panel-heading-description
-            | Logging functionality used throughout the system.
-    .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
-                    +dropdown('Logger:', kind, '"logger"', 'true', 'Default',
-                        '[\
-                            {value: "Log4j", label: "Apache Log4j"},\
-                            {value: "Log4j2", label: "Apache Log4j 2"},\
-                            {value: "SLF4J", label: "Simple Logging Facade (SLF4J)"},\
-                            {value: "Java", label: "Java logger (JUL)"},\
-                            {value: "JCL", label: "Jakarta Commons Logging (JCL)"},\
-                            {value: "Null", label: "Null logger"},\
-                            {value: "Custom", label: "Custom"},\
-                            {value: null, label: "Default"}\
-                        ]',
-                        'Logger implementations\
-                        <ul>\
-                            <li>Apache Log4j - log4j-based logger</li>\
-                            <li>Apache Log4j 2 - Log4j2-based logger</li>\
-                            <li>Simple Logging Facade (SLF4J) - SLF4j-based logger</li>\
-                            <li>Java logger (JUL) - built in java logger</li>\
-                            <li>Jakarta Commons Logging (JCL) - wraps any JCL (Jakarta Commons Logging) loggers</li>\
-                            <li>Null logger - logger which does not output anything</li>\
-                            <li>Custom - custom logger implementation</li>\
-                            <li>Default - Apache Log4j if awailable on classpath or Java logger otherwise</li>\
-                        </ul>')
-                .pc-form-group(ng-show=`${kind} && (${kind} === 'Log4j2' || ${kind} === 'Log4j' || ${kind} === 'Custom')`)
-                    .pc-form-grid-row(ng-show=`${kind} === 'Log4j2'`)
-                        include ./logger/log4j2
-                    .pc-form-grid-row(ng-show=`${kind} === 'Log4j'`)
-                        include ./logger/log4j
-                    .pc-form-grid-row(ng-show=`${kind} === 'Custom'`)
-                        include ./logger/custom
-            .pca-form-column-6
-                -var model = '$ctrl.clonedCluster.logger'
-                +preview-xml-java(model, 'clusterLogger')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Logger configuration
+    panel-description Logging functionality used throughout the system.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('Logger:', kind, '"logger"', 'true', 'Default',
+                    '[\
+                        {value: "Log4j", label: "Apache Log4j"},\
+                        {value: "Log4j2", label: "Apache Log4j 2"},\
+                        {value: "SLF4J", label: "Simple Logging Facade (SLF4J)"},\
+                        {value: "Java", label: "Java logger (JUL)"},\
+                        {value: "JCL", label: "Jakarta Commons Logging (JCL)"},\
+                        {value: "Null", label: "Null logger"},\
+                        {value: "Custom", label: "Custom"},\
+                        {value: null, label: "Default"}\
+                    ]',
+                    'Logger implementations\
+                    <ul>\
+                        <li>Apache Log4j - log4j-based logger</li>\
+                        <li>Apache Log4j 2 - Log4j2-based logger</li>\
+                        <li>Simple Logging Facade (SLF4J) - SLF4j-based logger</li>\
+                        <li>Java logger (JUL) - built in java logger</li>\
+                        <li>Jakarta Commons Logging (JCL) - wraps any JCL (Jakarta Commons Logging) loggers</li>\
+                        <li>Null logger - logger which does not output anything</li>\
+                        <li>Custom - custom logger implementation</li>\
+                        <li>Default - Apache Log4j if awailable on classpath or Java logger otherwise</li>\
+                    </ul>')
+            .pc-form-group(ng-show=`${kind} && (${kind} === 'Log4j2' || ${kind} === 'Log4j' || ${kind} === 'Custom')`)
+                .pc-form-grid-row(ng-show=`${kind} === 'Log4j2'`)
+                    include ./logger/log4j2
+                .pc-form-grid-row(ng-show=`${kind} === 'Log4j'`)
+                    include ./logger/log4j
+                .pc-form-grid-row(ng-show=`${kind} === 'Custom'`)
+                    include ./logger/custom
+        .pca-form-column-6
+            -var model = '$ctrl.clonedCluster.logger'
+            +preview-xml-java(model, 'clusterLogger')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.pug
index 61ab5d4..baa4956 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.pug
@@ -21,58 +21,55 @@ include /app/helpers/jade/mixins
 -var marshaller = model + '.marshaller'
 -var optMarshaller = marshaller + '.OptimizedMarshaller'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Marshaller
-        .pca-panel-heading-description
-            | Marshaller allows to marshal or unmarshal objects in grid. 
-            | It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized. 
-            | By default BinaryMarshaller will be used. 
-            | #[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(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +dropdown('Marshaller:', marshaller + '.kind', '"kind"', 'true', 'Default', '$ctrl.marshallerVariant',
-                        'Instance of marshaller to use in grid<br/>\
-                        <ul>\
-                            <li>OptimizedMarshaller - Optimized implementation of marshaller</li>\
-                            <li>JdkMarshaller - Marshaller based on JDK serialization mechanism</li>\
-                            <li>Default - BinaryMarshaller serialize and deserialize all objects in the binary format</li>\
-                        </ul>')
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["2.0.0", "2.1.0"])')
-                    +dropdown('Marshaller:', marshaller + '.kind', '"kind"', 'true', 'Default', '$ctrl.marshallerVariant',
-                        'Instance of marshaller to use in grid<br/>\
-                        <ul>\
-                            <li>JdkMarshaller - Marshaller based on JDK serialization mechanism</li>\
-                            <li>Default - BinaryMarshaller serialize and deserialize all objects in the binary format</li>\
-                        </ul>')
-                .pc-form-group.pc-form-grid-row(
-                    ng-show=`${marshaller}.kind === 'OptimizedMarshaller'`
-                    ng-if='$ctrl.available(["1.0.0", "2.1.0"])'
-                )
-                    .pc-form-grid-col-60
-                        +number('Streams pool size:', `${optMarshaller}.poolSize`, '"poolSize"', 'true', '0', '0',
-                            'Specifies size of cached object streams used by marshaller<br/>\
-                            Object streams are cached for performance reason to avoid costly recreation for every serialization routine<br/>\
-                            If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing<br/>\
-                            Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently<br/>\
-                            Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption<br/>\
-                            NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching')
-                    .pc-form-grid-col-60
-                        +checkbox('Require serializable', `${optMarshaller}.requireSerializable`, '"requireSerializable"',
-                            'Whether marshaller should require Serializable interface or not')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Marshaller
+    panel-description
+        | Marshaller allows to marshal or unmarshal objects in grid. 
+        | It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized. 
+        | By default BinaryMarshaller will be used. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/binary-marshaller" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +dropdown('Marshaller:', marshaller + '.kind', '"kind"', 'true', 'Default', '$ctrl.marshallerVariant',
+                    'Instance of marshaller to use in grid<br/>\
+                    <ul>\
+                        <li>OptimizedMarshaller - Optimized implementation of marshaller</li>\
+                        <li>JdkMarshaller - Marshaller based on JDK serialization mechanism</li>\
+                        <li>Default - BinaryMarshaller serialize and deserialize all objects in the binary format</li>\
+                    </ul>')
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["2.0.0", "2.1.0"])')
+                +dropdown('Marshaller:', marshaller + '.kind', '"kind"', 'true', 'Default', '$ctrl.marshallerVariant',
+                    'Instance of marshaller to use in grid<br/>\
+                    <ul>\
+                        <li>JdkMarshaller - Marshaller based on JDK serialization mechanism</li>\
+                        <li>Default - BinaryMarshaller serialize and deserialize all objects in the binary format</li>\
+                    </ul>')
+            .pc-form-group.pc-form-grid-row(
+                ng-show=`${marshaller}.kind === 'OptimizedMarshaller'`
+                ng-if='$ctrl.available(["1.0.0", "2.1.0"])'
+            )
                 .pc-form-grid-col-60
-                    +checkbox('Marshal local jobs', `${model}.marshalLocalJobs`, '"marshalLocalJobs"', 'If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node')
+                    +number('Streams pool size:', `${optMarshaller}.poolSize`, '"poolSize"', 'true', '0', '0',
+                        'Specifies size of cached object streams used by marshaller<br/>\
+                        Object streams are cached for performance reason to avoid costly recreation for every serialization routine<br/>\
+                        If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing<br/>\
+                        Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently<br/>\
+                        Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption<br/>\
+                        NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching')
+                .pc-form-grid-col-60
+                    +checkbox('Require serializable', `${optMarshaller}.requireSerializable`, '"requireSerializable"',
+                        'Whether marshaller should require Serializable interface or not')
+            .pc-form-grid-col-60
+                +checkbox('Marshal local jobs', `${model}.marshalLocalJobs`, '"marshalLocalJobs"', 'If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-30(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Keep alive time:', `${model}.marshallerCacheKeepAliveTime`, '"marshallerCacheKeepAliveTime"', 'true', '10000', '0',
-                        'Keep alive time of thread pool that is in charge of processing marshaller messages')
-                .pc-form-grid-col-30(ng-if-end)
-                    +number('Pool size:', `${model}.marshallerCacheThreadPoolSize`, '"marshallerCacheThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
-                        'Default size of thread pool that is in charge of processing marshaller messages')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-30(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Keep alive time:', `${model}.marshallerCacheKeepAliveTime`, '"marshallerCacheKeepAliveTime"', 'true', '10000', '0',
+                    'Keep alive time of thread pool that is in charge of processing marshaller messages')
+            .pc-form-grid-col-30(ng-if-end)
+                +number('Pool size:', `${model}.marshallerCacheThreadPoolSize`, '"marshallerCacheThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                    'Default size of thread pool that is in charge of processing marshaller messages')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterMarshaller')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterMarshaller')


[3/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/memory.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/memory.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/memory.pug
index 06c8e0b..831adea 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/memory.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/memory.pug
@@ -20,175 +20,176 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster.memoryConfiguration'
 -var memoryPolicies = model + '.memoryPolicies'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["2.0.0", "2.3.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Memory configuration
-        .pca-panel-heading-description
-            | Page memory is a manageable off-heap based memory architecture that is split into pages of fixed size. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/durable-memory" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available(["2.0.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show='$ctrl.available(["2.0.0", "2.3.0"])'
+)
+    panel-title Memory configuration
+    panel-description
+        | Page memory is a manageable off-heap based memory architecture that is split into pages of fixed size. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/durable-memory" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`$ctrl.available(["2.0.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +sane-ignite-form-field-dropdown({
+                    label: 'Page size:',
+                    model: `${model}.pageSize`,
+                    name: '"MemoryConfigurationPageSize"',
+                    options: `$ctrl.Clusters.memoryConfiguration.pageSize.values`,
+                    tip: 'Every memory region is split on pages of fixed size'
+                })
+            .pc-form-grid-col-60
+                +number('Concurrency level:', model + '.concurrencyLevel', '"MemoryConfigurationConcurrencyLevel"',
+                'true', 'availableProcessors', '2', 'The number of concurrent segments in Ignite internal page mapping tables')
+            .pc-form-grid-col-60.pc-form-group__text-title
+                span System cache
+            .pc-form-group.pc-form-grid-row
+                .pc-form-grid-col-30
+                    pc-form-field-size(
+                        label='Initial size:'
+                        ng-model=`${model}.systemCacheInitialSize`
+                        name='systemCacheInitialSize'
+                        placeholder='{{ $ctrl.Clusters.memoryConfiguration.systemCacheInitialSize.default / systemCacheInitialSizeScale.value }}'
+                        min='{{ ::$ctrl.Clusters.memoryConfiguration.systemCacheInitialSize.min }}'
+                        tip='Initial size of a memory region reserved for system cache'
+                        on-scale-change='systemCacheInitialSizeScale = $event'
+                    )
+                .pc-form-grid-col-30
+                    pc-form-field-size(
+                        label='Max size:'
+                        ng-model=`${model}.systemCacheMaxSize`
+                        name='systemCacheMaxSize'
+                        placeholder='{{ $ctrl.Clusters.memoryConfiguration.systemCacheMaxSize.default / systemCacheMaxSizeScale.value }}'
+                        min='{{ $ctrl.Clusters.memoryConfiguration.systemCacheMaxSize.min($ctrl.clonedCluster) }}'
+                        tip='Maximum size of a memory region reserved for system cache'
+                        on-scale-change='systemCacheMaxSizeScale = $event'
+                    )
+            .pc-form-grid-col-60.pc-form-group__text-title
+                span Memory policies
+            .pc-form-group.pc-form-grid-row
                 .pc-form-grid-col-60
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Page size:',
-                        model: `${model}.pageSize`,
-                        name: '"MemoryConfigurationPageSize"',
-                        options: `$ctrl.Clusters.memoryConfiguration.pageSize.values`,
-                        tip: 'Every memory region is split on pages of fixed size'
-                    })
+                    +sane-ignite-form-field-text({
+                        label: 'Default memory policy name:',
+                        model: `${model}.defaultMemoryPolicyName`,
+                        name: '"defaultMemoryPolicyName"',
+                        placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.name.default }}',
+                        tip: 'Name of a memory policy to be used as default one'
+                    })(
+                        pc-not-in-collection='::$ctrl.Clusters.memoryPolicy.name.invalidValues'
+                        ui-validate=`{
+                            defaultMemoryPolicyExists: '$ctrl.Clusters.memoryPolicy.customValidators.defaultMemoryPolicyExists($value, ${memoryPolicies})'
+                        }`
+                        ui-validate-watch=`"${memoryPolicies}"`
+                        ui-validate-watch-object-equality='true'
+                        ng-model-options='{allowInvalid: true}'
+                    )
+                        +form-field-feedback('"MemoryPolicyName"', 'notInCollection', '{{::$ctrl.Clusters.memoryPolicy.name.invalidValues[0]}} is reserved for internal use')
+                        +form-field-feedback('"MemoryPolicyName"', 'defaultMemoryPolicyExists', 'Memory policy with that name should be configured')
+                .pc-form-grid-col-60(ng-hide='(' + model + '.defaultMemoryPolicyName || "default") !== "default"')
+                    +number('Default memory policy size:', model + '.defaultMemoryPolicySize', '"defaultMemoryPolicySize"',
+                    'true', '0.8 * totalMemoryAvailable', '10485760',
+                    'Specify desired size of default memory policy without having to use more verbose syntax of MemoryPolicyConfiguration elements')
                 .pc-form-grid-col-60
-                    +number('Concurrency level:', model + '.concurrencyLevel', '"MemoryConfigurationConcurrencyLevel"',
-                    'true', 'availableProcessors', '2', 'The number of concurrent segments in Ignite internal page mapping tables')
-                .pc-form-grid-col-60.pc-form-group__text-title
-                    span System cache
-                .pc-form-group.pc-form-grid-row
-                    .pc-form-grid-col-30
-                        pc-form-field-size(
-                            label='Initial size:'
-                            ng-model=`${model}.systemCacheInitialSize`
-                            name='systemCacheInitialSize'
-                            placeholder='{{ $ctrl.Clusters.memoryConfiguration.systemCacheInitialSize.default / systemCacheInitialSizeScale.value }}'
-                            min='{{ ::$ctrl.Clusters.memoryConfiguration.systemCacheInitialSize.min }}'
-                            tip='Initial size of a memory region reserved for system cache'
-                            on-scale-change='systemCacheInitialSizeScale = $event'
-                        )
-                    .pc-form-grid-col-30
-                        pc-form-field-size(
-                            label='Max size:'
-                            ng-model=`${model}.systemCacheMaxSize`
-                            name='systemCacheMaxSize'
-                            placeholder='{{ $ctrl.Clusters.memoryConfiguration.systemCacheMaxSize.default / systemCacheMaxSizeScale.value }}'
-                            min='{{ $ctrl.Clusters.memoryConfiguration.systemCacheMaxSize.min($ctrl.clonedCluster) }}'
-                            tip='Maximum size of a memory region reserved for system cache'
-                            on-scale-change='systemCacheMaxSizeScale = $event'
-                        )
-                .pc-form-grid-col-60.pc-form-group__text-title
-                    span Memory policies
-                .pc-form-group.pc-form-grid-row
-                    .pc-form-grid-col-60
-                        +sane-ignite-form-field-text({
-                            label: 'Default memory policy name:',
-                            model: `${model}.defaultMemoryPolicyName`,
-                            name: '"defaultMemoryPolicyName"',
-                            placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.name.default }}',
-                            tip: 'Name of a memory policy to be used as default one'
-                        })(
-                            pc-not-in-collection='::$ctrl.Clusters.memoryPolicy.name.invalidValues'
-                            ui-validate=`{
-                                defaultMemoryPolicyExists: '$ctrl.Clusters.memoryPolicy.customValidators.defaultMemoryPolicyExists($value, ${memoryPolicies})'
-                            }`
-                            ui-validate-watch=`"${memoryPolicies}"`
-                            ui-validate-watch-object-equality='true'
-                            ng-model-options='{allowInvalid: true}'
-                        )
-                            +form-field-feedback('"MemoryPolicyName"', 'notInCollection', '{{::$ctrl.Clusters.memoryPolicy.name.invalidValues[0]}} is reserved for internal use')
-                            +form-field-feedback('"MemoryPolicyName"', 'defaultMemoryPolicyExists', 'Memory policy with that name should be configured')
-                    .pc-form-grid-col-60(ng-hide='(' + model + '.defaultMemoryPolicyName || "default") !== "default"')
-                        +number('Default memory policy size:', model + '.defaultMemoryPolicySize', '"defaultMemoryPolicySize"',
-                        'true', '0.8 * totalMemoryAvailable', '10485760',
-                        'Specify desired size of default memory policy without having to use more verbose syntax of MemoryPolicyConfiguration elements')
-                    .pc-form-grid-col-60
-                        mixin clusters-memory-policies
-                            .ignite-form-field(ng-init='memoryPoliciesTbl={type: "memoryPolicies", model: "memoryPolicies", focusId: "name", ui: "memory-policies-table"}')
-                                +ignite-form-field__label('Configured policies:', '"configuredPolicies"')
-                                    +tooltip(`List of configured policies`)
-                                .ignite-form-field__control
-                                    -let items = memoryPolicies
+                    mixin clusters-memory-policies
+                        .ignite-form-field(ng-init='memoryPoliciesTbl={type: "memoryPolicies", model: "memoryPolicies", focusId: "name", ui: "memory-policies-table"}')
+                            +ignite-form-field__label('Configured policies:', '"configuredPolicies"')
+                                +tooltip(`List of configured policies`)
+                            .ignite-form-field__control
+                                -let items = memoryPolicies
 
-                                    list-editable(ng-model=items name='memoryPolicies')
-                                        list-editable-item-edit.pc-form-grid-row
-                                            - form = '$parent.form'
-                                            .pc-form-grid-col-60
-                                                +sane-ignite-form-field-text({
-                                                    label: 'Name:',
-                                                    model: '$item.name',
-                                                    name: '"MemoryPolicyName"',
-                                                    placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.name.default }}',
-                                                    tip: 'Memory policy name'
-                                                })(
-                                                    ui-validate=`{
-                                                        uniqueMemoryPolicyName: '$ctrl.Clusters.memoryPolicy.customValidators.uniqueMemoryPolicyName($item, ${items})'
-                                                    }`
-                                                    ui-validate-watch=`"${items}"`
-                                                    ui-validate-watch-object-equality='true'
-                                                    pc-not-in-collection='::$ctrl.Clusters.memoryPolicy.name.invalidValues'
-                                                    ng-model-options='{allowInvalid: true}'
-                                                )
-                                                    +form-field-feedback('"MemoryPolicyName', 'uniqueMemoryPolicyName', 'Memory policy with that name is already configured')
-                                                    +form-field-feedback('"MemoryPolicyName', 'notInCollection', '{{::$ctrl.Clusters.memoryPolicy.name.invalidValues[0]}} is reserved for internal use')
-                                            .pc-form-grid-col-60
-                                                pc-form-field-size(
-                                                    label='Initial size:'
-                                                    ng-model='$item.initialSize'
-                                                    ng-model-options='{allowInvalid: true}'
-                                                    name='MemoryPolicyInitialSize'
-                                                    placeholder='{{ $ctrl.Clusters.memoryPolicy.initialSize.default / scale.value }}'
-                                                    min='{{ ::$ctrl.Clusters.memoryPolicy.initialSize.min }}'
-                                                    tip='Initial memory region size defined by this memory policy'
-                                                    on-scale-change='scale = $event'
-                                                )
-                                            .pc-form-grid-col-60
-                                                pc-form-field-size(
-                                                    ng-model='$item.maxSize'
-                                                    ng-model-options='{allowInvalid: true}'
-                                                    name='MemoryPolicyMaxSize'
-                                                    label='Maximum size:'
-                                                    placeholder='{{ ::$ctrl.Clusters.memoryPolicy.maxSize.default }}'
-                                                    min='{{ $ctrl.Clusters.memoryPolicy.maxSize.min($item) }}'
-                                                    tip='Maximum memory region size defined by this memory policy'
-                                                )
-                                            .pc-form-grid-col-60
-                                                +text('Swap file path:', '$item.swapFilePath', '"MemoryPolicySwapFilePath"', 'false',
-                                                'Input swap file path', 'An optional path to a memory mapped file for this memory policy')
-                                            .pc-form-grid-col-60
-                                                +dropdown('Eviction mode:', '$item.pageEvictionMode', '"MemoryPolicyPageEvictionMode"', 'true', 'DISABLED',
-                                                '[\
-                                                    {value: "DISABLED", label: "DISABLED"},\
-                                                    {value: "RANDOM_LRU", label: "RANDOM_LRU"},\
-                                                    {value: "RANDOM_2_LRU", label: "RANDOM_2_LRU"}\
-                                                ]',
-                                                'An algorithm for memory pages eviction\
-                                                <ul>\
-                                                    <li>DISABLED - Eviction is disabled</li>\
-                                                    <li>RANDOM_LRU - Once a memory region defined by a memory policy is configured, an off - heap array is allocated to track last usage timestamp for every individual data page</li>\
-                                                    <li>RANDOM_2_LRU - Differs from Random - LRU only in a way that two latest access timestamps are stored for every data page</li>\
-                                                </ul>')
-                                            .pc-form-grid-col-30
-                                                +number-min-max-step('Eviction threshold:', '$item.evictionThreshold', '"MemoryPolicyEvictionThreshold"',
-                                                'true', '0.9', '0.5', '0.999', '0.05', 'A threshold for memory pages eviction initiation')
-                                            .pc-form-grid-col-30
-                                                +sane-ignite-form-field-number({
-                                                    label: 'Empty pages pool size:',
-                                                    model: '$item.emptyPagesPoolSize',
-                                                    name: '"MemoryPolicyEmptyPagesPoolSize"',
-                                                    placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.default }}',
-                                                    min: '{{ ::$ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.min }}',
-                                                    max: '{{ $ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.max($ctrl.clonedCluster, $item) }}',
-                                                    tip: 'The minimal number of empty pages to be present in reuse lists for this memory policy'
-                                                })
+                                list-editable(ng-model=items name='memoryPolicies')
+                                    list-editable-item-edit.pc-form-grid-row
+                                        - form = '$parent.form'
+                                        .pc-form-grid-col-60
+                                            +sane-ignite-form-field-text({
+                                                label: 'Name:',
+                                                model: '$item.name',
+                                                name: '"MemoryPolicyName"',
+                                                placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.name.default }}',
+                                                tip: 'Memory policy name'
+                                            })(
+                                                ui-validate=`{
+                                                    uniqueMemoryPolicyName: '$ctrl.Clusters.memoryPolicy.customValidators.uniqueMemoryPolicyName($item, ${items})'
+                                                }`
+                                                ui-validate-watch=`"${items}"`
+                                                ui-validate-watch-object-equality='true'
+                                                pc-not-in-collection='::$ctrl.Clusters.memoryPolicy.name.invalidValues'
+                                                ng-model-options='{allowInvalid: true}'
+                                            )
+                                                +form-field-feedback('"MemoryPolicyName', 'uniqueMemoryPolicyName', 'Memory policy with that name is already configured')
+                                                +form-field-feedback('"MemoryPolicyName', 'notInCollection', '{{::$ctrl.Clusters.memoryPolicy.name.invalidValues[0]}} is reserved for internal use')
+                                        .pc-form-grid-col-60
+                                            pc-form-field-size(
+                                                label='Initial size:'
+                                                ng-model='$item.initialSize'
+                                                ng-model-options='{allowInvalid: true}'
+                                                name='MemoryPolicyInitialSize'
+                                                placeholder='{{ $ctrl.Clusters.memoryPolicy.initialSize.default / scale.value }}'
+                                                min='{{ ::$ctrl.Clusters.memoryPolicy.initialSize.min }}'
+                                                tip='Initial memory region size defined by this memory policy'
+                                                on-scale-change='scale = $event'
+                                            )
+                                        .pc-form-grid-col-60
+                                            pc-form-field-size(
+                                                ng-model='$item.maxSize'
+                                                ng-model-options='{allowInvalid: true}'
+                                                name='MemoryPolicyMaxSize'
+                                                label='Maximum size:'
+                                                placeholder='{{ ::$ctrl.Clusters.memoryPolicy.maxSize.default }}'
+                                                min='{{ $ctrl.Clusters.memoryPolicy.maxSize.min($item) }}'
+                                                tip='Maximum memory region size defined by this memory policy'
+                                            )
+                                        .pc-form-grid-col-60
+                                            +text('Swap file path:', '$item.swapFilePath', '"MemoryPolicySwapFilePath"', 'false',
+                                            'Input swap file path', 'An optional path to a memory mapped file for this memory policy')
+                                        .pc-form-grid-col-60
+                                            +dropdown('Eviction mode:', '$item.pageEvictionMode', '"MemoryPolicyPageEvictionMode"', 'true', 'DISABLED',
+                                            '[\
+                                                {value: "DISABLED", label: "DISABLED"},\
+                                                {value: "RANDOM_LRU", label: "RANDOM_LRU"},\
+                                                {value: "RANDOM_2_LRU", label: "RANDOM_2_LRU"}\
+                                            ]',
+                                            'An algorithm for memory pages eviction\
+                                            <ul>\
+                                                <li>DISABLED - Eviction is disabled</li>\
+                                                <li>RANDOM_LRU - Once a memory region defined by a memory policy is configured, an off - heap array is allocated to track last usage timestamp for every individual data page</li>\
+                                                <li>RANDOM_2_LRU - Differs from Random - LRU only in a way that two latest access timestamps are stored for every data page</li>\
+                                            </ul>')
+                                        .pc-form-grid-col-30
+                                            +number-min-max-step('Eviction threshold:', '$item.evictionThreshold', '"MemoryPolicyEvictionThreshold"',
+                                            'true', '0.9', '0.5', '0.999', '0.05', 'A threshold for memory pages eviction initiation')
+                                        .pc-form-grid-col-30
+                                            +sane-ignite-form-field-number({
+                                                label: 'Empty pages pool size:',
+                                                model: '$item.emptyPagesPoolSize',
+                                                name: '"MemoryPolicyEmptyPagesPoolSize"',
+                                                placeholder: '{{ ::$ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.default }}',
+                                                min: '{{ ::$ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.min }}',
+                                                max: '{{ $ctrl.Clusters.memoryPolicy.emptyPagesPoolSize.max($ctrl.clonedCluster, $item) }}',
+                                                tip: 'The minimal number of empty pages to be present in reuse lists for this memory policy'
+                                            })
 
-                                            //- Since ignite 2.1
-                                            .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.1.0")')
-                                                +number('Sub intervals:', '$item.subIntervals', '"MemoryPolicySubIntervals"',
-                                                    'true', '5', '1', 'A number of sub-intervals the whole rate time interval will be split into to calculate allocation and eviction rates')
-                                            .pc-form-grid-col-30(ng-if-end)
-                                                +number('Rate time interval:', '$item.rateTimeInterval', '"MemoryPolicyRateTimeInterval"',
-                                                    'true', '60000', '1000', 'Time interval for allocation rate and eviction rate monitoring purposes')
-                                                    
-                                            .pc-form-grid-col-60
-                                                +checkbox('Metrics enabled', '$item.metricsEnabled', '"MemoryPolicyMetricsEnabled"',
-                                                'Whether memory metrics are enabled by default on node startup')
+                                        //- Since ignite 2.1
+                                        .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.1.0")')
+                                            +number('Sub intervals:', '$item.subIntervals', '"MemoryPolicySubIntervals"',
+                                                'true', '5', '1', 'A number of sub-intervals the whole rate time interval will be split into to calculate allocation and eviction rates')
+                                        .pc-form-grid-col-30(ng-if-end)
+                                            +number('Rate time interval:', '$item.rateTimeInterval', '"MemoryPolicyRateTimeInterval"',
+                                                'true', '60000', '1000', 'Time interval for allocation rate and eviction rate monitoring purposes')
+                                                
+                                        .pc-form-grid-col-60
+                                            +checkbox('Metrics enabled', '$item.metricsEnabled', '"MemoryPolicyMetricsEnabled"',
+                                            'Whether memory metrics are enabled by default on node startup')
 
-                                        list-editable-no-items
-                                            list-editable-add-item-button(
-                                                add-item=`$ctrl.Clusters.addMemoryPolicy($ctrl.clonedCluster)`
-                                                label-single='memory policy configuration'
-                                                label-multiple='memory policy configurations'
-                                            )
+                                    list-editable-no-items
+                                        list-editable-add-item-button(
+                                            add-item=`$ctrl.Clusters.addMemoryPolicy($ctrl.clonedCluster)`
+                                            label-single='memory policy configuration'
+                                            label-multiple='memory policy configurations'
+                                        )
 
-                        +clusters-memory-policies
+                    +clusters-memory-policies
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterMemory')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterMemory')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.pug
index 2cfc59c..82994a9 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.pug
@@ -19,32 +19,28 @@ include /app/helpers/jade/mixins
 -var form = 'metrics'
 -var model = '$ctrl.clonedCluster'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Metrics
-        .pca-panel-heading-description
-            | Cluster runtime metrics settings.
-    .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
-                    +number('Elapsed time:', `${model}.metricsExpireTime`, '"metricsExpireTime"', 'true', 'Long.MAX_VALUE', '1',
-                        'Time in milliseconds after which a certain metric value is considered expired')
-                .pc-form-grid-col-30
-                    +number('History size:', `${model}.metricsHistorySize`, '"metricsHistorySize"', 'true', '10000', '1',
-                        'Number of metrics kept in history to compute totals and averages')
-                .pc-form-grid-col-30
-                    +number('Log frequency:', `${model}.metricsLogFrequency`, '"metricsLogFrequency"', 'true', '60000', '0',
-                        'Frequency of metrics log print out<br/>\ ' +
-                        'When <b>0</b> log print of metrics is disabled')
-                .pc-form-grid-col-30
-                    +number('Update frequency:', `${model}.metricsUpdateFrequency`, '"metricsUpdateFrequency"', 'true', '2000', '-1',
-                        'Job metrics update frequency in milliseconds\
-                        <ul>\
-                            <li>If set to -1 job metrics are never updated</li>\
-                            <li>If set to 0 job metrics are updated on each job start and finish</li>\
-                            <li>Positive value defines the actual update frequency</li>\
-                        </ul>')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterMetrics')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Metrics
+    panel-description Cluster runtime metrics settings.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +number('Elapsed time:', `${model}.metricsExpireTime`, '"metricsExpireTime"', 'true', 'Long.MAX_VALUE', '1',
+                    'Time in milliseconds after which a certain metric value is considered expired')
+            .pc-form-grid-col-30
+                +number('History size:', `${model}.metricsHistorySize`, '"metricsHistorySize"', 'true', '10000', '1',
+                    'Number of metrics kept in history to compute totals and averages')
+            .pc-form-grid-col-30
+                +number('Log frequency:', `${model}.metricsLogFrequency`, '"metricsLogFrequency"', 'true', '60000', '0',
+                    'Frequency of metrics log print out<br/>\ ' +
+                    'When <b>0</b> log print of metrics is disabled')
+            .pc-form-grid-col-30
+                +number('Update frequency:', `${model}.metricsUpdateFrequency`, '"metricsUpdateFrequency"', 'true', '2000', '-1',
+                    'Job metrics update frequency in milliseconds\
+                    <ul>\
+                        <li>If set to -1 job metrics are never updated</li>\
+                        <li>If set to 0 job metrics are updated on each job start and finish</li>\
+                        <li>Positive value defines the actual update frequency</li>\
+                    </ul>')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterMetrics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/misc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/misc.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/misc.pug
index 99f05f3..cdc7258 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/misc.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/misc.pug
@@ -19,44 +19,40 @@ include /app/helpers/jade/mixins
 -var form = 'misc'
 -var model = '$ctrl.clonedCluster'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Miscellaneous
-        .pca-panel-heading-description
-            | Various miscellaneous cluster settings.
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +text('Work directory:', model + '.workDirectory', '"workDirectory"', 'false', 'Input work directory',
-                        'Ignite work directory.<br/>\
-                        If not provided, the method will use work directory under IGNITE_HOME specified by IgniteConfiguration#setIgniteHome(String)\
-                        or IGNITE_HOME environment variable or system property.')
-
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.0.0")')
-                    +text('Consistent ID:', model + '.consistentId', '"ConsistentId"', 'false', 'Input consistent ID', 'Consistent globally unique node ID which survives node restarts')
-                .pc-form-grid-col-60
-                    +java-class('Warmup closure:', model + '.warmupClosure', '"warmupClosure"', 'true', 'false', 'This closure will be executed before actual grid instance start')
-                .pc-form-grid-col-60
-                    +checkbox('Active on start', model + '.activeOnStart', '"activeOnStart"',
-                        'If cluster is not active on start, there will be no cache partition map exchanges performed until the cluster is activated')
-                .pc-form-grid-col-60(ng-if-end)
-                    +checkbox('Cache sanity check enabled', model + '.cacheSanityCheckEnabled', '"cacheSanityCheckEnabled"',
-                        'If enabled, then Ignite will perform the following checks and throw an exception if check fails<br/>\
-                        <ul>\
-                        <li>Cache entry is not externally locked with lock or lockAsync methods when entry is enlisted to transaction</li>\
-                        <li>Each entry in affinity group - lock transaction has the same affinity key as was specified on affinity transaction start</li>\
-                        <li>Each entry in partition group - lock transaction belongs to the same partition as was specified on partition transaction start</li>\
-                        </ul>')
-
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.1.0"])')
-                    +checkbox('Late affinity assignment', model + '.lateAffinityAssignment', '"lateAffinityAssignment"',
-                        'With late affinity assignment mode if primary node was changed for some partition this nodes becomes primary only when rebalancing for all assigned primary partitions is finished')
-
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.1.0")')
-                    +number('Long query timeout:', `${model}.longQueryWarningTimeout`, '"LongQueryWarningTimeout"', 'true', '3000', '0',
-                    'Timeout in milliseconds after which long query warning will be printed')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterMisc', 'caches')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Miscellaneous
+    panel-description Various miscellaneous cluster settings.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +text('Work directory:', model + '.workDirectory', '"workDirectory"', 'false', 'Input work directory',
+                    'Ignite work directory.<br/>\
+                    If not provided, the method will use work directory under IGNITE_HOME specified by IgniteConfiguration#setIgniteHome(String)\
+                    or IGNITE_HOME environment variable or system property.')
+
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.0.0")')
+                +text('Consistent ID:', model + '.consistentId', '"ConsistentId"', 'false', 'Input consistent ID', 'Consistent globally unique node ID which survives node restarts')
+            .pc-form-grid-col-60
+                +java-class('Warmup closure:', model + '.warmupClosure', '"warmupClosure"', 'true', 'false', 'This closure will be executed before actual grid instance start')
+            .pc-form-grid-col-60
+                +checkbox('Active on start', model + '.activeOnStart', '"activeOnStart"',
+                    'If cluster is not active on start, there will be no cache partition map exchanges performed until the cluster is activated')
+            .pc-form-grid-col-60(ng-if-end)
+                +checkbox('Cache sanity check enabled', model + '.cacheSanityCheckEnabled', '"cacheSanityCheckEnabled"',
+                    'If enabled, then Ignite will perform the following checks and throw an exception if check fails<br/>\
+                    <ul>\
+                    <li>Cache entry is not externally locked with lock or lockAsync methods when entry is enlisted to transaction</li>\
+                    <li>Each entry in affinity group - lock transaction has the same affinity key as was specified on affinity transaction start</li>\
+                    <li>Each entry in partition group - lock transaction belongs to the same partition as was specified on partition transaction start</li>\
+                    </ul>')
+
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.1.0"])')
+                +checkbox('Late affinity assignment', model + '.lateAffinityAssignment', '"lateAffinityAssignment"',
+                    'With late affinity assignment mode if primary node was changed for some partition this nodes becomes primary only when rebalancing for all assigned primary partitions is finished')
+
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.1.0")')
+                +number('Long query timeout:', `${model}.longQueryWarningTimeout`, '"LongQueryWarningTimeout"', 'true', '3000', '0',
+                'Timeout in milliseconds after which long query warning will be printed')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterMisc', 'caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.pug
index b35b30c..74b1f02 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.pug
@@ -20,50 +20,51 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster.odbc'
 -var enabled = model + '.odbcEnabled'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["1.0.0", "2.1.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title ODBC configuration
-        .pca-panel-heading-description
-            | ODBC server configuration. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/odbc-driver" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available(["1.0.0", "2.1.0"]) && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6
-                .settings-row
-                    +sane-form-field-checkbox({
-                        label: 'Enabled',
-                        model: enabled,
-                        name: '"odbcEnabled"',
-                        tip: 'Flag indicating whether to configure ODBC configuration'
-                    })(
-                        ui-validate=`{
-                            correctMarshaller: '$ctrl.Clusters.odbc.odbcEnabled.correctMarshaller($ctrl.clonedCluster, $value)'
-                        }`
-                        ui-validate-watch='$ctrl.Clusters.odbc.odbcEnabled.correctMarshallerWatch("$ctrl.clonedCluster")'
-                    )
-                        +form-field-feedback(null, 'correctMarshaller', 'ODBC can only be used with BinaryMarshaller')
-                .settings-row
-                    +text-ip-address-with-port-range('ODBC endpoint address:', `${model}.endpointAddress`, '"endpointAddress"', enabled, '0.0.0.0:10800..10810',
-                        'ODBC endpoint address. <br/>\
-                        The following address formats are permitted:\
-                        <ul>\
-                            <li>hostname - will use provided hostname and default port range</li>\
-                            <li>hostname:port - will use provided hostname and port</li>\
-                            <li>hostname:port_from..port_to - will use provided hostname and port range</li>\
-                        </ul>')
-                .settings-row
-                    +number('Send buffer size:', `${model}.socketSendBufferSize`, '"ODBCSocketSendBufferSize"', enabled, '0', '0',
-                        'Socket send buffer size.<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .settings-row
-                    +number('Socket receive buffer size:', `${model}.socketReceiveBufferSize`, '"ODBCSocketReceiveBufferSize"', enabled, '0', '0',
-                        'Socket receive buffer size.<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .settings-row
-                    +number('Maximum open cursors', `${model}.maxOpenCursors`, '"maxOpenCursors"', enabled, '128', '1', 'Maximum number of opened cursors per connection')
-                .settings-row
-                    +number('Pool size:', `${model}.threadPoolSize`, '"ODBCThreadPoolSize"', enabled, 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing ODBC tasks')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterODBC')
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show='$ctrl.available(["1.0.0", "2.1.0"])'
+)
+    panel-title ODBC configuration
+    panel-description
+        | ODBC server configuration. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/odbc-driver" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`$ctrl.available(["1.0.0", "2.1.0"]) && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6
+            .settings-row
+                +sane-form-field-checkbox({
+                    label: 'Enabled',
+                    model: enabled,
+                    name: '"odbcEnabled"',
+                    tip: 'Flag indicating whether to configure ODBC configuration'
+                })(
+                    ui-validate=`{
+                        correctMarshaller: '$ctrl.Clusters.odbc.odbcEnabled.correctMarshaller($ctrl.clonedCluster, $value)'
+                    }`
+                    ui-validate-watch='$ctrl.Clusters.odbc.odbcEnabled.correctMarshallerWatch("$ctrl.clonedCluster")'
+                )
+                    +form-field-feedback(null, 'correctMarshaller', 'ODBC can only be used with BinaryMarshaller')
+            .settings-row
+                +text-ip-address-with-port-range('ODBC endpoint address:', `${model}.endpointAddress`, '"endpointAddress"', enabled, '0.0.0.0:10800..10810',
+                    'ODBC endpoint address. <br/>\
+                    The following address formats are permitted:\
+                    <ul>\
+                        <li>hostname - will use provided hostname and default port range</li>\
+                        <li>hostname:port - will use provided hostname and port</li>\
+                        <li>hostname:port_from..port_to - will use provided hostname and port range</li>\
+                    </ul>')
+            .settings-row
+                +number('Send buffer size:', `${model}.socketSendBufferSize`, '"ODBCSocketSendBufferSize"', enabled, '0', '0',
+                    'Socket send buffer size.<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .settings-row
+                +number('Socket receive buffer size:', `${model}.socketReceiveBufferSize`, '"ODBCSocketReceiveBufferSize"', enabled, '0', '0',
+                    'Socket receive buffer size.<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .settings-row
+                +number('Maximum open cursors', `${model}.maxOpenCursors`, '"maxOpenCursors"', enabled, '128', '1', 'Maximum number of opened cursors per connection')
+            .settings-row
+                +number('Pool size:', `${model}.threadPoolSize`, '"ODBCThreadPoolSize"', enabled, 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing ODBC tasks')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterODBC')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/persistence.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/persistence.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/persistence.pug
index edd1c32..2c8d10a 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/persistence.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/persistence.pug
@@ -20,62 +20,63 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster.persistenceStoreConfiguration'
 -var enabled = model + '.enabled'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["2.1.0", "2.3.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Persistence store
-        .pca-panel-heading-description
-            | Configures Apache Ignite Native Persistence.
-            a.link-success(href='https://apacheignite.readme.io/docs/distributed-persistent-store' target='_blank') More info
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available(["2.1.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', enabled, '"PersistenceEnabled"', 'Flag indicating whether to configure persistent configuration')
-                .pc-form-grid-col-60
-                    +text-enabled('Store path:', `${model}.persistentStorePath`, '"PersistenceStorePath"', enabled, 'false', 'Input store path',
-                    'A path the root directory where the Persistent Store will persist data and indexes')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Metrics enabled', `${model}.metricsEnabled`, '"PersistenceMetricsEnabled"', enabled, 'Flag indicating whether persistence metrics collection is enabled')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Always write full pages', `${model}.alwaysWriteFullPages`, '"PersistenceAlwaysWriteFullPages"', enabled, 'Flag indicating whether always write full pages')
-                .pc-form-grid-col-60
-                    +number('Checkpointing frequency:', `${model}.checkpointingFrequency`, '"PersistenceCheckpointingFrequency"', enabled, '180000', '1',
-                    'Frequency which is a minimal interval when the dirty pages will be written to the Persistent Store')
-                .pc-form-grid-col-60
-                    +number('Checkpointing page buffer size:', `${model}.checkpointingPageBufferSize`, '"PersistenceCheckpointingPageBufferSize"', enabled, '268435456', '0',
-                    'Amount of memory allocated for a checkpointing temporary buffer')
-                .pc-form-grid-col-60
-                    +number('Checkpointing threads:', `${model}.checkpointingThreads`, '"PersistenceCheckpointingThreads"', enabled, '1', '1', 'A number of threads to use for the checkpointing purposes')
-                .pc-form-grid-col-60
-                    +text-enabled('WAL store path:', `${model}.walStorePath`, '"PersistenceWalStorePath"', enabled, 'false', 'Input store path', 'A path to the directory where WAL is stored')
-                .pc-form-grid-col-60
-                    +text-enabled('WAL archive path:', `${model}.walArchivePath`, '"PersistenceWalArchivePath"', enabled, 'false', 'Input archive path', 'A path to the WAL archive directory')
-                .pc-form-grid-col-30
-                    +number('WAL segments:', `${model}.walSegments`, '"PersistenceWalSegments"', enabled, '10', '1', 'A number of WAL segments to work with')
-                .pc-form-grid-col-30
-                    +number('WAL segment size:', `${model}.walSegmentSize`, '"PersistenceWalSegmentSize"', enabled, '67108864', '0', 'Size of a WAL segment')
-                .pc-form-grid-col-30
-                    +number('WAL history size:', `${model}.walHistorySize`, '"PersistenceWalHistorySize"', enabled, '20', '1', 'A total number of checkpoints to keep in the WAL history')
-                .pc-form-grid-col-30
-                    +number('WAL flush frequency:', `${model}.walFlushFrequency`, '"PersistenceWalFlushFrequency"', enabled, '2000', '1',
-                    'How often will be fsync, in milliseconds. In background mode, exist thread which do fsync by timeout')
-                .pc-form-grid-col-30
-                    +number('WAL fsync delay:', `${model}.walFsyncDelayNanos`, '"PersistenceWalFsyncDelay"', enabled, '1000', '1', 'WAL fsync delay, in nanoseconds')
-                .pc-form-grid-col-30
-                    +number('WAL record iterator buffer size:', `${model}.walRecordIteratorBufferSize`, '"PersistenceWalRecordIteratorBufferSize"', enabled, '67108864', '1',
-                    'How many bytes iterator read from disk(for one reading), during go ahead WAL')
-                .pc-form-grid-col-30
-                    +number('Lock wait time:', `${model}.lockWaitTime`, '"PersistenceLockWaitTime"', enabled, '10000', '1',
-                    'Time out in second, while wait and try get file lock for start persist manager')
-                .pc-form-grid-col-30
-                    +number('Rate time interval:', `${model}.rateTimeInterval`, '"PersistenceRateTimeInterval"', enabled, '60000', '1000',
-                    'The length of the time interval for rate - based metrics. This interval defines a window over which hits will be tracked.')
-                .pc-form-grid-col-30
-                    +number('Thread local buffer size:', `${model}.tlbSize`, '"PersistenceTlbSize"', enabled, '131072', '1',
-                    'Define size thread local buffer. Each thread which write to WAL have thread local buffer for serialize recode before write in WAL')
-                .pc-form-grid-col-30
-                    +number('Sub intervals:', `${model}.subIntervals`, '"PersistenceSubIntervals"', enabled, '5', '1',
-                    'Number of sub - intervals the whole rate time interval will be split into to calculate rate - based metrics')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterPersistence')
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show='$ctrl.available(["2.1.0", "2.3.0"])'
+)
+    panel-title Persistence store
+    panel-description
+        | Configures Apache Ignite Native Persistence. 
+        a.link-success(href='https://apacheignite.readme.io/docs/distributed-persistent-store' target='_blank') More info
+    panel-content.pca-form-row(ng-if=`$ctrl.available(["2.1.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"PersistenceEnabled"', 'Flag indicating whether to configure persistent configuration')
+            .pc-form-grid-col-60
+                +text-enabled('Store path:', `${model}.persistentStorePath`, '"PersistenceStorePath"', enabled, 'false', 'Input store path',
+                'A path the root directory where the Persistent Store will persist data and indexes')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Metrics enabled', `${model}.metricsEnabled`, '"PersistenceMetricsEnabled"', enabled, 'Flag indicating whether persistence metrics collection is enabled')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Always write full pages', `${model}.alwaysWriteFullPages`, '"PersistenceAlwaysWriteFullPages"', enabled, 'Flag indicating whether always write full pages')
+            .pc-form-grid-col-60
+                +number('Checkpointing frequency:', `${model}.checkpointingFrequency`, '"PersistenceCheckpointingFrequency"', enabled, '180000', '1',
+                'Frequency which is a minimal interval when the dirty pages will be written to the Persistent Store')
+            .pc-form-grid-col-60
+                +number('Checkpointing page buffer size:', `${model}.checkpointingPageBufferSize`, '"PersistenceCheckpointingPageBufferSize"', enabled, '268435456', '0',
+                'Amount of memory allocated for a checkpointing temporary buffer')
+            .pc-form-grid-col-60
+                +number('Checkpointing threads:', `${model}.checkpointingThreads`, '"PersistenceCheckpointingThreads"', enabled, '1', '1', 'A number of threads to use for the checkpointing purposes')
+            .pc-form-grid-col-60
+                +text-enabled('WAL store path:', `${model}.walStorePath`, '"PersistenceWalStorePath"', enabled, 'false', 'Input store path', 'A path to the directory where WAL is stored')
+            .pc-form-grid-col-60
+                +text-enabled('WAL archive path:', `${model}.walArchivePath`, '"PersistenceWalArchivePath"', enabled, 'false', 'Input archive path', 'A path to the WAL archive directory')
+            .pc-form-grid-col-30
+                +number('WAL segments:', `${model}.walSegments`, '"PersistenceWalSegments"', enabled, '10', '1', 'A number of WAL segments to work with')
+            .pc-form-grid-col-30
+                +number('WAL segment size:', `${model}.walSegmentSize`, '"PersistenceWalSegmentSize"', enabled, '67108864', '0', 'Size of a WAL segment')
+            .pc-form-grid-col-30
+                +number('WAL history size:', `${model}.walHistorySize`, '"PersistenceWalHistorySize"', enabled, '20', '1', 'A total number of checkpoints to keep in the WAL history')
+            .pc-form-grid-col-30
+                +number('WAL flush frequency:', `${model}.walFlushFrequency`, '"PersistenceWalFlushFrequency"', enabled, '2000', '1',
+                'How often will be fsync, in milliseconds. In background mode, exist thread which do fsync by timeout')
+            .pc-form-grid-col-30
+                +number('WAL fsync delay:', `${model}.walFsyncDelayNanos`, '"PersistenceWalFsyncDelay"', enabled, '1000', '1', 'WAL fsync delay, in nanoseconds')
+            .pc-form-grid-col-30
+                +number('WAL record iterator buffer size:', `${model}.walRecordIteratorBufferSize`, '"PersistenceWalRecordIteratorBufferSize"', enabled, '67108864', '1',
+                'How many bytes iterator read from disk(for one reading), during go ahead WAL')
+            .pc-form-grid-col-30
+                +number('Lock wait time:', `${model}.lockWaitTime`, '"PersistenceLockWaitTime"', enabled, '10000', '1',
+                'Time out in second, while wait and try get file lock for start persist manager')
+            .pc-form-grid-col-30
+                +number('Rate time interval:', `${model}.rateTimeInterval`, '"PersistenceRateTimeInterval"', enabled, '60000', '1000',
+                'The length of the time interval for rate - based metrics. This interval defines a window over which hits will be tracked.')
+            .pc-form-grid-col-30
+                +number('Thread local buffer size:', `${model}.tlbSize`, '"PersistenceTlbSize"', enabled, '131072', '1',
+                'Define size thread local buffer. Each thread which write to WAL have thread local buffer for serialize recode before write in WAL')
+            .pc-form-grid-col-30
+                +number('Sub intervals:', `${model}.subIntervals`, '"PersistenceSubIntervals"', enabled, '5', '1',
+                'Number of sub - intervals the whole rate time interval will be split into to calculate rate - based metrics')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterPersistence')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/service.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/service.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/service.pug
index 7f9d75f..a244602 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/service.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/service.pug
@@ -19,74 +19,71 @@ include /app/helpers/jade/mixins
 -var form = 'serviceConfiguration'
 -var model = '$ctrl.clonedCluster.serviceConfigurations'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Service configuration
-        .pca-panel-heading-description
-            | Service Grid allows for deployments of arbitrary user-defined services on the cluster. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/fault-tolerance" 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
-                mixin clusters-service-configurations
-                    .ignite-form-field(ng-init='serviceConfigurationsTbl={type: "serviceConfigurations", model: "serviceConfigurations", focusId: "kind", ui: "failover-table"}')
-                        +ignite-form-field__label('Service configurations:', '"serviceConfigurations"')
-                        .ignite-form-field__control
-                            -let items = model
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Service configuration
+    panel-description
+        | Service Grid allows for deployments of arbitrary user-defined services on the cluster. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/fault-tolerance" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6
+            mixin clusters-service-configurations
+                .ignite-form-field(ng-init='serviceConfigurationsTbl={type: "serviceConfigurations", model: "serviceConfigurations", focusId: "kind", ui: "failover-table"}')
+                    +ignite-form-field__label('Service configurations:', '"serviceConfigurations"')
+                    .ignite-form-field__control
+                        -let items = model
 
-                            list-editable(ng-model=items name='serviceConfigurations')
-                                list-editable-item-edit
-                                    - form = '$parent.form'
-                        
-                                    -var nodeFilter = '$item.nodeFilter';
-                                    -var nodeFilterKind = nodeFilter + '.kind';
-                                    -var customFilter = nodeFilterKind + ' === "Custom"'
+                        list-editable(ng-model=items name='serviceConfigurations')
+                            list-editable-item-edit
+                                - form = '$parent.form'
+                    
+                                -var nodeFilter = '$item.nodeFilter';
+                                -var nodeFilterKind = nodeFilter + '.kind';
+                                -var customFilter = nodeFilterKind + ' === "Custom"'
 
-                                    .settings-row
-                                        +sane-ignite-form-field-text({
-                                            label: 'Name:',
-                                            model: '$item.name',
-                                            name: '"serviceName"',
-                                            required: true,
-                                            placeholder: 'Input service name'
-                                        })(
-                                            ui-validate=`{
-                                                uniqueName: '$ctrl.Clusters.serviceConfigurations.serviceConfiguration.name.customValidators.uniqueName($item, ${items})'
-                                            }`
-                                            ui-validate-watch=`"${items}"`
-                                            ui-validate-watch-object-equality='true'
-                                            ng-model-options='{allowInvalid: true}'
-                                        )
-                                            +form-field-feedback('"serviceName', 'uniqueName', 'Service with that name is already configured')
-                                    .settings-row
-                                        +java-class('Service class', '$item.service', '"serviceService"', 'true', 'true', 'Service implementation class name')
-                                    .settings-row
-                                        +number('Max per node count:', '$item.maxPerNodeCount', '"ServiceMaxPerNodeCount"', 'true', 'Unlimited', '0',
-                                            'Maximum number of deployed service instances on each node.<br/>' +
-                                            'Zero for unlimited')
-                                    .settings-row
-                                        +number('Total count:', '$item.totalCount', '"serviceTotalCount"', 'true', 'Unlimited', '0',
-                                            'Total number of deployed service instances in the cluster.<br/>' +
-                                            'Zero for unlimited')
-                                    .settings-row
-                                        +dropdown-required-empty('Cache:', '$item.cache', '"serviceCache"', 'true', 'false',
-                                            'Choose cache', 'No caches configured for current cluster', '$ctrl.cachesMenu', 'Cache name used for key-to-node affinity calculation')(
-                                            pc-is-in-collection='$ctrl.clonedCluster.caches'
-                                        ).settings-row
-                                            +form-field-feedback(form, 'isInCollection', `Cluster doesn't have such a cache`)
-                                    .settings-row
-                                        +text('Affinity key:', '$item.affinityKey', '"serviceAffinityKey"', 'false', 'Input affinity key',
-                                            'Affinity key used for key-to-node affinity calculation')
-
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$ctrl.Clusters.addServiceConfiguration($ctrl.clonedCluster)`
-                                        label-single='service configuration'
-                                        label-multiple='service configurations'
+                                .settings-row
+                                    +sane-ignite-form-field-text({
+                                        label: 'Name:',
+                                        model: '$item.name',
+                                        name: '"serviceName"',
+                                        required: true,
+                                        placeholder: 'Input service name'
+                                    })(
+                                        ui-validate=`{
+                                            uniqueName: '$ctrl.Clusters.serviceConfigurations.serviceConfiguration.name.customValidators.uniqueName($item, ${items})'
+                                        }`
+                                        ui-validate-watch=`"${items}"`
+                                        ui-validate-watch-object-equality='true'
+                                        ng-model-options='{allowInvalid: true}'
                                     )
+                                        +form-field-feedback('"serviceName', 'uniqueName', 'Service with that name is already configured')
+                                .settings-row
+                                    +java-class('Service class', '$item.service', '"serviceService"', 'true', 'true', 'Service implementation class name')
+                                .settings-row
+                                    +number('Max per node count:', '$item.maxPerNodeCount', '"ServiceMaxPerNodeCount"', 'true', 'Unlimited', '0',
+                                        'Maximum number of deployed service instances on each node.<br/>' +
+                                        'Zero for unlimited')
+                                .settings-row
+                                    +number('Total count:', '$item.totalCount', '"serviceTotalCount"', 'true', 'Unlimited', '0',
+                                        'Total number of deployed service instances in the cluster.<br/>' +
+                                        'Zero for unlimited')
+                                .settings-row
+                                    +dropdown-required-empty('Cache:', '$item.cache', '"serviceCache"', 'true', 'false',
+                                        'Choose cache', 'No caches configured for current cluster', '$ctrl.cachesMenu', 'Cache name used for key-to-node affinity calculation')(
+                                        pc-is-in-collection='$ctrl.clonedCluster.caches'
+                                    ).settings-row
+                                        +form-field-feedback(form, 'isInCollection', `Cluster doesn't have such a cache`)
+                                .settings-row
+                                    +text('Affinity key:', '$item.affinityKey', '"serviceAffinityKey"', 'false', 'Input affinity key',
+                                        'Affinity key used for key-to-node affinity calculation')
+
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$ctrl.Clusters.addServiceConfiguration($ctrl.clonedCluster)`
+                                    label-single='service configuration'
+                                    label-multiple='service configurations'
+                                )
 
-                +clusters-service-configurations
+            +clusters-service-configurations
 
-            .pca-form-column-6
-                +preview-xml-java('$ctrl.clonedCluster', 'clusterServiceConfiguration', '$ctrl.caches')
+        .pca-form-column-6
+            +preview-xml-java('$ctrl.clonedCluster', 'clusterServiceConfiguration', '$ctrl.caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/sql-connector.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/sql-connector.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/sql-connector.pug
index b52b973..2e61fc2 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/sql-connector.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/sql-connector.pug
@@ -21,37 +21,38 @@ include /app/helpers/jade/mixins
 -var connectionModel = model + '.sqlConnectorConfiguration'
 -var connectionEnabled = connectionModel + '.enabled'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["2.1.0", "2.3.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Query configuration
-        //- TODO IGNITE-5415 Add link to documentation.
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available(["2.1.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', connectionEnabled, '"SqlConnectorEnabled"', 'Flag indicating whether to configure SQL connector configuration')
-                .pc-form-grid-col-40
-                    +text-enabled('Host:', `${connectionModel}.host`, '"SqlConnectorHost"', connectionEnabled, 'false', 'localhost')
-                .pc-form-grid-col-20
-                    +number('Port:', `${connectionModel}.port`, '"SqlConnectorPort"', connectionEnabled, '10800', '1025')
-                .pc-form-grid-col-20
-                    +number('Port range:', `${connectionModel}.portRange`, '"SqlConnectorPortRange"', connectionEnabled, '100', '0')
-                .pc-form-grid-col-20
-                    +number('Socket send buffer size:', `${connectionModel}.socketSendBufferSize`, '"SqlConnectorSocketSendBufferSize"', connectionEnabled, '0', '0',
-                        'Socket send buffer size.<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .pc-form-grid-col-20
-                    +number('Socket receive buffer size:', `${connectionModel}.socketReceiveBufferSize`, '"SqlConnectorSocketReceiveBufferSize"', connectionEnabled, '0', '0',
-                        'Socket receive buffer size.<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .pc-form-grid-col-30
-                    +number('Max connection cursors:', `${connectionModel}.maxOpenCursorsPerConnection`, '"SqlConnectorMaxOpenCursorsPerConnection"', connectionEnabled, '128', '0',
-                        'Max number of opened cursors per connection')
-                .pc-form-grid-col-30
-                    +number('Pool size:', `${connectionModel}.threadPoolSize`, '"SqlConnectorThreadPoolSize"', connectionEnabled, 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing SQL requests')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('TCP_NODELAY option', `${connectionModel}.tcpNoDelay`, '"SqlConnectorTcpNoDelay"', connectionEnabled)
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterQuery')
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show='$ctrl.available(["2.1.0", "2.3.0"])'
+)
+    panel-title Query configuration
+    //- TODO IGNITE-5415 Add link to documentation.
+    panel-content.pca-form-row(ng-if=`$ctrl.available(["2.1.0", "2.3.0"]) && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Enabled', connectionEnabled, '"SqlConnectorEnabled"', 'Flag indicating whether to configure SQL connector configuration')
+            .pc-form-grid-col-40
+                +text-enabled('Host:', `${connectionModel}.host`, '"SqlConnectorHost"', connectionEnabled, 'false', 'localhost')
+            .pc-form-grid-col-20
+                +number('Port:', `${connectionModel}.port`, '"SqlConnectorPort"', connectionEnabled, '10800', '1025')
+            .pc-form-grid-col-20
+                +number('Port range:', `${connectionModel}.portRange`, '"SqlConnectorPortRange"', connectionEnabled, '100', '0')
+            .pc-form-grid-col-20
+                +number('Socket send buffer size:', `${connectionModel}.socketSendBufferSize`, '"SqlConnectorSocketSendBufferSize"', connectionEnabled, '0', '0',
+                    'Socket send buffer size.<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .pc-form-grid-col-20
+                +number('Socket receive buffer size:', `${connectionModel}.socketReceiveBufferSize`, '"SqlConnectorSocketReceiveBufferSize"', connectionEnabled, '0', '0',
+                    'Socket receive buffer size.<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .pc-form-grid-col-30
+                +number('Max connection cursors:', `${connectionModel}.maxOpenCursorsPerConnection`, '"SqlConnectorMaxOpenCursorsPerConnection"', connectionEnabled, '128', '0',
+                    'Max number of opened cursors per connection')
+            .pc-form-grid-col-30
+                +number('Pool size:', `${connectionModel}.threadPoolSize`, '"SqlConnectorThreadPoolSize"', connectionEnabled, 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing SQL requests')
+            .pc-form-grid-col-60
+                +checkbox-enabled('TCP_NODELAY option', `${connectionModel}.tcpNoDelay`, '"SqlConnectorTcpNoDelay"', connectionEnabled)
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterQuery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.pug
index f353e2e..2745f53 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.pug
@@ -22,72 +22,68 @@ include /app/helpers/jade/mixins
 -var model = cluster + '.sslContextFactory'
 -var trust = model + '.trustManagers'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title SSL configuration
-        .pca-panel-heading-description
-            | Settings for SSL configuration for creating a secure socket layer. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/ssltls" 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
-                        +checkbox('Enabled', enabled, '"sslEnabled"', 'Flag indicating whether to configure SSL configuration')
-                    .pc-form-grid-col-60
-                        +text-options('Algorithm to create a key manager:', `${model}.keyAlgorithm`, '"keyAlgorithm"', '["SumX509", "X509"]', enabled, 'false', 'SumX509',
-                            'Sets key manager algorithm that will be used to create a key manager<br/>\
-                            Notice that in most cased default value suites well, however, on Android platform this value need to be set to X509')
-                    .pc-form-grid-col-60
-                        +text-enabled('Key store file:', `${model}.keyStoreFilePath`, '"keyStoreFilePath"', enabled, enabled, 'Path to the key store file',
-                            'Path to the key store file<br/>\
-                            This is a mandatory parameter since ssl context could not be initialized without key manager')
-                    .pc-form-grid-col-30
-                        +text-options('Key store type:', `${model}.keyStoreType`, '"keyStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS',
-                            'Key store type used in context initialization')
-                    .pc-form-grid-col-30
-                        +text-options('Protocol:', `${model}.protocol`, '"protocol"', '["TSL", "SSL"]', enabled, 'false', 'TSL', 'Protocol for secure transport')
-                    .pc-form-grid-col-60
-                        .ignite-form-field
-                            .ignite-form-field__control
-                                list-editable(
-                                    ng-model=trust
-                                    name='trustManagers'
-                                    list-editable-cols=`::[{name: "Pre-configured trust managers:"}]`
-                                    ng-disabled=enabledToDisabled(enabled)
-                                    ng-required=`${enabled} && !${model}.trustStoreFilePath`
-                                )
-                                    list-editable-item-view {{ $item }}
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title SSL configuration
+    panel-description
+        | Settings for SSL configuration for creating a secure socket layer. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/ssltls" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"sslEnabled"', 'Flag indicating whether to configure SSL configuration')
+            .pc-form-grid-col-60
+                +text-options('Algorithm to create a key manager:', `${model}.keyAlgorithm`, '"keyAlgorithm"', '["SumX509", "X509"]', enabled, 'false', 'SumX509',
+                    'Sets key manager algorithm that will be used to create a key manager<br/>\
+                    Notice that in most cased default value suites well, however, on Android platform this value need to be set to X509')
+            .pc-form-grid-col-60
+                +text-enabled('Key store file:', `${model}.keyStoreFilePath`, '"keyStoreFilePath"', enabled, enabled, 'Path to the key store file',
+                    'Path to the key store file<br/>\
+                    This is a mandatory parameter since ssl context could not be initialized without key manager')
+            .pc-form-grid-col-30
+                +text-options('Key store type:', `${model}.keyStoreType`, '"keyStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS',
+                    'Key store type used in context initialization')
+            .pc-form-grid-col-30
+                +text-options('Protocol:', `${model}.protocol`, '"protocol"', '["TSL", "SSL"]', enabled, 'false', 'TSL', 'Protocol for secure transport')
+            .pc-form-grid-col-60
+                .ignite-form-field
+                    .ignite-form-field__control
+                        list-editable(
+                            ng-model=trust
+                            name='trustManagers'
+                            list-editable-cols=`::[{name: "Pre-configured trust managers:"}]`
+                            ng-disabled=enabledToDisabled(enabled)
+                            ng-required=`${enabled} && !${model}.trustStoreFilePath`
+                        )
+                            list-editable-item-view {{ $item }}
 
-                                    list-editable-item-edit
-                                        +list-java-class-field('Trust manager', '$item', '"trustManager"', trust)
-                                            +unique-feedback('"trustManager"', 'Such trust manager already exists!')
+                            list-editable-item-edit
+                                +list-java-class-field('Trust manager', '$item', '"trustManager"', trust)
+                                    +unique-feedback('"trustManager"', 'Such trust manager already exists!')
 
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${trust} = ${trust} || []).push(''))`
-                                            label-single='trust manager'
-                                            label-multiple='trust managers'
-                                        )
-                            .ignite-form-field__errors(
-                                ng-messages=`sslConfiguration.trustManagers.$error`
-                                ng-show=`sslConfiguration.trustManagers.$invalid`
-                            )
-                                +form-field-feedback(_, 'required', 'Trust managers or trust store file should be configured')
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$editLast((${trust} = ${trust} || []).push(''))`
+                                    label-single='trust manager'
+                                    label-multiple='trust managers'
+                                )
+                    .ignite-form-field__errors(
+                        ng-messages=`sslConfiguration.trustManagers.$error`
+                        ng-show=`sslConfiguration.trustManagers.$invalid`
+                    )
+                        +form-field-feedback(_, 'required', 'Trust managers or trust store file should be configured')
 
-                    .pc-form-grid-col-30(ng-if-start=`!${trust}.length`)
-                        +sane-ignite-form-field-text({
-                            label: 'Trust store file:',
-                            model: `${model}.trustStoreFilePath`,
-                            name: '"trustStoreFilePath"',
-                            required: `${enabled} && !${trust}.length`,
-                            disabled: enabledToDisabled(enabled),
-                            placeholder: 'Path to the trust store file',
-                            tip: 'Path to the trust store file'
-                        })
-                            +form-field-feedback(_, 'required', 'Trust store file or trust managers should be configured')
-                    .pc-form-grid-col-30(ng-if-end)
-                        +text-options('Trust store type:', `${model}.trustStoreType`, '"trustStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS', 'Trust store type used in context initialization')
-            .pca-form-column-6
-                +preview-xml-java(cluster, 'clusterSsl')
+            .pc-form-grid-col-30(ng-if-start=`!${trust}.length`)
+                +sane-ignite-form-field-text({
+                    label: 'Trust store file:',
+                    model: `${model}.trustStoreFilePath`,
+                    name: '"trustStoreFilePath"',
+                    required: `${enabled} && !${trust}.length`,
+                    disabled: enabledToDisabled(enabled),
+                    placeholder: 'Path to the trust store file',
+                    tip: 'Path to the trust store file'
+                })
+                    +form-field-feedback(_, 'required', 'Trust store file or trust managers should be configured')
+            .pc-form-grid-col-30(ng-if-end)
+                +text-options('Trust store type:', `${model}.trustStoreType`, '"trustStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS', 'Trust store type used in context initialization')
+        .pca-form-column-6
+            +preview-xml-java(cluster, 'clusterSsl')


[6/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 4cfbbaf..32d966a 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
@@ -42,272 +42,269 @@ mixin hibernateField(name, model, items, valid, save, newItem)
                 ignite-on-escape=onEscape
             )
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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}'
-                    )
-                        +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'`
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Store
+    panel-description 
+        | Cache store settings. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/3rd-party-store" target="_blank") More info]
+    panel-content.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}'
+                )
+                    +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
+                        +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>')
+                    .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'`
+                    -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.
+                    .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'`
+                    -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(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-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-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'
-                                    })
+                    .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')
-                .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> \
-                            <li>IgniteCache.putIfAbsent()</li> \
-                            <li>IgniteCache.replace()</li> \
-                            <li>IgniteCache.remove()</li> \
-                            <li>IgniteCache.getAndPut()</li> \
-                            <li>IgniteCache.getAndRemove()</li> \
-                            <li>IgniteCache.getAndReplace()</li> \
-                            <li> IgniteCache.getAndPutIfAbsent()</li>\
-                        </ul>')
-                .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'
+            - 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')
+            .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> \
+                        <li>IgniteCache.putIfAbsent()</li> \
+                        <li>IgniteCache.replace()</li> \
+                        <li>IgniteCache.remove()</li> \
+                        <li>IgniteCache.getAndPut()</li> \
+                        <li>IgniteCache.getAndRemove()</li> \
+                        <li>IgniteCache.getAndReplace()</li> \
+                        <li> IgniteCache.getAndPutIfAbsent()</li>\
+                    </ul>')
+            .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}'
-                        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.
-                        `
+                .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}'
                     )
-                        +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')
+                .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')
+                //- 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')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheStore', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 8994fa6..13424f8 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
@@ -22,57 +22,54 @@ include /app/helpers/jade/mixins
 -var rendezvousAff = affModel + '.kind === "Rendezvous"'
 -var customAff = affModel + '.kind === "Custom"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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"},\
-                            {value: "REPLICATED", label: "REPLICATED"},\
-                            {value: "PARTITIONED", label: "PARTITIONED"}\
-                        ]',
-                        'Cache modes:\
-                        <ul>\
-                            <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
-                            <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>')
-                .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')
-                .pc-form-grid-col-60(ng-show=`!(${model}.cacheMode && ${model}.cacheMode != "PARTITIONED")`)
-                    +number('Backups:', model + '.backups', '"backups"', 'true', '0', '0', 'Number of backup nodes')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Atomic configuration
+    panel-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]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .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"},\
+                        {value: "REPLICATED", label: "REPLICATED"},\
+                        {value: "PARTITIONED", label: "PARTITIONED"}\
+                    ]',
+                    'Cache modes:\
+                    <ul>\
+                        <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
+                        <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>')
+            .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')
+            .pc-form-grid-col-60(ng-show=`!(${model}.cacheMode && ${model}.cacheMode != "PARTITIONED")`)
+                +number('Backups:', model + '.backups', '"backups"', 'true', '0', '0', 'Number of backup nodes')
 
-                .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')
-                        .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')
-                        .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')
-                        .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')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterAtomics')
+            .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')
+                    .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')
+                    .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')
+                    .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')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterAtomics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 edff038..b57f1da 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
@@ -19,26 +19,22 @@ include /app/helpers/jade/mixins
 -var form = 'attributes'
 -var model = '$ctrl.clonedCluster'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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'
-                        })
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title User attributes
+    panel-description Configuration for Ignite user attributes.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .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')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterUserAttributes')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 9c3a48d..6c1b246 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
@@ -19,65 +19,62 @@ include /app/helpers/jade/mixins
 -var form = 'binary'
 -var model = '$ctrl.clonedCluster.binaryConfiguration'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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')
-                .pc-form-grid-col-60
-                    +java-class('Name mapper:', model + '.nameMapper', '"nameMapper"', 'true', 'false', 'Maps type/class and field names to different names')
-                .pc-form-grid-col-60
-                    +java-class('Serializer:', model + '.serializer', '"serializer"', 'true', 'false', 'Class with custom serialization logic for binary objects')
-                .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')
-
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$ctrl.Clusters.addBinaryTypeConfiguration($ctrl.clonedCluster)`
-                                        label-single='configuration'
-                                        label-multiple='configurations'
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Binary configuration
+    panel-description
+        | Configuration of specific binary types. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/binary-marshaller" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .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')
+            .pc-form-grid-col-60
+                +java-class('Name mapper:', model + '.nameMapper', '"nameMapper"', 'true', 'false', 'Maps type/class and field names to different names')
+            .pc-form-grid-col-60
+                +java-class('Serializer:', model + '.serializer', '"serializer"', 'true', 'false', 'Class with custom serialization logic for binary objects')
+            .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')
+
+                            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')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterBinary')
+            - 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')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterBinary')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 577d66c..abc8ff1 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
@@ -19,48 +19,45 @@ include /app/helpers/jade/mixins
 -var form = 'cacheKeyCfg'
 -var model = '$ctrl.clonedCluster.cacheKeyConfiguration'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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'
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Cache key configuration
+    panel-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.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .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'
                                     )
-
-                +clusters-cache-key-cfg
-
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterCacheKeyConfiguration')
+                                        +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/d24dab81/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 5adb29c..b00c98c 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
@@ -21,65 +21,62 @@ include /app/helpers/jade/mixins
 -var CustomCheckpoint = '$checkpointSPI.kind === "Custom"'
 -var CacheCheckpoint = '$checkpointSPI.kind === "Cache"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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>')
+panel-collapsible(ng-form=form)
+    panel-title Checkpointing
+    panel-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]
+    panel-content.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>')
 
-                                    include ./checkpoint/fs
+                                include ./checkpoint/fs
 
-                                    .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)
+                                .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)
 
-                                    include ./checkpoint/s3
+                                include ./checkpoint/s3
 
-                                    include ./checkpoint/jdbc
+                                include ./checkpoint/jdbc
 
-                                    .pc-form-grid-col-60(ng-if=CustomCheckpoint)
-                                        +java-class('Class name:', '$checkpointSPI.Custom.className', '"checkpointCustomClassName"', 'true', CustomCheckpoint,
-                                        'Custom CheckpointSpi implementation class', CustomCheckpoint)
+                                .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')
+                            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/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/client-connector.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/client-connector.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/client-connector.pug
index 5421255..d27fa14 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/client-connector.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/client-connector.pug
@@ -23,57 +23,54 @@ include /app/helpers/jade/mixins
 -var sslEnabled = `${connectionEnabled} && ${connectionModel}.sslEnabled`
 -var sslFactoryEnabled = `${sslEnabled} && !${connectionModel}.useIgniteSslContextFactory`
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available("2.3.0")' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Client connector configuration
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available("2.3.0") && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', connectionEnabled, '"ClientConnectorEnabled"', 'Flag indicating whether to configure client connector configuration')
-                .pc-form-grid-col-40
-                    +text-enabled('Host:', `${connectionModel}.host`, '"ClientConnectorHost"', connectionEnabled, 'false', 'localhost')
-                .pc-form-grid-col-20
-                    +number('Port:', `${connectionModel}.port`, '"ClientConnectorPort"', connectionEnabled, '10800', '1025')
-                .pc-form-grid-col-20
-                    +number('Port range:', `${connectionModel}.portRange`, '"ClientConnectorPortRange"', connectionEnabled, '100', '0')
-                .pc-form-grid-col-20
-                    +number('Socket send buffer size:', `${connectionModel}.socketSendBufferSize`, '"ClientConnectorSocketSendBufferSize"', connectionEnabled, '0', '0',
-                        'Socket send buffer size<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .pc-form-grid-col-20
-                    +number('Socket receive buffer size:', `${connectionModel}.socketReceiveBufferSize`, '"ClientConnectorSocketReceiveBufferSize"', connectionEnabled, '0', '0',
-                        'Socket receive buffer size<br/>\
-                        When set to <b>0</b>, operation system default will be used')
-                .pc-form-grid-col-30
-                    +number('Max connection cursors:', `${connectionModel}.maxOpenCursorsPerConnection`, '"ClientConnectorMaxOpenCursorsPerConnection"', connectionEnabled, '128', '0',
-                        'Max number of opened cursors per connection')
-                .pc-form-grid-col-30
-                    +number('Pool size:', `${connectionModel}.threadPoolSize`, '"ClientConnectorThreadPoolSize"', connectionEnabled, 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing SQL requests')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('TCP_NODELAY option', `${connectionModel}.tcpNoDelay`, '"ClientConnectorTcpNoDelay"', connectionEnabled)
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
-                    +number('Idle timeout:', `${connectionModel}.idleTimeout`, '"ClientConnectorIdleTimeout"', connectionEnabled, '0', '-1',
-                        'Idle timeout for client connections<br/>\
-                        Zero or negative means no timeout')
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.5.0")')
-                    +checkbox-enabled('Enable SSL', `${connectionModel}.sslEnabled`, '"ClientConnectorSslEnabled"', connectionEnabled, 'Enable secure socket layer on client connector')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Enable SSL client auth', `${connectionModel}.sslClientAuth`, '"ClientConnectorSslClientAuth"', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Use Ignite SSL', `${connectionModel}.useIgniteSslContextFactory`, '"ClientConnectorUseIgniteSslContextFactory"', sslEnabled, 'Use SSL factory Ignite configuration')
-                .pc-form-grid-col-60(ng-if-end)
-                    +java-class('SSL factory:', `${connectionModel}.sslContextFactory`, '"ClientConnectorSslContextFactory"', sslFactoryEnabled, sslFactoryEnabled,
-                    'If SSL factory specified then replication will be performed through secure SSL channel created with this factory<br/>\
-                    If not present <b>isUseIgniteSslContextFactory()</b> flag will be evaluated<br/>\
-                    If set to <b>true</b> and <b>IgniteConfiguration#getSslContextFactory()</b> exists, then Ignite SSL context factory will be used to establish secure connection')
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.4.0")')
-                    +checkbox-enabled('JDBC Enabled', `${connectionModel}.jdbcEnabled`, '"ClientConnectorJdbcEnabled"', connectionEnabled, 'Access through JDBC is enabled')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('ODBC Enabled', `${connectionModel}.odbcEnabled`, '"ClientConnectorOdbcEnabled"', connectionEnabled, 'Access through ODBC is enabled')
-                .pc-form-grid-col-60(ng-if-end)
-                    +checkbox-enabled('Thin client enabled', `${connectionModel}.thinClientEnabled`, '"ClientConnectorThinCliEnabled"', connectionEnabled, 'Access through thin client is enabled')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterClientConnector')
+panel-collapsible(ng-show='$ctrl.available("2.3.0")' ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Client connector configuration
+    panel-content.pca-form-row(ng-if=`$ctrl.available("2.3.0") && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Enabled', connectionEnabled, '"ClientConnectorEnabled"', 'Flag indicating whether to configure client connector configuration')
+            .pc-form-grid-col-40
+                +text-enabled('Host:', `${connectionModel}.host`, '"ClientConnectorHost"', connectionEnabled, 'false', 'localhost')
+            .pc-form-grid-col-20
+                +number('Port:', `${connectionModel}.port`, '"ClientConnectorPort"', connectionEnabled, '10800', '1025')
+            .pc-form-grid-col-20
+                +number('Port range:', `${connectionModel}.portRange`, '"ClientConnectorPortRange"', connectionEnabled, '100', '0')
+            .pc-form-grid-col-20
+                +number('Socket send buffer size:', `${connectionModel}.socketSendBufferSize`, '"ClientConnectorSocketSendBufferSize"', connectionEnabled, '0', '0',
+                    'Socket send buffer size<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .pc-form-grid-col-20
+                +number('Socket receive buffer size:', `${connectionModel}.socketReceiveBufferSize`, '"ClientConnectorSocketReceiveBufferSize"', connectionEnabled, '0', '0',
+                    'Socket receive buffer size<br/>\
+                    When set to <b>0</b>, operation system default will be used')
+            .pc-form-grid-col-30
+                +number('Max connection cursors:', `${connectionModel}.maxOpenCursorsPerConnection`, '"ClientConnectorMaxOpenCursorsPerConnection"', connectionEnabled, '128', '0',
+                    'Max number of opened cursors per connection')
+            .pc-form-grid-col-30
+                +number('Pool size:', `${connectionModel}.threadPoolSize`, '"ClientConnectorThreadPoolSize"', connectionEnabled, 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing SQL requests')
+            .pc-form-grid-col-60
+                +checkbox-enabled('TCP_NODELAY option', `${connectionModel}.tcpNoDelay`, '"ClientConnectorTcpNoDelay"', connectionEnabled)
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
+                +number('Idle timeout:', `${connectionModel}.idleTimeout`, '"ClientConnectorIdleTimeout"', connectionEnabled, '0', '-1',
+                    'Idle timeout for client connections<br/>\
+                    Zero or negative means no timeout')
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.5.0")')
+                +checkbox-enabled('Enable SSL', `${connectionModel}.sslEnabled`, '"ClientConnectorSslEnabled"', connectionEnabled, 'Enable secure socket layer on client connector')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Enable SSL client auth', `${connectionModel}.sslClientAuth`, '"ClientConnectorSslClientAuth"', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Use Ignite SSL', `${connectionModel}.useIgniteSslContextFactory`, '"ClientConnectorUseIgniteSslContextFactory"', sslEnabled, 'Use SSL factory Ignite configuration')
+            .pc-form-grid-col-60(ng-if-end)
+                +java-class('SSL factory:', `${connectionModel}.sslContextFactory`, '"ClientConnectorSslContextFactory"', sslFactoryEnabled, sslFactoryEnabled,
+                'If SSL factory specified then replication will be performed through secure SSL channel created with this factory<br/>\
+                If not present <b>isUseIgniteSslContextFactory()</b> flag will be evaluated<br/>\
+                If set to <b>true</b> and <b>IgniteConfiguration#getSslContextFactory()</b> exists, then Ignite SSL context factory will be used to establish secure connection')
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available("2.4.0")')
+                +checkbox-enabled('JDBC Enabled', `${connectionModel}.jdbcEnabled`, '"ClientConnectorJdbcEnabled"', connectionEnabled, 'Access through JDBC is enabled')
+            .pc-form-grid-col-60
+                +checkbox-enabled('ODBC Enabled', `${connectionModel}.odbcEnabled`, '"ClientConnectorOdbcEnabled"', connectionEnabled, 'Access through ODBC is enabled')
+            .pc-form-grid-col-60(ng-if-end)
+                +checkbox-enabled('Thin client enabled', `${connectionModel}.thinClientEnabled`, '"ClientConnectorThinCliEnabled"', connectionEnabled, 'Access through thin client is enabled')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterClientConnector')


[5/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.pug
index be07cfd..c315af1 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.pug
@@ -20,42 +20,39 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster.collision'
 -var modelCollisionKind = model + '.kind';
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Collision configuration
-        .pca-panel-heading-description
-            | Configuration Collision SPI allows to regulate how grid jobs get executed when they arrive on a destination node for execution. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/job-scheduling" 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
-                    +dropdown('CollisionSpi:', modelCollisionKind, '"collisionKind"', 'true', '',
-                        '[\
-                            {value: "JobStealing", label: "Job stealing"},\
-                            {value: "FifoQueue", label: "FIFO queue"},\
-                            {value: "PriorityQueue", label: "Priority queue"},\
-                            {value: "Custom", label: "Custom"},\
-                            {value: "Noop", label: "Default"}\
-                        ]',
-                        'Regulate how grid jobs get executed when they arrive on a destination node for execution\
-                        <ul>\
-                            <li>Job stealing - supports job stealing from over-utilized nodes to under-utilized nodes</li>\
-                            <li>FIFO queue - jobs are ordered as they arrived</li>\
-                            <li>Priority queue - jobs are first ordered by their priority</li>\
-                            <li>Custom - custom CollisionSpi implementation</li>\
-                            <li>Default - jobs are activated immediately on arrival to mapped node</li>\
-                        </ul>')
-                .pc-form-group(ng-show=`${modelCollisionKind} !== 'Noop'`)
-                    .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'JobStealing'`)
-                        include ./collision/job-stealing
-                    .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'FifoQueue'`)
-                        include ./collision/fifo-queue
-                    .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'PriorityQueue'`)
-                        include ./collision/priority-queue
-                    .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'Custom'`)
-                        include ./collision/custom
-            .pca-form-column-6
-                -var model = '$ctrl.clonedCluster.collision'
-                +preview-xml-java(model, 'clusterCollision')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Collision configuration
+    panel-description
+        | Configuration Collision SPI allows to regulate how grid jobs get executed when they arrive on a destination node for execution. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/job-scheduling" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('CollisionSpi:', modelCollisionKind, '"collisionKind"', 'true', '',
+                    '[\
+                        {value: "JobStealing", label: "Job stealing"},\
+                        {value: "FifoQueue", label: "FIFO queue"},\
+                        {value: "PriorityQueue", label: "Priority queue"},\
+                        {value: "Custom", label: "Custom"},\
+                        {value: "Noop", label: "Default"}\
+                    ]',
+                    'Regulate how grid jobs get executed when they arrive on a destination node for execution\
+                    <ul>\
+                        <li>Job stealing - supports job stealing from over-utilized nodes to under-utilized nodes</li>\
+                        <li>FIFO queue - jobs are ordered as they arrived</li>\
+                        <li>Priority queue - jobs are first ordered by their priority</li>\
+                        <li>Custom - custom CollisionSpi implementation</li>\
+                        <li>Default - jobs are activated immediately on arrival to mapped node</li>\
+                    </ul>')
+            .pc-form-group(ng-show=`${modelCollisionKind} !== 'Noop'`)
+                .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'JobStealing'`)
+                    include ./collision/job-stealing
+                .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'FifoQueue'`)
+                    include ./collision/fifo-queue
+                .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'PriorityQueue'`)
+                    include ./collision/priority-queue
+                .pc-form-grid-row(ng-show=`${modelCollisionKind} === 'Custom'`)
+                    include ./collision/custom
+        .pca-form-column-6
+            -var model = '$ctrl.clonedCluster.collision'
+            +preview-xml-java(model, 'clusterCollision')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.pug
index 7fa92e1..bd8971a 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.pug
@@ -20,118 +20,115 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster'
 -var communication = model + '.communication'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Communication
-        .pca-panel-heading-description
-            | Configuration of communication with other nodes by TCP/IP.
-            | Provide basic plumbing to send and receive grid messages and is utilized for all distributed grid operations. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/network-config" 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
-                    +number('Timeout:', `${model}.networkTimeout`, '"commNetworkTimeout"', 'true', '5000', '1', 'Maximum timeout in milliseconds for network requests')
-                .pc-form-grid-col-30
-                    +number('Send retry delay:', `${model}.networkSendRetryDelay`, '"networkSendRetryDelay"', 'true', '1000', '1', 'Interval in milliseconds between message send retries')
-                .pc-form-grid-col-30
-                    +number('Send retry count:', `${model}.networkSendRetryCount`, '"networkSendRetryCount"', 'true', '3', '1', 'Message send retries count')
-                .pc-form-grid-col-30(ng-if='$ctrl.available(["1.0.0", "2.3.0"])')
-                    +number('Discovery startup delay:', `${model}.discoveryStartupDelay`, '"discoveryStartupDelay"', 'true', '60000', '1', 'This value is used to expire messages from waiting list whenever node discovery discrepancies happen')
-                .pc-form-grid-col-60
-                    +java-class('Communication listener:', `${communication}.listener`, '"comListener"', 'true', 'false', 'Listener of communication events')
-                .pc-form-grid-col-30
-                    +text-ip-address('Local IP address:', `${communication}.localAddress`, '"comLocalAddress"', 'true', '0.0.0.0',
-                        'Local host address for socket binding<br/>\
-                        If not specified use all available addres on local host')
-                .pc-form-grid-col-30
-                    +number-min-max('Local port:', `${communication}.localPort`, '"comLocalPort"', 'true', '47100', '1024', '65535', 'Local port for socket binding')
-                .pc-form-grid-col-30
-                    +number('Local port range:', `${communication}.localPortRange`, '"comLocalPortRange"', 'true', '100', '1', 'Local port range for local host ports')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Shared memory port:',
-                        model: `${communication}.sharedMemoryPort`,
-                        name: '"sharedMemoryPort"',
-                        placeholder: '{{ ::$ctrl.Clusters.sharedMemoryPort.default }}',
-                        min: '{{ ::$ctrl.Clusters.sharedMemoryPort.min }}',
-                        max: '{{ ::$ctrl.Clusters.sharedMemoryPort.max }}',
-                        tip: `Local port to accept shared memory connections<br/>If set to <b>-1</b> shared memory communication will be disabled`
-                    })(
-                        pc-not-in-collection='::$ctrl.Clusters.sharedMemoryPort.invalidValues'
-                    )
-                        +form-field-feedback('"sharedMemoryPort"', 'notInCollection', 'Shared memory port should be more than "{{ ::$ctrl.Clusters.sharedMemoryPort.invalidValues[0] }}" or equal to "{{ ::$ctrl.Clusters.sharedMemoryPort.min }}"')
-                .pc-form-grid-col-30
-                    +number('Idle connection timeout:', `${communication}.idleConnectionTimeout`, '"idleConnectionTimeout"', 'true', '30000', '1',
-                        'Maximum idle connection timeout upon which a connection to client will be closed')
-                .pc-form-grid-col-30
-                    +number('Connect timeout:', `${communication}.connectTimeout`, '"connectTimeout"', 'true', '5000', '0', 'Connect timeout used when establishing connection with remote nodes')
-                .pc-form-grid-col-30
-                    +number('Max. connect timeout:', `${communication}.maxConnectTimeout`, '"maxConnectTimeout"', 'true', '600000', '0', 'Maximum connect timeout')
-                .pc-form-grid-col-30
-                    +number('Reconnect count:', `${communication}.reconnectCount`, '"comReconnectCount"', 'true', '10', '1',
-                        'Maximum number of reconnect attempts used when establishing connection with remote nodes')
-                .pc-form-grid-col-30
-                    +number('Socket send buffer:', `${communication}.socketSendBuffer`, '"socketSendBuffer"', 'true', '32768', '0', 'Send buffer size for sockets created or accepted by this SPI')
-                .pc-form-grid-col-30
-                    +number('Socket receive buffer:', `${communication}.socketReceiveBuffer`, '"socketReceiveBuffer"', 'true', '32768', '0', 'Receive buffer size for sockets created or accepted by this SPI')
-                .pc-form-grid-col-30
-                    +number('Slow client queue limit:', `${communication}.slowClientQueueLimit`, '"slowClientQueueLimit"', 'true', '0', '0', 'Slow client queue limit')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Ack send threshold:',
-                        model: `${communication}.ackSendThreshold`,
-                        name: '"ackSendThreshold"',
-                        placeholder: '{{ ::$ctrl.Clusters.ackSendThreshold.default }}',
-                        min: '{{ ::$ctrl.Clusters.ackSendThreshold.min }}',
-                        tip: 'Number of received messages per connection to node after which acknowledgment message is sent'
-                    })
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Message queue limit:',
-                        model: `${communication}.messageQueueLimit`,
-                        name: '"messageQueueLimit"',
-                        placeholder: '{{ ::$ctrl.Clusters.messageQueueLimit.default }}',
-                        min: '{{ ::$ctrl.Clusters.messageQueueLimit.min }}',
-                        tip: 'Message queue limit for incoming and outgoing messages'
-                    })
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Unacknowledged messages:',
-                        model: `${communication}.unacknowledgedMessagesBufferSize`,
-                        name: '"unacknowledgedMessagesBufferSize"',
-                        placeholder: '{{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.default }}',
-                        min: `{{ $ctrl.Clusters.unacknowledgedMessagesBufferSize.min(
-                            ${communication}.unacknowledgedMessagesBufferSize,
-                            ${communication}.messageQueueLimit,
-                            ${communication}.ackSendThreshold
-                        ) }}`,
-                        tip: `Maximum number of stored unacknowledged messages per connection to node<br/>
-                        If specified non zero value it should be
-                        <ul>
-                            <li>At least ack send threshold * {{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.validRatio }}</li>
-                            <li>At least message queue limit * {{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.validRatio }}</li>
-                        </ul>`
-                    })(
-                        //- allowInvalid: true prevents from infinite digest loop when old value was 0 and becomes less than allowed minimum
-                        ng-model-options=`{
-                            allowInvalid: true
-                        }`
-                    )
-                .pc-form-grid-col-30
-                    +number('Socket write timeout:', `${communication}.socketWriteTimeout`, '"socketWriteTimeout"', 'true', '2000', '0', 'Socket write timeout')
-                .pc-form-grid-col-30
-                    +number('Selectors count:', `${communication}.selectorsCount`, '"selectorsCount"', 'true', 'min(4, availableProcessors)', '1', 'Count of selectors te be used in TCP server')
-                .pc-form-grid-col-60
-                    +java-class('Address resolver:', `${communication}.addressResolver`, '"comAddressResolver"', 'true', 'false', 'Provides resolution between external and internal addresses')
-                .pc-form-grid-col-60
-                    +checkbox('Direct buffer', `${communication}.directBuffer`, '"directBuffer"',
-                    'If value is true, then SPI will use ByteBuffer.allocateDirect(int) call<br/>\
-                    Otherwise, SPI will use ByteBuffer.allocate(int) call')
-                .pc-form-grid-col-60
-                    +checkbox('Direct send buffer', `${communication}.directSendBuffer`, '"directSendBuffer"', 'Flag defining whether direct send buffer should be used')
-                .pc-form-grid-col-60
-                    +checkbox('TCP_NODELAY option', `${communication}.tcpNoDelay`, '"tcpNoDelay"', 'Value for TCP_NODELAY socket option')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterCommunication')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Communication
+    panel-description
+        | Configuration of communication with other nodes by TCP/IP.
+        | Provide basic plumbing to send and receive grid messages and is utilized for all distributed grid operations. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/network-config" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +number('Timeout:', `${model}.networkTimeout`, '"commNetworkTimeout"', 'true', '5000', '1', 'Maximum timeout in milliseconds for network requests')
+            .pc-form-grid-col-30
+                +number('Send retry delay:', `${model}.networkSendRetryDelay`, '"networkSendRetryDelay"', 'true', '1000', '1', 'Interval in milliseconds between message send retries')
+            .pc-form-grid-col-30
+                +number('Send retry count:', `${model}.networkSendRetryCount`, '"networkSendRetryCount"', 'true', '3', '1', 'Message send retries count')
+            .pc-form-grid-col-30(ng-if='$ctrl.available(["1.0.0", "2.3.0"])')
+                +number('Discovery startup delay:', `${model}.discoveryStartupDelay`, '"discoveryStartupDelay"', 'true', '60000', '1', 'This value is used to expire messages from waiting list whenever node discovery discrepancies happen')
+            .pc-form-grid-col-60
+                +java-class('Communication listener:', `${communication}.listener`, '"comListener"', 'true', 'false', 'Listener of communication events')
+            .pc-form-grid-col-30
+                +text-ip-address('Local IP address:', `${communication}.localAddress`, '"comLocalAddress"', 'true', '0.0.0.0',
+                    'Local host address for socket binding<br/>\
+                    If not specified use all available addres on local host')
+            .pc-form-grid-col-30
+                +number-min-max('Local port:', `${communication}.localPort`, '"comLocalPort"', 'true', '47100', '1024', '65535', 'Local port for socket binding')
+            .pc-form-grid-col-30
+                +number('Local port range:', `${communication}.localPortRange`, '"comLocalPortRange"', 'true', '100', '1', 'Local port range for local host ports')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Shared memory port:',
+                    model: `${communication}.sharedMemoryPort`,
+                    name: '"sharedMemoryPort"',
+                    placeholder: '{{ ::$ctrl.Clusters.sharedMemoryPort.default }}',
+                    min: '{{ ::$ctrl.Clusters.sharedMemoryPort.min }}',
+                    max: '{{ ::$ctrl.Clusters.sharedMemoryPort.max }}',
+                    tip: `Local port to accept shared memory connections<br/>If set to <b>-1</b> shared memory communication will be disabled`
+                })(
+                    pc-not-in-collection='::$ctrl.Clusters.sharedMemoryPort.invalidValues'
+                )
+                    +form-field-feedback('"sharedMemoryPort"', 'notInCollection', 'Shared memory port should be more than "{{ ::$ctrl.Clusters.sharedMemoryPort.invalidValues[0] }}" or equal to "{{ ::$ctrl.Clusters.sharedMemoryPort.min }}"')
+            .pc-form-grid-col-30
+                +number('Idle connection timeout:', `${communication}.idleConnectionTimeout`, '"idleConnectionTimeout"', 'true', '30000', '1',
+                    'Maximum idle connection timeout upon which a connection to client will be closed')
+            .pc-form-grid-col-30
+                +number('Connect timeout:', `${communication}.connectTimeout`, '"connectTimeout"', 'true', '5000', '0', 'Connect timeout used when establishing connection with remote nodes')
+            .pc-form-grid-col-30
+                +number('Max. connect timeout:', `${communication}.maxConnectTimeout`, '"maxConnectTimeout"', 'true', '600000', '0', 'Maximum connect timeout')
+            .pc-form-grid-col-30
+                +number('Reconnect count:', `${communication}.reconnectCount`, '"comReconnectCount"', 'true', '10', '1',
+                    'Maximum number of reconnect attempts used when establishing connection with remote nodes')
+            .pc-form-grid-col-30
+                +number('Socket send buffer:', `${communication}.socketSendBuffer`, '"socketSendBuffer"', 'true', '32768', '0', 'Send buffer size for sockets created or accepted by this SPI')
+            .pc-form-grid-col-30
+                +number('Socket receive buffer:', `${communication}.socketReceiveBuffer`, '"socketReceiveBuffer"', 'true', '32768', '0', 'Receive buffer size for sockets created or accepted by this SPI')
+            .pc-form-grid-col-30
+                +number('Slow client queue limit:', `${communication}.slowClientQueueLimit`, '"slowClientQueueLimit"', 'true', '0', '0', 'Slow client queue limit')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Ack send threshold:',
+                    model: `${communication}.ackSendThreshold`,
+                    name: '"ackSendThreshold"',
+                    placeholder: '{{ ::$ctrl.Clusters.ackSendThreshold.default }}',
+                    min: '{{ ::$ctrl.Clusters.ackSendThreshold.min }}',
+                    tip: 'Number of received messages per connection to node after which acknowledgment message is sent'
+                })
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Message queue limit:',
+                    model: `${communication}.messageQueueLimit`,
+                    name: '"messageQueueLimit"',
+                    placeholder: '{{ ::$ctrl.Clusters.messageQueueLimit.default }}',
+                    min: '{{ ::$ctrl.Clusters.messageQueueLimit.min }}',
+                    tip: 'Message queue limit for incoming and outgoing messages'
+                })
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Unacknowledged messages:',
+                    model: `${communication}.unacknowledgedMessagesBufferSize`,
+                    name: '"unacknowledgedMessagesBufferSize"',
+                    placeholder: '{{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.default }}',
+                    min: `{{ $ctrl.Clusters.unacknowledgedMessagesBufferSize.min(
+                        ${communication}.unacknowledgedMessagesBufferSize,
+                        ${communication}.messageQueueLimit,
+                        ${communication}.ackSendThreshold
+                    ) }}`,
+                    tip: `Maximum number of stored unacknowledged messages per connection to node<br/>
+                    If specified non zero value it should be
+                    <ul>
+                        <li>At least ack send threshold * {{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.validRatio }}</li>
+                        <li>At least message queue limit * {{ ::$ctrl.Clusters.unacknowledgedMessagesBufferSize.validRatio }}</li>
+                    </ul>`
+                })(
+                    //- allowInvalid: true prevents from infinite digest loop when old value was 0 and becomes less than allowed minimum
+                    ng-model-options=`{
+                        allowInvalid: true
+                    }`
+                )
+            .pc-form-grid-col-30
+                +number('Socket write timeout:', `${communication}.socketWriteTimeout`, '"socketWriteTimeout"', 'true', '2000', '0', 'Socket write timeout')
+            .pc-form-grid-col-30
+                +number('Selectors count:', `${communication}.selectorsCount`, '"selectorsCount"', 'true', 'min(4, availableProcessors)', '1', 'Count of selectors te be used in TCP server')
+            .pc-form-grid-col-60
+                +java-class('Address resolver:', `${communication}.addressResolver`, '"comAddressResolver"', 'true', 'false', 'Provides resolution between external and internal addresses')
+            .pc-form-grid-col-60
+                +checkbox('Direct buffer', `${communication}.directBuffer`, '"directBuffer"',
+                'If value is true, then SPI will use ByteBuffer.allocateDirect(int) call<br/>\
+                Otherwise, SPI will use ByteBuffer.allocate(int) call')
+            .pc-form-grid-col-60
+                +checkbox('Direct send buffer', `${communication}.directSendBuffer`, '"directSendBuffer"', 'Flag defining whether direct send buffer should be used')
+            .pc-form-grid-col-60
+                +checkbox('TCP_NODELAY option', `${communication}.tcpNoDelay`, '"tcpNoDelay"', 'Value for TCP_NODELAY socket option')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterCommunication')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.pug
index 50975b7..76c5016 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.pug
@@ -21,83 +21,80 @@ include /app/helpers/jade/mixins
 -var enabled = model + '.enabled'
 -var sslEnabled = enabled + ' && ' + model + '.sslEnabled'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Connector configuration
-        .pca-panel-heading-description
-            | Configure HTTP REST configuration to enable HTTP server features. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/rest-api#general-configuration" 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
-                    +checkbox('Enabled', enabled, '"restEnabled"', 'Flag indicating whether to configure connector configuration')
-                .pc-form-grid-col-60
-                    +text-enabled('Jetty configuration path:', `${model}.jettyPath`, '"connectorJettyPath"', enabled, 'false', 'Input path to Jetty configuration',
-                        'Path, either absolute or relative to IGNITE_HOME, to Jetty XML configuration file<br/>\
-                        Jetty is used to support REST over HTTP protocol for accessing Ignite APIs remotely<br/>\
-                        If not provided, Jetty instance with default configuration will be started picking IgniteSystemProperties.IGNITE_JETTY_HOST and IgniteSystemProperties.IGNITE_JETTY_PORT as host and port respectively')
-                .pc-form-grid-col-20
-                    +text-ip-address('TCP host:', `${model}.host`, '"connectorHost"', enabled, 'IgniteConfiguration#getLocalHost()',
-                        'Host for TCP binary protocol server<br/>\
-                        This can be either an IP address or a domain name<br/>\
-                        If not defined, system - wide local address will be used IgniteConfiguration#getLocalHost()<br/>\
-                        You can also use "0.0.0.0" value to bind to all locally - available IP addresses')
-                .pc-form-grid-col-20
-                    +number-min-max('TCP port:', `${model}.port`, '"connectorPort"', enabled, '11211', '1024', '65535', 'Port for TCP binary protocol server')
-                .pc-form-grid-col-20
-                    +number('TCP port range:', `${model}.portRange`, '"connectorPortRange"', enabled, '100', '1', 'Number of ports for TCP binary protocol server to try if configured port is already in use')
-                .pc-form-grid-col-60
-                    +number('Idle query cursor timeout:', `${model}.idleQueryCursorTimeout`, '"connectorIdleQueryCursorTimeout"', enabled, '600000', '0',
-                        'Reject open query cursors that is not used timeout<br/>\
-                        If no fetch query request come within idle timeout, it will be removed on next check for old query cursors')
-                .pc-form-grid-col-60
-                    +number('Idle query cursor check frequency:', `${model}.idleQueryCursorCheckFrequency`, '"connectorIdleQueryCursorCheckFrequency"', enabled, '60000', '0',
-                        'Idle query cursors check frequency<br/>\
-                        This setting is used to reject open query cursors that is not used')
-                .pc-form-grid-col-30
-                    +number('Idle timeout:', `${model}.idleTimeout`, '"connectorIdleTimeout"', enabled, '7000', '0',
-                        'Idle timeout for REST server<br/>\
-                        This setting is used to reject half - opened sockets<br/>\
-                        If no packets come within idle timeout, the connection is closed')
-                .pc-form-grid-col-30
-                    +number('Receive buffer size:', `${model}.receiveBufferSize`, '"connectorReceiveBufferSize"', enabled, '32768', '0', 'REST TCP server receive buffer size')
-                .pc-form-grid-col-30
-                    +number('Send buffer size:', `${model}.sendBufferSize`, '"connectorSendBufferSize"', enabled, '32768', '0', 'REST TCP server send buffer size')
-                .pc-form-grid-col-30
-                    +number('Send queue limit:', `${model}.sendQueueLimit`, '"connectorSendQueueLimit"', enabled, 'unlimited', '0',
-                        'REST TCP server send queue limit<br/>\
-                        If the limit exceeds, all successive writes will block until the queue has enough capacity')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Direct buffer', `${model}.directBuffer`, '"connectorDirectBuffer"', enabled,
-                        'Flag indicating whether REST TCP server should use direct buffers<br/>\
-                        A direct buffer is a buffer that is allocated and accessed using native system calls, without using JVM heap<br/>\
-                        Enabling direct buffer may improve performance and avoid memory issues(long GC pauses due to huge buffer size)')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('TCP_NODELAY option', `${model}.noDelay`, '"connectorNoDelay"', enabled,
-                        'Flag indicating whether TCP_NODELAY option should be set for accepted client connections<br/>\
-                        Setting this option reduces network latency and should be enabled in majority of cases<br/>\
-                        For more information, see Socket#setTcpNoDelay(boolean)')
-                .pc-form-grid-col-30
-                    +number('Selector count:', `${model}.selectorCount`, '"connectorSelectorCount"', enabled, 'min(4, availableProcessors)', '1',
-                        'Number of selector threads in REST TCP server<br/>\
-                        Higher value for this parameter may increase throughput, but also increases context switching')
-                .pc-form-grid-col-30
-                    +number('Thread pool size:', `${model}.threadPoolSize`, '"connectorThreadPoolSize"', enabled, 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool size to use for processing of client messages (REST requests)')
-                .pc-form-grid-col-60
-                    +java-class('Message interceptor:', `${model}.messageInterceptor`, '"connectorMessageInterceptor"', enabled, 'false',
-                        'Interceptor allows to transform all objects exchanged via REST protocol<br/>\
-                        For example if you use custom serialisation on client you can write interceptor to transform binary representations received from client to Java objects and later access them from java code directly')
-                .pc-form-grid-col-60
-                    +text-enabled('Secret key:', `${model}.secretKey`, '"connectorSecretKey"', enabled, 'false', 'Specify to enable authentication', 'Secret key to authenticate REST requests')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Enable SSL', `${model}.sslEnabled`, '"connectorSslEnabled"', enabled, 'Enables/disables SSL for REST TCP binary protocol')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Enable SSL client auth', `${model}.sslClientAuth`, '"connectorSslClientAuth"', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
-                .pc-form-grid-col-60
-                    +java-class('SSL factory:', `${model}.sslFactory`, '"connectorSslFactory"', sslEnabled, sslEnabled,
-                        'Instance of Factory that will be used to create an instance of SSLContext for Secure Socket Layer on TCP binary protocol')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterConnector')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Connector configuration
+    panel-description
+        | Configure HTTP REST configuration to enable HTTP server features. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/rest-api#general-configuration" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"restEnabled"', 'Flag indicating whether to configure connector configuration')
+            .pc-form-grid-col-60
+                +text-enabled('Jetty configuration path:', `${model}.jettyPath`, '"connectorJettyPath"', enabled, 'false', 'Input path to Jetty configuration',
+                    'Path, either absolute or relative to IGNITE_HOME, to Jetty XML configuration file<br/>\
+                    Jetty is used to support REST over HTTP protocol for accessing Ignite APIs remotely<br/>\
+                    If not provided, Jetty instance with default configuration will be started picking IgniteSystemProperties.IGNITE_JETTY_HOST and IgniteSystemProperties.IGNITE_JETTY_PORT as host and port respectively')
+            .pc-form-grid-col-20
+                +text-ip-address('TCP host:', `${model}.host`, '"connectorHost"', enabled, 'IgniteConfiguration#getLocalHost()',
+                    'Host for TCP binary protocol server<br/>\
+                    This can be either an IP address or a domain name<br/>\
+                    If not defined, system - wide local address will be used IgniteConfiguration#getLocalHost()<br/>\
+                    You can also use "0.0.0.0" value to bind to all locally - available IP addresses')
+            .pc-form-grid-col-20
+                +number-min-max('TCP port:', `${model}.port`, '"connectorPort"', enabled, '11211', '1024', '65535', 'Port for TCP binary protocol server')
+            .pc-form-grid-col-20
+                +number('TCP port range:', `${model}.portRange`, '"connectorPortRange"', enabled, '100', '1', 'Number of ports for TCP binary protocol server to try if configured port is already in use')
+            .pc-form-grid-col-60
+                +number('Idle query cursor timeout:', `${model}.idleQueryCursorTimeout`, '"connectorIdleQueryCursorTimeout"', enabled, '600000', '0',
+                    'Reject open query cursors that is not used timeout<br/>\
+                    If no fetch query request come within idle timeout, it will be removed on next check for old query cursors')
+            .pc-form-grid-col-60
+                +number('Idle query cursor check frequency:', `${model}.idleQueryCursorCheckFrequency`, '"connectorIdleQueryCursorCheckFrequency"', enabled, '60000', '0',
+                    'Idle query cursors check frequency<br/>\
+                    This setting is used to reject open query cursors that is not used')
+            .pc-form-grid-col-30
+                +number('Idle timeout:', `${model}.idleTimeout`, '"connectorIdleTimeout"', enabled, '7000', '0',
+                    'Idle timeout for REST server<br/>\
+                    This setting is used to reject half - opened sockets<br/>\
+                    If no packets come within idle timeout, the connection is closed')
+            .pc-form-grid-col-30
+                +number('Receive buffer size:', `${model}.receiveBufferSize`, '"connectorReceiveBufferSize"', enabled, '32768', '0', 'REST TCP server receive buffer size')
+            .pc-form-grid-col-30
+                +number('Send buffer size:', `${model}.sendBufferSize`, '"connectorSendBufferSize"', enabled, '32768', '0', 'REST TCP server send buffer size')
+            .pc-form-grid-col-30
+                +number('Send queue limit:', `${model}.sendQueueLimit`, '"connectorSendQueueLimit"', enabled, 'unlimited', '0',
+                    'REST TCP server send queue limit<br/>\
+                    If the limit exceeds, all successive writes will block until the queue has enough capacity')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Direct buffer', `${model}.directBuffer`, '"connectorDirectBuffer"', enabled,
+                    'Flag indicating whether REST TCP server should use direct buffers<br/>\
+                    A direct buffer is a buffer that is allocated and accessed using native system calls, without using JVM heap<br/>\
+                    Enabling direct buffer may improve performance and avoid memory issues(long GC pauses due to huge buffer size)')
+            .pc-form-grid-col-60
+                +checkbox-enabled('TCP_NODELAY option', `${model}.noDelay`, '"connectorNoDelay"', enabled,
+                    'Flag indicating whether TCP_NODELAY option should be set for accepted client connections<br/>\
+                    Setting this option reduces network latency and should be enabled in majority of cases<br/>\
+                    For more information, see Socket#setTcpNoDelay(boolean)')
+            .pc-form-grid-col-30
+                +number('Selector count:', `${model}.selectorCount`, '"connectorSelectorCount"', enabled, 'min(4, availableProcessors)', '1',
+                    'Number of selector threads in REST TCP server<br/>\
+                    Higher value for this parameter may increase throughput, but also increases context switching')
+            .pc-form-grid-col-30
+                +number('Thread pool size:', `${model}.threadPoolSize`, '"connectorThreadPoolSize"', enabled, 'max(8, availableProcessors) * 2', '1',
+                    'Thread pool size to use for processing of client messages (REST requests)')
+            .pc-form-grid-col-60
+                +java-class('Message interceptor:', `${model}.messageInterceptor`, '"connectorMessageInterceptor"', enabled, 'false',
+                    'Interceptor allows to transform all objects exchanged via REST protocol<br/>\
+                    For example if you use custom serialisation on client you can write interceptor to transform binary representations received from client to Java objects and later access them from java code directly')
+            .pc-form-grid-col-60
+                +text-enabled('Secret key:', `${model}.secretKey`, '"connectorSecretKey"', enabled, 'false', 'Specify to enable authentication', 'Secret key to authenticate REST requests')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Enable SSL', `${model}.sslEnabled`, '"connectorSslEnabled"', enabled, 'Enables/disables SSL for REST TCP binary protocol')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Enable SSL client auth', `${model}.sslClientAuth`, '"connectorSslClientAuth"', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
+            .pc-form-grid-col-60
+                +java-class('SSL factory:', `${model}.sslFactory`, '"connectorSslFactory"', sslEnabled, sslEnabled,
+                    'Instance of Factory that will be used to create an instance of SSLContext for Secure Socket Layer on TCP binary protocol')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterConnector')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/data-storage.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/data-storage.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/data-storage.pug
index b605fad..c9fea56 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/data-storage.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/data-storage.pug
@@ -135,170 +135,167 @@ mixin data-region-form({modelAt, namePlaceholder, dataRegionsAt})
         +checkbox('Persistence enabled', `${modelAt}.persistenceEnabled`, '"RegionPersistenceEnabled" + $index',
         'Enable Ignite Native Persistence')
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available("2.3.0")' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Data storage configuration
-        .pca-panel-heading-description
-            | Page memory is a manageable off-heap based memory architecture that is split into pages of fixed size. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/distributed-persistent-store" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available("2.3.0") && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
+panel-collapsible(ng-show='$ctrl.available("2.3.0")' ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Data storage configuration
+    panel-description
+        | Page memory is a manageable off-heap based memory architecture that is split into pages of fixed size. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/distributed-persistent-store" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`$ctrl.available("2.3.0") && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-dropdown({
+                    label: 'Page size:',
+                    model: `${model}.pageSize`,
+                    name: '"DataStorageConfigurationPageSize"',
+                    options: `$ctrl.Clusters.dataStorageConfiguration.pageSize.values`,
+                    tip: 'Every memory region is split on pages of fixed size'
+                })
+            .pc-form-grid-col-30
+                +number('Concurrency level:', model + '.concurrencyLevel', '"DataStorageConfigurationConcurrencyLevel"',
+                'true', 'availableProcessors', '2', 'The number of concurrent segments in Ignite internal page mapping tables')
+            .pc-form-grid-col-60.pc-form-group__text-title
+                span System region
+            .pc-form-group.pc-form-grid-row
                 .pc-form-grid-col-30
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Page size:',
-                        model: `${model}.pageSize`,
-                        name: '"DataStorageConfigurationPageSize"',
-                        options: `$ctrl.Clusters.dataStorageConfiguration.pageSize.values`,
-                        tip: 'Every memory region is split on pages of fixed size'
-                    })
+                    pc-form-field-size(
+                        label='Initial size:'
+                        ng-model=`${model}.systemRegionInitialSize`
+                        name='DataStorageSystemRegionInitialSize'
+                        placeholder='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionInitialSize.default / systemRegionInitialSizeScale.value }}'
+                        min='{{ ::$ctrl.Clusters.dataStorageConfiguration.systemRegionInitialSize.min }}'
+                        tip='Initial size of a data region reserved for system cache'
+                        on-scale-change='systemRegionInitialSizeScale = $event'
+                    )
                 .pc-form-grid-col-30
-                    +number('Concurrency level:', model + '.concurrencyLevel', '"DataStorageConfigurationConcurrencyLevel"',
-                    'true', 'availableProcessors', '2', 'The number of concurrent segments in Ignite internal page mapping tables')
-                .pc-form-grid-col-60.pc-form-group__text-title
-                    span System region
-                .pc-form-group.pc-form-grid-row
-                    .pc-form-grid-col-30
-                        pc-form-field-size(
-                            label='Initial size:'
-                            ng-model=`${model}.systemRegionInitialSize`
-                            name='DataStorageSystemRegionInitialSize'
-                            placeholder='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionInitialSize.default / systemRegionInitialSizeScale.value }}'
-                            min='{{ ::$ctrl.Clusters.dataStorageConfiguration.systemRegionInitialSize.min }}'
-                            tip='Initial size of a data region reserved for system cache'
-                            on-scale-change='systemRegionInitialSizeScale = $event'
-                        )
-                    .pc-form-grid-col-30
-                        pc-form-field-size(
-                            label='Max size:'
-                            ng-model=`${model}.systemRegionMaxSize`
-                            name='DataStorageSystemRegionMaxSize'
-                            placeholder='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionMaxSize.default / systemRegionMaxSizeScale.value }}'
-                            min='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionMaxSize.min($ctrl.clonedCluster) }}'
-                            tip='Maximum data region size reserved for system cache'
-                            on-scale-change='systemRegionMaxSizeScale = $event'
-                        )
-                .pc-form-grid-col-60.pc-form-group__text-title
-                    span Default data region
-                .pc-form-group.pc-form-grid-row
-                    +data-region-form({
-                        modelAt: dfltRegionModel,
-                        namePlaceholder: '{{ ::$ctrl.Clusters.dataRegion.name.default }}',
-                        dataRegionsAt: dataRegionConfigurations
-                    })
-                .pc-form-grid-col-60
-                    .ignite-form-field
-                        .ignite-form-field__label Data region configurations
-                        .ignite-form-field__control
-                            list-editable(name='dataRegionConfigurations' ng-model=dataRegionConfigurations)
-                                list-editable-item-edit.pc-form-grid-row
-                                    - form = '$parent.form'
-                                    +data-region-form({
-                                        modelAt: '$item',
-                                        namePlaceholder: 'Data region name',
-                                        dataRegionsAt: dataRegionConfigurations
-                                    })
-                                    - form = 'dataStorageConfiguration'
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$ctrl.Clusters.addDataRegionConfiguration($ctrl.clonedCluster)`
-                                        label-single='data region configuration'
-                                        label-multiple='data region configurations'
-                                    )
+                    pc-form-field-size(
+                        label='Max size:'
+                        ng-model=`${model}.systemRegionMaxSize`
+                        name='DataStorageSystemRegionMaxSize'
+                        placeholder='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionMaxSize.default / systemRegionMaxSizeScale.value }}'
+                        min='{{ $ctrl.Clusters.dataStorageConfiguration.systemRegionMaxSize.min($ctrl.clonedCluster) }}'
+                        tip='Maximum data region size reserved for system cache'
+                        on-scale-change='systemRegionMaxSizeScale = $event'
+                    )
+            .pc-form-grid-col-60.pc-form-group__text-title
+                span Default data region
+            .pc-form-group.pc-form-grid-row
+                +data-region-form({
+                    modelAt: dfltRegionModel,
+                    namePlaceholder: '{{ ::$ctrl.Clusters.dataRegion.name.default }}',
+                    dataRegionsAt: dataRegionConfigurations
+                })
+            .pc-form-grid-col-60
+                .ignite-form-field
+                    .ignite-form-field__label Data region configurations
+                    .ignite-form-field__control
+                        list-editable(name='dataRegionConfigurations' ng-model=dataRegionConfigurations)
+                            list-editable-item-edit.pc-form-grid-row
+                                - form = '$parent.form'
+                                +data-region-form({
+                                    modelAt: '$item',
+                                    namePlaceholder: 'Data region name',
+                                    dataRegionsAt: dataRegionConfigurations
+                                })
+                                - form = 'dataStorageConfiguration'
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$ctrl.Clusters.addDataRegionConfiguration($ctrl.clonedCluster)`
+                                    label-single='data region configuration'
+                                    label-multiple='data region configurations'
+                                )
 
-                .pc-form-grid-col-60
-                    +text-enabled('Storage path:', `${model}.storagePath`, '"DataStoragePath"', 'true', 'false', 'db',
-                    'Directory where index and partition files are stored')
-                .pc-form-grid-col-60
-                    +number('Checkpoint frequency:', `${model}.checkpointFrequency`, '"DataStorageCheckpointFrequency"', 'true', '180000', '1',
-                    'Frequency which is a minimal interval when the dirty pages will be written to the Persistent Store')
-                .pc-form-grid-col-20
-                    +number('Checkpoint threads:', `${model}.checkpointThreads`, '"DataStorageCheckpointThreads"', 'true', '4', '1', 'A number of threads to use for the checkpoint purposes')
-                .pc-form-grid-col-20
-                    +dropdown('Checkpoint write order:', `${model}.checkpointWriteOrder`, '"DataStorageCheckpointWriteOrder"', 'true', 'SEQUENTIAL',
-                    '[\
-                        {value: "RANDOM", label: "RANDOM"},\
-                        {value: "SEQUENTIAL", label: "SEQUENTIAL"}\
-                    ]',
-                    'Order of writing pages to disk storage during checkpoint.\
-                    <ul>\
-                        <li>RANDOM - Pages are written in order provided by checkpoint pages collection iterator</li>\
-                        <li>SEQUENTIAL - All checkpoint pages are collected into single list and sorted by page index</li>\
-                    </ul>')
-                .pc-form-grid-col-20
-                    +dropdown('WAL mode:', `${model}.walMode`, '"DataStorageWalMode"', 'true', 'DEFAULT',
-                    '[\
-                        {value: "DEFAULT", label: "DEFAULT"},\
-                        {value: "LOG_ONLY", label: "LOG_ONLY"},\
-                        {value: "BACKGROUND", label: "BACKGROUND"},\
-                        {value: "NONE", label: "NONE"}\
-                    ]',
-                    'Type define behavior wal fsync.\
-                    <ul>\
-                        <li>DEFAULT - full-sync disk writes</li>\
-                        <li>LOG_ONLY - flushes application buffers</li>\
-                        <li>BACKGROUND - does not force application&#39;s buffer flush</li>\
-                        <li>NONE - WAL is disabled</li>\
-                    </ul>')
-                .pc-form-grid-col-60
-                    +text-enabled('WAL path:', `${model}.walPath`, '"DataStorageWalPath"', 'true', 'false', 'db/wal', 'A path to the directory where WAL is stored')
-                .pc-form-grid-col-60
-                    +text-enabled('WAL archive path:', `${model}.walArchivePath`, '"DataStorageWalArchivePath"', 'true', 'false', 'db/wal/archive', 'A path to the WAL archive directory')
-                .pc-form-grid-col-20
-                    +number('WAL segments:', `${model}.walSegments`, '"DataStorageWalSegments"', 'true', '10', '1', 'A number of WAL segments to work with')
-                .pc-form-grid-col-20
-                    +number('WAL segment size:', `${model}.walSegmentSize`, '"DataStorageWalSegmentSize"', 'true', '67108864', '0', 'Size of a WAL segment')
-                .pc-form-grid-col-20
-                    +number('WAL history size:', `${model}.walHistorySize`, '"DataStorageWalHistorySize"', 'true', '20', '1', 'A total number of checkpoints to keep in the WAL history')
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
-                    +number('WAL buffer size:', `${model}.walBufferSize`, '"DataStorageWalBufferSize"', 'true', 'WAL segment size / 4', '1',
-                    'Size of WAL buffer')
-                .pc-form-grid-col-30
-                    +number('WAL flush frequency:', `${model}.walFlushFrequency`, '"DataStorageWalFlushFrequency"', 'true', '2000', '1',
-                    'How often will be fsync, in milliseconds. In background mode, exist thread which do fsync by timeout')
-                .pc-form-grid-col-30
-                    +number('WAL fsync delay:', `${model}.walFsyncDelayNanos`, '"DataStorageWalFsyncDelay"', 'true', '1000', '1', 'WAL fsync delay, in nanoseconds')
-                .pc-form-grid-col-60
-                    +number('WAL record iterator buffer size:', `${model}.walRecordIteratorBufferSize`, '"DataStorageWalRecordIteratorBufferSize"', 'true', '67108864', '1',
-                    'How many bytes iterator read from disk(for one reading), during go ahead WAL')
-                .pc-form-grid-col-30
-                    +number('Lock wait time:', `${model}.lockWaitTime`, '"DataStorageLockWaitTime"', 'true', '10000', '1',
-                    'Time out in milliseconds, while wait and try get file lock for start persist manager')
-                .pc-form-grid-col-30
-                    +number('WAL thread local buffer size:', `${model}.walThreadLocalBufferSize`, '"DataStorageWalThreadLocalBufferSize"', 'true', '131072', '1',
-                    'Define size thread local buffer. Each thread which write to WAL have thread local buffer for serialize recode before write in WAL')
-                .pc-form-grid-col-30
-                    +number('Metrics sub interval count:', `${model}.metricsSubIntervalCount`, '"DataStorageMetricsSubIntervalCount"', 'true', '5', '1',
-                    'Number of sub - intervals the whole rate time interval will be split into to calculate rate - based metrics')
-                .pc-form-grid-col-30
-                    +number('Metrics rate time interval:', `${model}.metricsRateTimeInterval`, '"DataStorageMetricsRateTimeInterval"', 'true', '60000', '1000',
-                    'The length of the time interval for rate - based metrics. This interval defines a window over which hits will be tracked')
-                .pc-form-grid-col-30
-                    +dropdown('File IO factory:', `${model}.fileIOFactory`, '"DataStorageFileIOFactory"', 'true', 'Default',
-                    '[\
-                        {value: "RANDOM", label: "RANDOM"},\
-                        {value: "ASYNC", label: "ASYNC"},\
-                        {value: null, label: "Default"},\
-                    ]',
-                    'Order of writing pages to disk storage during checkpoint.\
-                    <ul>\
-                        <li>RANDOM - Pages are written in order provided by checkpoint pages collection iterator</li>\
-                        <li>SEQUENTIAL - All checkpoint pages are collected into single list and sorted by page index</li>\
-                    </ul>')
-                .pc-form-grid-col-30
-                    +number('WAL auto archive after inactivity:', `${model}.walAutoArchiveAfterInactivity`, '"DataStorageWalAutoArchiveAfterInactivity"', 'true', '-1', '-1',
-                    'Time in millis to run auto archiving segment after last record logging')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Metrics enabled', `${model}.metricsEnabled`, '"DataStorageMetricsEnabled"', 'true', 'Flag indicating whether persistence metrics collection is enabled')
-                .pc-form-grid-col-60
-                    +checkbox-enabled('Always write full pages', `${model}.alwaysWriteFullPages`, '"DataStorageAlwaysWriteFullPages"', 'true', 'Flag indicating whether always write full pages')
-                .pc-form-grid-col-60
-                    +checkbox('Write throttling enabled', `${model}.writeThrottlingEnabled`, '"DataStorageWriteThrottlingEnabled"',
-                    'Throttle threads that generate dirty pages too fast during ongoing checkpoint')
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
-                    +checkbox('Enable WAL compaction', `${model}.walCompactionEnabled`, '"DataStorageWalCompactionEnabled"',
-                    'If true, system filters and compresses WAL archive in background')
+            .pc-form-grid-col-60
+                +text-enabled('Storage path:', `${model}.storagePath`, '"DataStoragePath"', 'true', 'false', 'db',
+                'Directory where index and partition files are stored')
+            .pc-form-grid-col-60
+                +number('Checkpoint frequency:', `${model}.checkpointFrequency`, '"DataStorageCheckpointFrequency"', 'true', '180000', '1',
+                'Frequency which is a minimal interval when the dirty pages will be written to the Persistent Store')
+            .pc-form-grid-col-20
+                +number('Checkpoint threads:', `${model}.checkpointThreads`, '"DataStorageCheckpointThreads"', 'true', '4', '1', 'A number of threads to use for the checkpoint purposes')
+            .pc-form-grid-col-20
+                +dropdown('Checkpoint write order:', `${model}.checkpointWriteOrder`, '"DataStorageCheckpointWriteOrder"', 'true', 'SEQUENTIAL',
+                '[\
+                    {value: "RANDOM", label: "RANDOM"},\
+                    {value: "SEQUENTIAL", label: "SEQUENTIAL"}\
+                ]',
+                'Order of writing pages to disk storage during checkpoint.\
+                <ul>\
+                    <li>RANDOM - Pages are written in order provided by checkpoint pages collection iterator</li>\
+                    <li>SEQUENTIAL - All checkpoint pages are collected into single list and sorted by page index</li>\
+                </ul>')
+            .pc-form-grid-col-20
+                +dropdown('WAL mode:', `${model}.walMode`, '"DataStorageWalMode"', 'true', 'DEFAULT',
+                '[\
+                    {value: "DEFAULT", label: "DEFAULT"},\
+                    {value: "LOG_ONLY", label: "LOG_ONLY"},\
+                    {value: "BACKGROUND", label: "BACKGROUND"},\
+                    {value: "NONE", label: "NONE"}\
+                ]',
+                'Type define behavior wal fsync.\
+                <ul>\
+                    <li>DEFAULT - full-sync disk writes</li>\
+                    <li>LOG_ONLY - flushes application buffers</li>\
+                    <li>BACKGROUND - does not force application&#39;s buffer flush</li>\
+                    <li>NONE - WAL is disabled</li>\
+                </ul>')
+            .pc-form-grid-col-60
+                +text-enabled('WAL path:', `${model}.walPath`, '"DataStorageWalPath"', 'true', 'false', 'db/wal', 'A path to the directory where WAL is stored')
+            .pc-form-grid-col-60
+                +text-enabled('WAL archive path:', `${model}.walArchivePath`, '"DataStorageWalArchivePath"', 'true', 'false', 'db/wal/archive', 'A path to the WAL archive directory')
+            .pc-form-grid-col-20
+                +number('WAL segments:', `${model}.walSegments`, '"DataStorageWalSegments"', 'true', '10', '1', 'A number of WAL segments to work with')
+            .pc-form-grid-col-20
+                +number('WAL segment size:', `${model}.walSegmentSize`, '"DataStorageWalSegmentSize"', 'true', '67108864', '0', 'Size of a WAL segment')
+            .pc-form-grid-col-20
+                +number('WAL history size:', `${model}.walHistorySize`, '"DataStorageWalHistorySize"', 'true', '20', '1', 'A total number of checkpoints to keep in the WAL history')
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
+                +number('WAL buffer size:', `${model}.walBufferSize`, '"DataStorageWalBufferSize"', 'true', 'WAL segment size / 4', '1',
+                'Size of WAL buffer')
+            .pc-form-grid-col-30
+                +number('WAL flush frequency:', `${model}.walFlushFrequency`, '"DataStorageWalFlushFrequency"', 'true', '2000', '1',
+                'How often will be fsync, in milliseconds. In background mode, exist thread which do fsync by timeout')
+            .pc-form-grid-col-30
+                +number('WAL fsync delay:', `${model}.walFsyncDelayNanos`, '"DataStorageWalFsyncDelay"', 'true', '1000', '1', 'WAL fsync delay, in nanoseconds')
+            .pc-form-grid-col-60
+                +number('WAL record iterator buffer size:', `${model}.walRecordIteratorBufferSize`, '"DataStorageWalRecordIteratorBufferSize"', 'true', '67108864', '1',
+                'How many bytes iterator read from disk(for one reading), during go ahead WAL')
+            .pc-form-grid-col-30
+                +number('Lock wait time:', `${model}.lockWaitTime`, '"DataStorageLockWaitTime"', 'true', '10000', '1',
+                'Time out in milliseconds, while wait and try get file lock for start persist manager')
+            .pc-form-grid-col-30
+                +number('WAL thread local buffer size:', `${model}.walThreadLocalBufferSize`, '"DataStorageWalThreadLocalBufferSize"', 'true', '131072', '1',
+                'Define size thread local buffer. Each thread which write to WAL have thread local buffer for serialize recode before write in WAL')
+            .pc-form-grid-col-30
+                +number('Metrics sub interval count:', `${model}.metricsSubIntervalCount`, '"DataStorageMetricsSubIntervalCount"', 'true', '5', '1',
+                'Number of sub - intervals the whole rate time interval will be split into to calculate rate - based metrics')
+            .pc-form-grid-col-30
+                +number('Metrics rate time interval:', `${model}.metricsRateTimeInterval`, '"DataStorageMetricsRateTimeInterval"', 'true', '60000', '1000',
+                'The length of the time interval for rate - based metrics. This interval defines a window over which hits will be tracked')
+            .pc-form-grid-col-30
+                +dropdown('File IO factory:', `${model}.fileIOFactory`, '"DataStorageFileIOFactory"', 'true', 'Default',
+                '[\
+                    {value: "RANDOM", label: "RANDOM"},\
+                    {value: "ASYNC", label: "ASYNC"},\
+                    {value: null, label: "Default"},\
+                ]',
+                'Order of writing pages to disk storage during checkpoint.\
+                <ul>\
+                    <li>RANDOM - Pages are written in order provided by checkpoint pages collection iterator</li>\
+                    <li>SEQUENTIAL - All checkpoint pages are collected into single list and sorted by page index</li>\
+                </ul>')
+            .pc-form-grid-col-30
+                +number('WAL auto archive after inactivity:', `${model}.walAutoArchiveAfterInactivity`, '"DataStorageWalAutoArchiveAfterInactivity"', 'true', '-1', '-1',
+                'Time in millis to run auto archiving segment after last record logging')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Metrics enabled', `${model}.metricsEnabled`, '"DataStorageMetricsEnabled"', 'true', 'Flag indicating whether persistence metrics collection is enabled')
+            .pc-form-grid-col-60
+                +checkbox-enabled('Always write full pages', `${model}.alwaysWriteFullPages`, '"DataStorageAlwaysWriteFullPages"', 'true', 'Flag indicating whether always write full pages')
+            .pc-form-grid-col-60
+                +checkbox('Write throttling enabled', `${model}.writeThrottlingEnabled`, '"DataStorageWriteThrottlingEnabled"',
+                'Throttle threads that generate dirty pages too fast during ongoing checkpoint')
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.4.0")')
+                +checkbox('Enable WAL compaction', `${model}.walCompactionEnabled`, '"DataStorageWalCompactionEnabled"',
+                'If true, system filters and compresses WAL archive in background')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterDataStorageConfiguration')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterDataStorageConfiguration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.pug
index 10244ac..1f0b615 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.pug
@@ -27,169 +27,166 @@ include /app/helpers/jade/mixins
 -var localDeployment = modelDeployment + '.kind === "Local"'
 -var customDeployment = modelDeployment + '.kind === "Custom"'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Class deployment
-        .pca-panel-heading-description
-            | Task and resources deployment in cluster.
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/deployment-modes" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id='deployment')
-        .pca-panel-body(ng-if=`ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +dropdown('Deployment mode:', `${model}.deploymentMode`, '"deploymentMode"', 'true', 'SHARED',
-                        '[\
-                            {value: "PRIVATE", label: "PRIVATE"},\
-                            {value: "ISOLATED", label: "ISOLATED"}, \
-                            {value: "SHARED", label: "SHARED"},\
-                            {value: "CONTINUOUS", label: "CONTINUOUS"}\
-                        ]',
-                        'Task classes and resources sharing mode<br/>\
-                        The following deployment modes are supported:\
-                        <ul>\
-                            <li>PRIVATE - in this mode deployed classes do not share resources</li>\
-                            <li>ISOLATED - in this mode tasks or classes deployed within the same class loader will share the same instances of resources</li>\
-                            <li>SHARED - same as ISOLATED, but now tasks from different master nodes with the same user version and same class loader will share the same class loader on remote nodes</li>\
-                            <li>CONTINUOUS - same as SHARED deployment mode, but resources will not be undeployed even after all master nodes left grid</li>\
-                        </ul>')
-                .pc-form-grid-col-60
-                    +checkbox('Enable peer class loading', `${model}.peerClassLoadingEnabled`, '"peerClassLoadingEnabled"', 'Enables/disables peer class loading')
-                .pc-form-grid-col-60
-                    +number('Missed resources cache size:', `${model}.peerClassLoadingMissedResourcesCacheSize`, '"peerClassLoadingMissedResourcesCacheSize"', enabled, '100', '0',
-                        'If size greater than 0, missed resources will be cached and next resource request ignored<br/>\
-                        If size is 0, then request for the resource will be sent to the remote node every time this resource is requested')
-                .pc-form-grid-col-60
-                    +number('Pool size:', `${model}.peerClassLoadingThreadPoolSize`, '"peerClassLoadingThreadPoolSize"', enabled, '2', '1', 'Thread pool size to use for peer class loading')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Class deployment
+    panel-description
+        | Task and resources deployment in cluster.
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/deployment-modes" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('Deployment mode:', `${model}.deploymentMode`, '"deploymentMode"', 'true', 'SHARED',
+                    '[\
+                        {value: "PRIVATE", label: "PRIVATE"},\
+                        {value: "ISOLATED", label: "ISOLATED"}, \
+                        {value: "SHARED", label: "SHARED"},\
+                        {value: "CONTINUOUS", label: "CONTINUOUS"}\
+                    ]',
+                    'Task classes and resources sharing mode<br/>\
+                    The following deployment modes are supported:\
+                    <ul>\
+                        <li>PRIVATE - in this mode deployed classes do not share resources</li>\
+                        <li>ISOLATED - in this mode tasks or classes deployed within the same class loader will share the same instances of resources</li>\
+                        <li>SHARED - same as ISOLATED, but now tasks from different master nodes with the same user version and same class loader will share the same class loader on remote nodes</li>\
+                        <li>CONTINUOUS - same as SHARED deployment mode, but resources will not be undeployed even after all master nodes left grid</li>\
+                    </ul>')
+            .pc-form-grid-col-60
+                +checkbox('Enable peer class loading', `${model}.peerClassLoadingEnabled`, '"peerClassLoadingEnabled"', 'Enables/disables peer class loading')
+            .pc-form-grid-col-60
+                +number('Missed resources cache size:', `${model}.peerClassLoadingMissedResourcesCacheSize`, '"peerClassLoadingMissedResourcesCacheSize"', enabled, '100', '0',
+                    'If size greater than 0, missed resources will be cached and next resource request ignored<br/>\
+                    If size is 0, then request for the resource will be sent to the remote node every time this resource is requested')
+            .pc-form-grid-col-60
+                +number('Pool size:', `${model}.peerClassLoadingThreadPoolSize`, '"peerClassLoadingThreadPoolSize"', enabled, '2', '1', 'Thread pool size to use for peer class loading')
+            .pc-form-grid-col-60
+                mixin clusters-deployment-packages
+                    .ignite-form-field
+                        -let items = exclude
+                        -var uniqueTip = 'Such package already exists!'
+
+                        list-editable(
+                            ng-model=items
+                            name='localClassPathExclude'
+                            list-editable-cols=`::[{
+                                name: "Local class path excludes:",
+                                tip: "List of packages from the system classpath that need to be peer-to-peer loaded from task originating node<br/>
+                                '*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause"
+                            }]`
+                            ng-disabled=enabledToDisabled(enabled)
+                        )
+                            list-editable-item-view {{ $item }}
+
+                            list-editable-item-edit
+                                +list-java-package-field('Package name', '$item', '"packageName"', items)(
+                                    ignite-auto-focus
+                                )
+                                    +unique-feedback('"packageName"', uniqueTip)
+
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$editLast($ctrl.Clusters.addPeerClassLoadingLocalClassPathExclude(${model}))`
+                                    label-single='package'
+                                    label-multiple='packages'
+                                )
+
+                -var form = '$parent.form'
+                +clusters-deployment-packages
+                -var form = 'deployment'
+
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +java-class('Class loader:', model + '.classLoader', '"classLoader"', 'true', 'false',
+                    'Loader which will be used for instantiating execution context')
+
+            .pc-form-grid-col-60
+                +dropdown('Deployment variant:', modelDeployment + '.kind', '"deploymentKind"', 'true', 'Default',
+                    '[\
+                        {value: "URI", label: "URI"},\
+                        {value: "Local", label: "Local"}, \
+                        {value: "Custom", label: "Custom"},\
+                        {value: null, label: "Default"}\
+                    ]',
+                    'Grid deployment SPI is in charge of deploying tasks and classes from different sources:\
+                    <ul>\
+                        <li>URI - Deploy tasks from different sources like file system folders, email and HTTP</li>\
+                        <li>Local - Only within VM deployment on local node</li>\
+                        <li>Custom - Custom implementation of DeploymentSpi</li>\
+                        <li>Default - Default configuration of LocalDeploymentSpi will be used</li>\
+                    </ul>')
+            .pc-form-group(ng-show=uriDeployment).pc-form-grid-row
                 .pc-form-grid-col-60
-                    mixin clusters-deployment-packages
+                    mixin clusters-deployment-uri
                         .ignite-form-field
-                            -let items = exclude
-                            -var uniqueTip = 'Such package already exists!'
+                            -let items = uriListModel
+                            -var uniqueTip = 'Such URI already configured!'
 
                             list-editable(
                                 ng-model=items
-                                name='localClassPathExclude'
+                                name='uriList'
                                 list-editable-cols=`::[{
-                                    name: "Local class path excludes:",
-                                    tip: "List of packages from the system classpath that need to be peer-to-peer loaded from task originating node<br/>
-                                    '*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause"
+                                    name: "URI list:",
+                                    tip: "List of URI which point to GAR file and which should be scanned by SPI for the new tasks"
                                 }]`
-                                ng-disabled=enabledToDisabled(enabled)
                             )
                                 list-editable-item-view {{ $item }}
 
                                 list-editable-item-edit
-                                    +list-java-package-field('Package name', '$item', '"packageName"', items)(
-                                        ignite-auto-focus
-                                    )
-                                        +unique-feedback('"packageName"', uniqueTip)
+                                    +list-url-field('URL', '$item', '"url"', items)
+                                        +unique-feedback('"url"', uniqueTip)
 
                                 list-editable-no-items
                                     list-editable-add-item-button(
-                                        add-item=`$editLast($ctrl.Clusters.addPeerClassLoadingLocalClassPathExclude(${model}))`
-                                        label-single='package'
-                                        label-multiple='packages'
+                                        add-item=`$editLast((${items} = ${items} || []).push(''))`
+                                        label-single='URI'
+                                        label-multiple='URIs'
                                     )
 
-                    -var form = '$parent.form'
-                    +clusters-deployment-packages
-                    -var form = 'deployment'
+                    - var form = '$parent.form'
+                    +clusters-deployment-uri
+                    - var form = 'deployment'
+
+                .pc-form-grid-col-60
+                    +text('Temporary directory path:', modelDeployment + '.URI.temporaryDirectoryPath', '"DeploymentURITemporaryDirectoryPath"', 'false', 'Temporary directory path',
+                    'Absolute path to temporary directory which will be used by deployment SPI to keep all deployed classes in')
+                .pc-form-grid-col-60
+                    mixin clusters-deployment-scanner
+                        .ignite-form-field
+                            -let items = scannerModel
+                            -var uniqueTip = 'Such scanner already configured!'
+
+                            list-editable(
+                                ng-model=items
+                                name='scannerModel'
+                                list-editable-cols=`::[{name: "URI deployment scanners:"}]`
+                            )
+                                list-editable-item-view {{ $item }}
+
+                                list-editable-item-edit
+                                    +list-java-class-field('Scanner', '$item', '"scanner"', items)
+                                        +unique-feedback('"scanner"', uniqueTip)
 
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +java-class('Class loader:', model + '.classLoader', '"classLoader"', 'true', 'false',
-                        'Loader which will be used for instantiating execution context')
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`$editLast((${items} = ${items} || []).push(''))`
+                                        label-single='scanner'
+                                        label-multiple='scanners'
+                                    )
+
+                    - var form = '$parent.form'
+                    +clusters-deployment-scanner
+                    - var form = 'deployment'
 
                 .pc-form-grid-col-60
-                    +dropdown('Deployment variant:', modelDeployment + '.kind', '"deploymentKind"', 'true', 'Default',
-                        '[\
-                            {value: "URI", label: "URI"},\
-                            {value: "Local", label: "Local"}, \
-                            {value: "Custom", label: "Custom"},\
-                            {value: null, label: "Default"}\
-                        ]',
-                        'Grid deployment SPI is in charge of deploying tasks and classes from different sources:\
-                        <ul>\
-                            <li>URI - Deploy tasks from different sources like file system folders, email and HTTP</li>\
-                            <li>Local - Only within VM deployment on local node</li>\
-                            <li>Custom - Custom implementation of DeploymentSpi</li>\
-                            <li>Default - Default configuration of LocalDeploymentSpi will be used</li>\
-                        </ul>')
-                .pc-form-group(ng-show=uriDeployment).pc-form-grid-row
-                    .pc-form-grid-col-60
-                        mixin clusters-deployment-uri
-                            .ignite-form-field
-                                -let items = uriListModel
-                                -var uniqueTip = 'Such URI already configured!'
-
-                                list-editable(
-                                    ng-model=items
-                                    name='uriList'
-                                    list-editable-cols=`::[{
-                                        name: "URI list:",
-                                        tip: "List of URI which point to GAR file and which should be scanned by SPI for the new tasks"
-                                    }]`
-                                )
-                                    list-editable-item-view {{ $item }}
-
-                                    list-editable-item-edit
-                                        +list-url-field('URL', '$item', '"url"', items)
-                                            +unique-feedback('"url"', uniqueTip)
-
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${items} = ${items} || []).push(''))`
-                                            label-single='URI'
-                                            label-multiple='URIs'
-                                        )
-
-                        - var form = '$parent.form'
-                        +clusters-deployment-uri
-                        - var form = 'deployment'
-
-                    .pc-form-grid-col-60
-                        +text('Temporary directory path:', modelDeployment + '.URI.temporaryDirectoryPath', '"DeploymentURITemporaryDirectoryPath"', 'false', 'Temporary directory path',
-                        'Absolute path to temporary directory which will be used by deployment SPI to keep all deployed classes in')
-                    .pc-form-grid-col-60
-                        mixin clusters-deployment-scanner
-                            .ignite-form-field
-                                -let items = scannerModel
-                                -var uniqueTip = 'Such scanner already configured!'
-
-                                list-editable(
-                                    ng-model=items
-                                    name='scannerModel'
-                                    list-editable-cols=`::[{name: "URI deployment scanners:"}]`
-                                )
-                                    list-editable-item-view {{ $item }}
-
-                                    list-editable-item-edit
-                                        +list-java-class-field('Scanner', '$item', '"scanner"', items)
-                                            +unique-feedback('"scanner"', uniqueTip)
-
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${items} = ${items} || []).push(''))`
-                                            label-single='scanner'
-                                            label-multiple='scanners'
-                                        )
-
-                        - var form = '$parent.form'
-                        +clusters-deployment-scanner
-                        - var form = 'deployment'
-
-                    .pc-form-grid-col-60
-                        +java-class('Listener:', `${modelDeployment}.URI.listener`, '"DeploymentURIListener"', 'true', 'false', 'Deployment event listener', uriDeployment)
-                    .pc-form-grid-col-60
-                        +checkbox('Check MD5', `${modelDeployment}.URI.checkMd5`, '"DeploymentURICheckMd5"', 'Exclude files with same md5s from deployment')
-                    .pc-form-grid-col-60
-                        +checkbox('Encode URI', `${modelDeployment}.URI.encodeUri`, '"DeploymentURIEncodeUri"', 'URI must be encoded before usage')
-                .pc-form-group(ng-show=localDeployment).pc-form-grid-row
-                    .pc-form-grid-col-60
-                        +java-class('Listener:', `${modelDeployment}.Local.listener`, '"DeploymentLocalListener"', 'true', 'false', 'Deployment event listener', localDeployment)
-                .pc-form-group(ng-show=customDeployment).pc-form-grid-row
-                    .pc-form-grid-col-60
-                        +java-class('Class:', `${modelDeployment}.Custom.className`, '"DeploymentCustom"', 'true', customDeployment, 'DeploymentSpi implementation class', customDeployment)
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterDeployment')
+                    +java-class('Listener:', `${modelDeployment}.URI.listener`, '"DeploymentURIListener"', 'true', 'false', 'Deployment event listener', uriDeployment)
+                .pc-form-grid-col-60
+                    +checkbox('Check MD5', `${modelDeployment}.URI.checkMd5`, '"DeploymentURICheckMd5"', 'Exclude files with same md5s from deployment')
+                .pc-form-grid-col-60
+                    +checkbox('Encode URI', `${modelDeployment}.URI.encodeUri`, '"DeploymentURIEncodeUri"', 'URI must be encoded before usage')
+            .pc-form-group(ng-show=localDeployment).pc-form-grid-row
+                .pc-form-grid-col-60
+                    +java-class('Listener:', `${modelDeployment}.Local.listener`, '"DeploymentLocalListener"', 'true', 'false', 'Deployment event listener', localDeployment)
+            .pc-form-group(ng-show=customDeployment).pc-form-grid-row
+                .pc-form-grid-col-60
+                    +java-class('Class:', `${modelDeployment}.Custom.className`, '"DeploymentCustom"', 'true', customDeployment, 'DeploymentSpi implementation class', customDeployment)
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterDeployment')


[8/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
IGNITE-7894 Web Console: Refactored panel-collapsible to component.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d24dab81
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d24dab81
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d24dab81

Branch: refs/heads/master
Commit: d24dab813936adbe2d33a09c86ddf1f393f0c226
Parents: ca75df1
Author: Ilya Borisov <kl...@gmail.com>
Authored: Thu Apr 5 14:09:17 2018 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Thu Apr 5 14:09:17 2018 +0700

----------------------------------------------------------------------
 .../e2e/testcafe/components/PanelCollapsible.js |  28 ++
 .../e2e/testcafe/components/confirmation.js     |  16 +-
 .../components/pageAdvancedConfiguration.js     |  14 +-
 .../fixtures/user-profile/credentials.js        |  34 +-
 .../testcafe/fixtures/user-profile/profile.js   |  60 +--
 .../e2e/testcafe/page-models/pageProfile.js     |  40 ++
 modules/web-console/frontend/.eslintrc          |   1 +
 modules/web-console/frontend/app/app.js         |   2 +
 .../components/cache-edit-form/controller.js    |   3 +-
 .../components/cache-edit-form/template.tpl.pug |   2 -
 .../components/cluster-edit-form/controller.js  |   2 -
 .../cluster-edit-form/template.tpl.pug          |  81 ++-
 .../components/igfs-edit-form/controller.js     |   3 -
 .../components/igfs-edit-form/template.tpl.pug  |  17 +-
 .../components/model-edit-form/controller.js    |   3 -
 .../components/model-edit-form/template.tpl.pug |   9 +-
 .../page-configure-advanced/style.scss          |  11 +-
 .../page-configure/components/pcValidation.js   |   5 +-
 .../app/components/page-profile/controller.js   |  25 +-
 .../app/components/page-profile/style.scss      |   6 +-
 .../app/components/page-profile/template.pug    |  32 +-
 .../components/panel-collapsible/component.js   |  39 ++
 .../components/panel-collapsible/controller.js  |  52 ++
 .../app/components/panel-collapsible/index.js   |  25 +
 .../components/panel-collapsible/index.spec.js  | 140 ++++++
 .../app/components/panel-collapsible/style.scss |  79 +++
 .../components/panel-collapsible/template.pug   |  24 +
 .../panel-collapsible/transcludeDirective.js    |  51 ++
 .../states/configuration/caches/affinity.pug    | 113 ++---
 .../states/configuration/caches/concurrency.pug |  85 ++--
 .../states/configuration/caches/general.pug     | 176 ++++---
 .../states/configuration/caches/memory.pug      | 263 +++++-----
 .../configuration/caches/near-cache-client.pug  |  55 +-
 .../configuration/caches/near-cache-server.pug  |  57 +--
 .../states/configuration/caches/node-filter.pug |  58 +--
 .../states/configuration/caches/query.pug       | 169 +++----
 .../states/configuration/caches/rebalance.pug   |  89 ++--
 .../states/configuration/caches/statistics.pug  |  30 +-
 .../states/configuration/caches/store.pug       | 499 +++++++++----------
 .../states/configuration/clusters/atomic.pug    | 103 ++--
 .../configuration/clusters/attributes.pug       |  40 +-
 .../states/configuration/clusters/binary.pug    | 117 +++--
 .../configuration/clusters/cache-key-cfg.pug    |  85 ++--
 .../configuration/clusters/checkpoint.pug       | 109 ++--
 .../configuration/clusters/client-connector.pug | 105 ++--
 .../states/configuration/clusters/collision.pug |  75 ++-
 .../configuration/clusters/communication.pug    | 227 +++++----
 .../states/configuration/clusters/connector.pug | 157 +++---
 .../configuration/clusters/data-storage.pug     | 323 ++++++------
 .../configuration/clusters/deployment.pug       | 291 ++++++-----
 .../states/configuration/clusters/discovery.pug | 151 +++---
 .../states/configuration/clusters/events.pug    |  81 ++-
 .../states/configuration/clusters/failover.pug  | 123 +++--
 .../states/configuration/clusters/general.pug   | 111 ++---
 .../states/configuration/clusters/hadoop.pug    | 114 ++---
 .../states/configuration/clusters/igfs.pug      |  29 +-
 .../configuration/clusters/load-balancing.pug   | 177 ++++---
 .../states/configuration/clusters/logger.pug    |  80 ++-
 .../configuration/clusters/marshaller.pug       | 101 ++--
 .../states/configuration/clusters/memory.pug    | 331 ++++++------
 .../states/configuration/clusters/metrics.pug   |  54 +-
 .../states/configuration/clusters/misc.pug      |  78 ++-
 .../states/configuration/clusters/odbc.pug      |  95 ++--
 .../configuration/clusters/persistence.pug      | 119 ++---
 .../states/configuration/clusters/service.pug   | 129 +++--
 .../configuration/clusters/sql-connector.pug    |  69 +--
 .../states/configuration/clusters/ssl.pug       | 128 +++--
 .../states/configuration/clusters/swap.pug      |  99 ++--
 .../states/configuration/clusters/thread.pug    | 240 +++++----
 .../states/configuration/clusters/time.pug      |  48 +-
 .../configuration/clusters/transactions.pug     |  91 ++--
 .../states/configuration/domains/general.pug    |  71 ++-
 .../states/configuration/domains/query.pug      | 431 ++++++++--------
 .../states/configuration/domains/store.pug      |  89 ++--
 .../modules/states/configuration/igfs/dual.pug  |  41 +-
 .../states/configuration/igfs/fragmentizer.pug  |  33 +-
 .../states/configuration/igfs/general.pug       | 105 ++--
 .../modules/states/configuration/igfs/ipc.pug   |  69 ++-
 .../modules/states/configuration/igfs/misc.pug  | 179 ++++---
 .../states/configuration/igfs/secondary.pug     |  69 ++-
 modules/web-console/frontend/package-lock.json  |  73 +++
 modules/web-console/frontend/package.json       |  10 +-
 .../frontend/test/karma.conf.babel.js           |   8 +
 .../frontend/webpack/webpack.test.js            |   5 +-
 84 files changed, 4016 insertions(+), 3645 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/components/PanelCollapsible.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/components/PanelCollapsible.js b/modules/web-console/e2e/testcafe/components/PanelCollapsible.js
new file mode 100644
index 0000000..d58d48b
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/components/PanelCollapsible.js
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+import {Selector} from 'testcafe';
+
+export class PanelCollapsible {
+    constructor(title) {
+        this._selector = Selector('.panel-collapsible__title').withText(title).parent('panel-collapsible');
+        this.heading = this._selector.find('.panel-collapsible__heading');
+        this.body = this._selector.find('.panel-collapsible__content').addCustomDOMProperties({
+            isOpened: (el) => !el.classList.contains('ng-hide')
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/components/confirmation.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/components/confirmation.js b/modules/web-console/e2e/testcafe/components/confirmation.js
index 7b39b23..b4fa2b5 100644
--- a/modules/web-console/e2e/testcafe/components/confirmation.js
+++ b/modules/web-console/e2e/testcafe/components/confirmation.js
@@ -17,15 +17,23 @@
 
 import {Selector, t} from 'testcafe';
 
+const body = Selector('.modal-body');
+const confirmButton = Selector('#confirm-btn-ok');
+const cancelButton = Selector('#confirm-btn-cancel');
+const closeButton = Selector('.modal .close');
+
 export const confirmation = {
-    body: Selector('.modal-body'),
+    body,
+    confirmButton,
+    cancelButton,
+    closeButton,
     async confirm() {
-        await t.click('#confirm-btn-ok');
+        await t.click(confirmButton);
     },
     async cancel() {
-        await t.click('#confirm-btn-cancel');
+        await t.click(cancelButton);
     },
     async close() {
-        await t.click('.modal .close');
+        await t.click(closeButton);
     }
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/components/pageAdvancedConfiguration.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/components/pageAdvancedConfiguration.js b/modules/web-console/e2e/testcafe/components/pageAdvancedConfiguration.js
index eabd337..627a345 100644
--- a/modules/web-console/e2e/testcafe/components/pageAdvancedConfiguration.js
+++ b/modules/web-console/e2e/testcafe/components/pageAdvancedConfiguration.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {Selector, t} from 'testcafe'
+import {Selector, t} from 'testcafe';
 
 export const pageAdvancedConfiguration = {
     saveButton: Selector('.pc-form-actions-panel .btn-ignite').withText('Save'),
@@ -24,16 +24,6 @@ export const pageAdvancedConfiguration = {
     cachesNavButton: Selector('.pca-menu-link[ui-sref="base.configuration.edit.advanced.caches"]'),
     igfsNavButton: Selector('.pca-menu-link[ui-sref="base.configuration.edit.advanced.igfs"]'),
     async save() {
-        await t.click(this.saveButton)
+        await t.click(this.saveButton);
     }
 };
-
-export class Panel {
-    constructor(title) {
-        this._selector = Selector('.pca-panel-heading-title').withText(title).parent('.pca-panel');
-        this.heading = this._selector.find('.pca-panel-heading')
-        this.body = this._selector.find('.pca-panel-collapse').addCustomDOMProperties({
-            isOpened: el => el.classList.contains('in')
-        })
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
index 33d2232..42c76cf 100644
--- a/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/credentials.js
@@ -15,9 +15,11 @@
  * limitations under the License.
  */
 
-import { Selector } from 'testcafe';
 import { dropTestDB, insertTestUser, resolveUrl } from '../../envtools';
 import { createRegularUser } from '../../roles';
+import {pageProfile} from '../../page-models/pageProfile';
+import {confirmation} from '../../components/confirmation';
+import {successNotification} from '../../components/notifications';
 
 const regularUser = createRegularUser();
 
@@ -35,30 +37,24 @@ fixture('Checking user credentials change')
     });
 
 test('Testing secure token change', async(t) => {
-    await t.click(Selector('header').withAttribute('ng-click', '$ctrl.toggleToken()'));
+    await t.click(pageProfile.securityToken.panel.heading);
 
-    const currentToken = await Selector('#current-security-token').innerText;
+    const currentToken = await pageProfile.securityToken.value.innerText;
 
     await t
-        .click(Selector('i').withAttribute('ng-click', '$ctrl.generateToken()'))
-        .expect(Selector('p').withText('Are you sure you want to change security token?').exists)
-        .ok()
-        .click('#confirm-btn-ok');
-
-    await t
-        .expect(await Selector('#current-security-token').innerText)
-        .notEql(currentToken);
+        .click(pageProfile.securityToken.generateTokenButton)
+        .expect(confirmation.body.innerText).contains('Are you sure you want to change security token?')
+        .click(confirmation.confirmButton)
+        .expect(pageProfile.securityToken.value.innerText).notEql(currentToken);
 });
 
 test('Testing password change', async(t) => {
-    await t.click(Selector('header').withAttribute('ng-click', '$ctrl.togglePassword()'));
-
-    await t
-        .typeText('#passwordInput', 'newPass')
-        .typeText('#passwordConfirmInput', 'newPass')
-        .click(Selector('button').withText('Save Changes'));
+    const pass = 'newPass';
 
     await t
-        .expect(Selector('span').withText('Profile saved.').exists)
-        .ok();
+        .click(pageProfile.password.panel.heading)
+        .typeText(pageProfile.password.newPassword.control, pass)
+        .typeText(pageProfile.password.confirmPassword.control, pass)
+        .click(pageProfile.saveChangesButton)
+        .expect(successNotification.withText('Profile saved.').exists).ok();
 });

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
index 398b0ad..1e9f0c3 100644
--- a/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
+++ b/modules/web-console/e2e/testcafe/fixtures/user-profile/profile.js
@@ -18,6 +18,7 @@
 import { Selector } from 'testcafe';
 import { dropTestDB, insertTestUser, resolveUrl } from '../../envtools';
 import { createRegularUser } from '../../roles';
+import {pageProfile} from '../../page-models/pageProfile';
 
 const regularUser = createRegularUser();
 
@@ -35,50 +36,25 @@ fixture('Checking user profile')
     });
 
 test('Testing user data change', async(t) => {
-    const newUserData = {
-        firstName: {
-            selector: '#firstNameInput',
-            value: 'Richard'
-        },
-        lastName: {
-            selector: '#lastNameInput',
-            value: 'Roe'
-        },
-        email: {
-            selector: '#emailInput',
-            value: 'r.roe@mail.com'
-        },
-        company: {
-            selector: '#companyInput',
-            value: 'New Company'
-        },
-        country: {
-            selector: '#countryInput',
-            value: 'Israel'
-        }
-    };
-
-    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
-        await t
-            .click(newUserData[item].selector)
-            .pressKey('ctrl+a delete')
-            .typeText(newUserData[item].selector, newUserData[item].value);
-    });
+    const firstName = 'Richard';
+    const lastName = 'Roe';
+    const email = 'r.roe@mail.com';
+    const company = 'New Company';
+    const country = 'Israel';
 
     await t
-        .click(newUserData.country.selector)
-        .click(Selector('span').withText(newUserData.country.value))
-        .click(Selector('button').withText('Save Changes'));
-
-    await t.navigateTo(resolveUrl('/settings/profile'));
-
-    ['firstName', 'lastName', 'email', 'company'].forEach(async(item) => {
-        await t
-            .expect(await Selector(newUserData[item].selector).getAttribute('value'))
-            .eql(newUserData[item].value);
-    });
+        .typeText(pageProfile.firstName.control, firstName, {replace: true})
+        .typeText(pageProfile.lastName.control, lastName, {replace: true})
+        .typeText(pageProfile.email.control, email, {replace: true})
+        .typeText(pageProfile.company.control, company, {replace: true});
+    await pageProfile.country.selectOption(country);
+    await t.click(pageProfile.saveChangesButton);
 
     await t
-        .expect(Selector(newUserData.country.selector).innerText)
-        .eql(newUserData.country.value);
+        .navigateTo(resolveUrl('/settings/profile'))
+        .expect(pageProfile.firstName.control.value).eql(firstName)
+        .expect(pageProfile.lastName.control.value).eql(lastName)
+        .expect(pageProfile.email.control.value).eql(email)
+        .expect(pageProfile.company.control.value).eql(company)
+        .expect(pageProfile.country.control.innerText).eql(country);
 });

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/e2e/testcafe/page-models/pageProfile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/e2e/testcafe/page-models/pageProfile.js b/modules/web-console/e2e/testcafe/page-models/pageProfile.js
new file mode 100644
index 0000000..a2eb1db
--- /dev/null
+++ b/modules/web-console/e2e/testcafe/page-models/pageProfile.js
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+import {CustomFormField} from '../components/FormField';
+import {PanelCollapsible} from '../components/PanelCollapsible';
+import {Selector} from 'testcafe';
+
+export const pageProfile = {
+    firstName: new CustomFormField({id: 'firstNameInput'}),
+    lastName: new CustomFormField({id: 'lastNameInput'}),
+    email: new CustomFormField({id: 'emailInput'}),
+    phone: new CustomFormField({id: 'phoneInput'}),
+    country: new CustomFormField({id: 'countryInput'}),
+    company: new CustomFormField({id: 'companyInput'}),
+    securityToken: {
+        panel: new PanelCollapsible('security token'),
+        generateTokenButton: Selector('i').withAttribute('ng-click', '$ctrl.generateToken()'),
+        value: Selector('#current-security-token')
+    },
+    password: {
+        panel: new PanelCollapsible('password'),
+        newPassword: new CustomFormField({id: 'passwordInput'}),
+        confirmPassword: new CustomFormField({id: 'passwordConfirmInput'})
+    },
+    saveChangesButton: Selector('.btn-ignite.btn-ignite--success').withText('Save Changes')
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.eslintrc b/modules/web-console/frontend/.eslintrc
index 75de1ea..805b339 100644
--- a/modules/web-console/frontend/.eslintrc
+++ b/modules/web-console/frontend/.eslintrc
@@ -6,6 +6,7 @@ plugins:
 env:
     es6: true
     browser: true
+    mocha: true
 parserOptions:
     sourceType: module
     ecmaFeatures:

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js
index 871b06f..757be22 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -134,6 +134,7 @@ import uiGridHovering from './components/ui-grid-hovering';
 import uiGridFilters from './components/ui-grid-filters';
 import listEditable from './components/list-editable';
 import breadcrumbs from './components/breadcrumbs';
+import panelCollapsible from './components/panel-collapsible';
 import clusterSelector from './components/cluster-selector';
 import connectedClusters from './components/connected-clusters';
 import pageSignIn from './components/page-signin';
@@ -226,6 +227,7 @@ angular.module('ignite-console', [
     AngularStrapTooltip.name,
     AngularStrapSelect.name,
     listEditable.name,
+    panelCollapsible.name,
     clusterSelector.name,
     servicesModule.name,
     connectedClusters.name,

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
index 14439c1..f1bba1f 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/controller.js
@@ -64,9 +64,8 @@ export default class CacheEditFormController {
             .do(filterModel)
             .subscribe();
 
+        // TODO: Do we really need this?
         this.$scope.ui = this.IgniteFormUtils.formUI();
-        this.$scope.ui.activePanels = [0];
-        this.$scope.ui.topPanels = [0, 1, 2, 3];
     }
     $onDestroy() {
         this.subscription.unsubscribe();

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
index 20cde2e..70cb445 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cache-edit-form/template.tpl.pug
@@ -18,8 +18,6 @@ form(
     name='ui.inputForm'
     id='cache'
     novalidate
-    bs-collapse=''
-    data-allow-multiple='true'
     ng-submit='$ctrl.save($ctrl.clonedCache)'
 )
     include /app/modules/states/configuration/caches/general

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
index dc76bd5..35b43e0 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js
@@ -86,8 +86,6 @@ export default class ClusterEditFormController {
 
         this.$scope.ui = this.IgniteFormUtils.formUI();
         this.$scope.ui.loadedPanels = ['checkpoint', 'serviceConfiguration', 'odbcConfiguration'];
-        this.$scope.ui.activePanels = [0];
-        this.$scope.ui.topPanels = [0];
     }
     $onChanges(changes) {
         if (

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
index 5bd52ac..4dd0e17 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/template.tpl.pug
@@ -16,60 +16,59 @@
 
 include /app/helpers/jade/mixins
 
-div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-    form(id='cluster' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
-        .panel-group
-            include /app/modules/states/configuration/clusters/general
+form(id='cluster' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
+    .panel-group
+        include /app/modules/states/configuration/clusters/general
 
-            include /app/modules/states/configuration/clusters/atomic
-            include /app/modules/states/configuration/clusters/binary
-            include /app/modules/states/configuration/clusters/cache-key-cfg
-            include /app/modules/states/configuration/clusters/checkpoint
+        include /app/modules/states/configuration/clusters/atomic
+        include /app/modules/states/configuration/clusters/binary
+        include /app/modules/states/configuration/clusters/cache-key-cfg
+        include /app/modules/states/configuration/clusters/checkpoint
 
-            //- Since ignite 2.3
-            include /app/modules/states/configuration/clusters/client-connector
+        //- Since ignite 2.3
+        include /app/modules/states/configuration/clusters/client-connector
 
-            include /app/modules/states/configuration/clusters/collision
-            include /app/modules/states/configuration/clusters/communication
-            include /app/modules/states/configuration/clusters/connector
-            include /app/modules/states/configuration/clusters/deployment
+        include /app/modules/states/configuration/clusters/collision
+        include /app/modules/states/configuration/clusters/communication
+        include /app/modules/states/configuration/clusters/connector
+        include /app/modules/states/configuration/clusters/deployment
 
-            //- Since ignite 2.3
-            include /app/modules/states/configuration/clusters/data-storage
+        //- Since ignite 2.3
+        include /app/modules/states/configuration/clusters/data-storage
 
-            include /app/modules/states/configuration/clusters/discovery
-            include /app/modules/states/configuration/clusters/events
-            include /app/modules/states/configuration/clusters/failover
-            include /app/modules/states/configuration/clusters/hadoop
-            include /app/modules/states/configuration/clusters/load-balancing
-            include /app/modules/states/configuration/clusters/logger
-            include /app/modules/states/configuration/clusters/marshaller
+        include /app/modules/states/configuration/clusters/discovery
+        include /app/modules/states/configuration/clusters/events
+        include /app/modules/states/configuration/clusters/failover
+        include /app/modules/states/configuration/clusters/hadoop
+        include /app/modules/states/configuration/clusters/load-balancing
+        include /app/modules/states/configuration/clusters/logger
+        include /app/modules/states/configuration/clusters/marshaller
 
-            //- Since ignite 2.0, deprecated in ignite 2.3
-            include /app/modules/states/configuration/clusters/memory
+        //- Since ignite 2.0, deprecated in ignite 2.3
+        include /app/modules/states/configuration/clusters/memory
 
-            include /app/modules/states/configuration/clusters/misc
-            include /app/modules/states/configuration/clusters/metrics
+        include /app/modules/states/configuration/clusters/misc
+        include /app/modules/states/configuration/clusters/metrics
 
-            //- Deprecated in ignite 2.1
-            include /app/modules/states/configuration/clusters/odbc
+        //- Deprecated in ignite 2.1
+        include /app/modules/states/configuration/clusters/odbc
 
-            //- Since ignite 2.1, deprecated in ignite 2.3
-            include /app/modules/states/configuration/clusters/persistence
+        //- Since ignite 2.1, deprecated in ignite 2.3
+        include /app/modules/states/configuration/clusters/persistence
 
-            //- Deprecated in ignite 2.3
-            include /app/modules/states/configuration/clusters/sql-connector
+        //- Deprecated in ignite 2.3
+        include /app/modules/states/configuration/clusters/sql-connector
 
-            include /app/modules/states/configuration/clusters/service
-            include /app/modules/states/configuration/clusters/ssl
+        include /app/modules/states/configuration/clusters/service
+        include /app/modules/states/configuration/clusters/ssl
 
-            //- Removed in ignite 2.0
-            include /app/modules/states/configuration/clusters/swap
+        //- Removed in ignite 2.0
+        include /app/modules/states/configuration/clusters/swap
 
-            include /app/modules/states/configuration/clusters/thread
-            include /app/modules/states/configuration/clusters/time
-            include /app/modules/states/configuration/clusters/transactions
-            include /app/modules/states/configuration/clusters/attributes
+        include /app/modules/states/configuration/clusters/thread
+        include /app/modules/states/configuration/clusters/time
+        include /app/modules/states/configuration/clusters/transactions
+        include /app/modules/states/configuration/clusters/attributes
 
 .pc-form-actions-panel(n_g-show='$ctrl.$scope.selectedItem')
     button-preview-project(cluster='$ctrl.cluster' ng-hide='$ctrl.isNew')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
index aa150d3..6812002 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/controller.js
@@ -27,9 +27,6 @@ export default class IgfsEditFormController {
         this.available = this.IgniteVersion.available.bind(this.IgniteVersion);
 
         this.$scope.ui = this.IgniteFormUtils.formUI();
-        this.$scope.ui.activePanels = [0];
-        this.$scope.ui.topPanels = [0];
-        this.$scope.ui.expanded = true;
         this.$scope.ui.loadedPanels = ['general', 'secondaryFileSystem', 'misc'];
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/template.tpl.pug
index f14a59c..fe8b218 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/template.tpl.pug
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/igfs-edit-form/template.tpl.pug
@@ -14,17 +14,16 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-    form(id='igfs' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
-        include /app/modules/states/configuration/igfs/general
+form(id='igfs' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
+    include /app/modules/states/configuration/igfs/general
 
-        include /app/modules/states/configuration/igfs/secondary
-        include /app/modules/states/configuration/igfs/ipc
-        include /app/modules/states/configuration/igfs/fragmentizer
+    include /app/modules/states/configuration/igfs/secondary
+    include /app/modules/states/configuration/igfs/ipc
+    include /app/modules/states/configuration/igfs/fragmentizer
 
-        //- Removed in ignite 2.0
-        include /app/modules/states/configuration/igfs/dual
-        include /app/modules/states/configuration/igfs/misc
+    //- Removed in ignite 2.0
+    include /app/modules/states/configuration/igfs/dual
+    include /app/modules/states/configuration/igfs/misc
 
 .pc-form-actions-panel
     .pc-form-actions-panel__right-after

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js
index 1b16a02..20384d5 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js
@@ -50,9 +50,6 @@ export default class ModelEditFormController {
 
         this.queryFieldTypes = this.LegacyUtils.javaBuiltInClasses.concat('byte[]');
         this.$scope.ui = this.IgniteFormUtils.formUI();
-        this.$scope.ui.activePanels = [0, 1];
-        this.$scope.ui.topPanels = [0, 1, 2];
-        this.$scope.ui.expanded = true;
 
         this.$scope.javaBuiltInClasses = this.LegacyUtils.javaBuiltInClasses;
         this.$scope.supportedJdbcTypes = this.LegacyUtils.mkOptions(this.LegacyUtils.SUPPORTED_JDBC_TYPES);

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/template.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/template.tpl.pug b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/template.tpl.pug
index 685213c..8ebd11c 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/template.tpl.pug
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/template.tpl.pug
@@ -14,11 +14,10 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-    form(id='model' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
-        include /app/modules/states/configuration/domains/general
-        include /app/modules/states/configuration/domains/query
-        include /app/modules/states/configuration/domains/store
+form(id='model' name='ui.inputForm' novalidate ng-submit='$ctrl.save()')
+    include /app/modules/states/configuration/domains/general
+    include /app/modules/states/configuration/domains/query
+    include /app/modules/states/configuration/domains/store
 
 .pc-form-actions-panel
     .pc-form-actions-panel__right-after

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure-advanced/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/style.scss b/modules/web-console/frontend/app/components/page-configure-advanced/style.scss
index 7af830c..2bc5e84 100644
--- a/modules/web-console/frontend/app/components/page-configure-advanced/style.scss
+++ b/modules/web-console/frontend/app/components/page-configure-advanced/style.scss
@@ -71,15 +71,12 @@ page-configure-advanced {
         }
     }
 
-    .pca-content {
-        border-left: 1px solid $gray-lighter;
-        padding: 30px;
-        flex: 1;
+    .pca-panel, panel-collapsible {
+        margin-bottom: 20px;
     }
 
-
-    .pca-panel {
-        margin-bottom: 20px;
+    panel-content.pca-form-row {
+        display: flex !important;
     }
 
     .pca-form-row {

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
index 45ca6f2..5ddd4ef 100644
--- a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
+++ b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js
@@ -148,12 +148,13 @@ export default angular.module('ignite-console.page-configure.validation', [])
     })
     .directive('ngModel', ['$timeout', function($timeout) {
         return {
-            require: ['ngModel', '?^^bsCollapseTarget', '?^^igniteFormField'],
-            link(scope, el, attr, [ngModel, bsCollapseTarget, igniteFormField]) {
+            require: ['ngModel', '?^^bsCollapseTarget', '?^^igniteFormField', '?^^panelCollapsible'],
+            link(scope, el, attr, [ngModel, bsCollapseTarget, igniteFormField, panelCollapsible]) {
                 const off = scope.$on('$showValidationError', (e, target) => {
                     if (target !== ngModel) return;
                     ngModel.$setTouched();
                     bsCollapseTarget && bsCollapseTarget.open();
+                    panelCollapsible && panelCollapsible.open();
                     $timeout(() => {
                         if (el[0].scrollIntoViewIfNeeded)
                             el[0].scrollIntoViewIfNeeded();

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-profile/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-profile/controller.js b/modules/web-console/frontend/app/components/page-profile/controller.js
index 3fc7318..05fe118 100644
--- a/modules/web-console/frontend/app/components/page-profile/controller.js
+++ b/modules/web-console/frontend/app/components/page-profile/controller.js
@@ -33,11 +33,8 @@ export default class PageProfileController {
         this.ui.countries = this.Countries.getAll();
     }
 
-    toggleToken() {
-        this.ui.expandedToken = !this.ui.expandedToken;
-
-        if (!this.ui.expandedToken)
-            this.ui.user.token = this.$root.user.token;
+    onSecurityTokenPanelClose() {
+        this.ui.user.token = this.$root.user.token;
     }
 
     generateToken() {
@@ -45,26 +42,16 @@ export default class PageProfileController {
             .then(() => this.ui.user.token = this.LegacyUtils.randomString(20));
     }
 
-    togglePassword() {
-        this.ui.expandedPassword = !this.ui.expandedPassword;
-
-        if (this.ui.expandedPassword)
-            this.Focus.move('profile_password');
-        else {
-            delete this.ui.user.password;
-            delete this.ui.user.confirm;
-        }
+    onPasswordPanelClose() {
+        delete this.ui.user.password;
+        delete this.ui.user.confirm;
     }
 
     saveUser() {
         return this.$http.post('/api/v1/profile/save', this.ui.user)
             .then(this.User.load)
             .then(() => {
-                if (this.ui.expandedPassword)
-                    this.togglePassword();
-
-                if (this.ui.expandedToken)
-                    this.toggleToken();
+                this.ui.expandedPassword = this.ui.expandedToken = false;
 
                 this.Messages.showInfo('Profile saved.');
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-profile/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-profile/style.scss b/modules/web-console/frontend/app/components/page-profile/style.scss
index f4eae1a..8c9387f 100644
--- a/modules/web-console/frontend/app/components/page-profile/style.scss
+++ b/modules/web-console/frontend/app/components/page-profile/style.scss
@@ -16,7 +16,7 @@
  */
 
 page-profile {
-    .panel--ignite {
+    panel-collapsible {
         width: 100%;
     }
 
@@ -28,8 +28,4 @@ page-profile {
     .btn-ignite + .btn-ignite {
         margin-left: 10px;
     }
-
-    [ignite-icon='expand'], [ignite-icon='collapse'] {
-        color: #757575;
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/page-profile/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-profile/template.pug b/modules/web-console/frontend/app/components/page-profile/template.pug
index 48aa151..eafde6b 100644
--- a/modules/web-console/frontend/app/components/page-profile/template.pug
+++ b/modules/web-console/frontend/app/components/page-profile/template.pug
@@ -90,14 +90,14 @@ div
 
         .row#security-token-section
             .col-50
-                .panel--ignite.panel--collapse(ng-class='{ in: !$ctrl.ui.expandedToken }')
-                    header(ng-click='$ctrl.toggleToken()')
-                        svg(ignite-icon='expand')
-                        svg(ignite-icon='collapse')
-
-                        | {{$ctrl.ui.expandedToken ? 'Cancel security token changing...' : 'Show security token...'}}
-                    hr
-                    section(ng-if='$ctrl.ui.expandedToken')
+                panel-collapsible(
+                    opened='$ctrl.ui.expandedToken'
+                    on-open='$ctrl.ui.expandedToken = true'
+                    on-close='$ctrl.onSecurityTokenPanelClose()'
+                )
+                    panel-title
+                        | {{ $panel.opened ? 'Cancel security token changing...' : 'Show security token...' }}
+                    panel-content
                         .row
                             .col-25
                                 label.required Security token:
@@ -110,14 +110,14 @@ div
 
         .row
             .col-50
-                .panel--ignite.panel--collapse(ng-class='{ in: !$ctrl.ui.expandedPassword }')
-                    header(ng-click='$ctrl.togglePassword()')
-                        svg(ignite-icon='expand')
-                        svg(ignite-icon='collapse')
-
-                        | {{ $ctrl.ui.expandedPassword ? 'Cancel password changing...' : 'Change password...' }}
-                    hr
-                    section(ng-if='$ctrl.ui.expandedPassword')
+                panel-collapsible(
+                    opened='$ctrl.ui.expandedPassword'
+                    on-open='$ctrl.ui.expandedToken = false'
+                    on-close='$ctrl.onPasswordPanelClose()'
+                )
+                    panel-title
+                        | {{ $panel.opened ? 'Cancel password changing...' : 'Change password...' }}
+                    panel-content(ng-if='$panel.opened')
                         .row
                             .col-100
                                 +form-field__password({

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/component.js b/modules/web-console/frontend/app/components/panel-collapsible/component.js
new file mode 100644
index 0000000..f0cdc65
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/component.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+import template from './template.pug';
+import controller from './controller';
+import './style.scss';
+
+export default {
+    template,
+    controller,
+    bindings: {
+        opened: '<?',
+        onOpen: '&?',
+        onClose: '&?',
+        title: '@?',
+        description: '@?',
+        disabled: '@?'
+    },
+    transclude: {
+        title: '?panelTitle',
+        description: '?panelDescription',
+        actions: '?panelActions',
+        content: 'panelContent'
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/controller.js b/modules/web-console/frontend/app/components/panel-collapsible/controller.js
new file mode 100644
index 0000000..0b8b4da
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/controller.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+export default class PanelCollapsible {
+    /** @type {Boolean} */
+    opened;
+    /** @type {ng.ICompiledExpression} */
+    onOpen;
+    /** @type {ng.ICompiledExpression} */
+    onClose;
+    /** @type {String} */
+    disabled;
+
+    static $inject = ['$transclude'];
+
+    /**
+     * @param {ng.ITranscludeFunction} $transclude
+     */
+    constructor($transclude) {
+        this.$transclude = $transclude;
+    }
+    toggle() {
+        if (this.opened)
+            this.close();
+        else
+            this.open();
+    }
+    open() {
+        if (this.disabled) return;
+        this.opened = true;
+        if (this.onOpen && this.opened) this.onOpen({});
+    }
+    close() {
+        if (this.disabled) return;
+        this.opened = false;
+        if (this.onClose && !this.opened) this.onClose({});
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/index.js b/modules/web-console/frontend/app/components/panel-collapsible/index.js
new file mode 100644
index 0000000..6f64b3b
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/index.js
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+import angular from 'angular';
+import component from './component';
+import transclude from './transcludeDirective';
+
+export default angular
+    .module('ignite-console.panel-collapsible', [])
+    .directive('panelCollapsibleTransclude', transclude)
+    .component('panelCollapsible', component);

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/index.spec.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/index.spec.js b/modules/web-console/frontend/app/components/panel-collapsible/index.spec.js
new file mode 100644
index 0000000..7972246
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/index.spec.js
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+import 'mocha';
+import {assert} from 'chai';
+import angular from 'angular';
+import 'angular-mocks';
+import {spy} from 'sinon';
+import componentModule from './index.js';
+
+suite('panel-collapsible', () => {
+    const ICON_COLLAPSE = 'collapse';
+    const ICON_EXPAND = 'expand';
+    /** @type {ng.IScope} */
+    let $scope;
+    /** @type {ng.ICompileService} */
+    let $compile;
+    angular.module('test', [componentModule.name]);
+
+    const isClosed = (el) => el[0].querySelector('.panel-collapsible__content').classList.contains('ng-hide');
+    const click = (el) => el[0].querySelector('.panel-collapsible__status-icon').click();
+    const getIcon = (el) => (
+        el[0]
+            .querySelector('.panel-collapsible__status-icon [ignite-icon]:not(.ng-hide)')
+            .getAttribute('ignite-icon')
+    );
+
+    setup(() => {
+        angular.module('test', [componentModule.name]);
+        angular.mock.module('test');
+        angular.mock.inject((_$rootScope_, _$compile_) => {
+            $compile = _$compile_;
+            $scope = _$rootScope_.$new();
+        });
+    });
+
+    test('Required slot', () => {
+        const el = angular.element(`<panel-collapsible></panel-collapsible>`);
+        assert.throws(
+            () => $compile(el)($scope),
+            /Required transclusion slot `content` was not filled/,
+            'Throws when panel-content slot was not filled'
+        );
+    });
+
+    test('Open/close', () => {
+        $scope.opened = false;
+        const onOpen = $scope.onOpen = spy();
+        const onClose = $scope.onClose = spy();
+        const el = angular.element(`
+            <panel-collapsible
+                opened="opened"
+                on-open="onOpen()"
+                on-close="onClose()"
+            >
+                <panel-content>Content</panel-content>
+            </panel-collapsible>
+        `);
+
+        $compile(el)($scope);
+        $scope.$digest();
+        assert.equal(getIcon(el), ICON_EXPAND, `Shows ${ICON_EXPAND} icon when closed`);
+        assert.ok(isClosed(el), 'Hides content by default');
+        click(el);
+        $scope.$digest();
+        assert.equal(getIcon(el), ICON_COLLAPSE, `Shows ${ICON_COLLAPSE} icon when opened`);
+        assert.notOk(isClosed(el), 'Shows content when clicked');
+        click(el);
+        $scope.$digest();
+        assert.equal(onOpen.callCount, 1, 'Evaluates onOpen expression');
+        assert.equal(onClose.callCount, 1, 'Evaluates onClose expression');
+        $scope.opened = true;
+        $scope.$digest();
+        assert.notOk(isClosed(el), 'Uses opened binding to control visibility');
+    });
+
+    test('Slot transclusion', () => {
+        const el = angular.element(`
+            <panel-collapsible opened='::true'>
+                <panel-title>Title {{$panel.opened}}</panel-title>
+                <panel-description>Description {{$panel.opened}}</panel-description>
+                <panel-actions>
+                    <button
+                        class='my-button'
+                        ng-click='$panel.close()'
+                    >Button {{$panel.opened}}</button>
+                </panel-actions>
+                <panel-content>Content {{$panel.opened}}</panel-content>
+            </panel-collapsible>
+        `);
+        $compile(el)($scope);
+        $scope.$digest();
+        assert.equal(
+            el[0].querySelector('panel-title').textContent,
+            'Title true',
+            'Transcludes title slot and exposes $panel controller'
+        );
+        assert.equal(
+            el[0].querySelector('panel-description').textContent,
+            'Description true',
+            'Transcludes Description slot and exposes $panel controller'
+        );
+        assert.equal(
+            el[0].querySelector('panel-content').textContent,
+            'Content true',
+            'Transcludes content slot and exposes $panel controller'
+        );
+        el[0].querySelector('.my-button').click();
+        $scope.$digest();
+        assert.ok(isClosed(el), 'Can close by calling a method on exposed controller');
+    });
+
+    test('Disabled state', () => {
+        const el = angular.element(`
+            <panel-collapsible disabled='disabled'>
+                <panel-content>Content</panel-content>
+            </panel-collapsible>
+        `);
+        $compile(el)($scope);
+        $scope.$digest();
+        click(el);
+        $scope.$digest();
+        assert.ok(isClosed(el), `Can't be opened when disabled`);
+        // TODO: test disabled styles
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/style.scss b/modules/web-console/frontend/app/components/panel-collapsible/style.scss
new file mode 100644
index 0000000..73eba25
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/style.scss
@@ -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.
+ */
+
+panel-collapsible {
+    display: flex;
+    flex-direction: column;
+    font-family: Roboto;
+    border-radius: 0 0 4px 4px;
+    background-color: #ffffff;
+    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
+
+    &[disabled] {
+        opacity: 0.5;
+    }
+
+    .#{&}__status-icon {
+        margin-right: 10px;
+        color: #757575;
+    }
+
+    .#{&}__heading {
+        padding: 30px 20px 30px;
+        color: #393939;
+        display: flex;
+        flex-direction: row;
+        align-items: baseline;
+        user-select: none;
+        cursor: pointer;
+        line-height: 1.42857;
+    }
+
+    .#{&}__title {
+        font-size: 16px;
+        margin-right: 8px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+    }
+
+    .#{&}__description {
+        font-size: 12px;
+        color: #757575;
+        flex: 1 1;
+    }
+
+    .#{&}__actions {
+        margin-left: auto;
+
+        & > panel-actions {
+            display: flex;
+            flex-direction: row;
+
+            & > * {
+                flex: 0 0 auto;
+                margin-left: 10px;
+            }
+        }
+    }
+
+    .#{&}__content {
+        border-top: 1px solid #dddddd;
+        padding: 15px 20px;
+        contain: content;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/template.pug b/modules/web-console/frontend/app/components/panel-collapsible/template.pug
new file mode 100644
index 0000000..9120f58
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/template.pug
@@ -0,0 +1,24 @@
+//-
+    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.
+
+.panel-collapsible__heading(ng-click='$ctrl.toggle()')
+    .panel-collapsible__status-icon
+        svg(ng-show='$ctrl.opened' ignite-icon='collapse')
+        svg(ng-hide='$ctrl.opened' ignite-icon='expand')
+    .panel-collapsible__title(panel-collapsible-transclude='title') {{::$ctrl.title}}
+    .panel-collapsible__description(panel-collapsible-transclude='description') {{::$ctrl.description}}
+    .panel-collapsible__actions(panel-collapsible-transclude='actions' ng-click='$event.stopPropagation()')
+.panel-collapsible__content(panel-collapsible-transclude='content' ng-show='$ctrl.opened')
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/components/panel-collapsible/transcludeDirective.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/panel-collapsible/transcludeDirective.js b/modules/web-console/frontend/app/components/panel-collapsible/transcludeDirective.js
new file mode 100644
index 0000000..86509f5
--- /dev/null
+++ b/modules/web-console/frontend/app/components/panel-collapsible/transcludeDirective.js
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+// eslint-disable-next-line
+import {default as Panel} from './controller';
+
+export default function panelCollapsibleTransclude() {
+    return {
+        restrict: 'A',
+        require: {
+            panel: '^panelCollapsible'
+        },
+        scope: true,
+        controller: class {
+            /** @type {Panel} */
+            panel;
+            /** @type {string} */
+            slot;
+            static $inject = ['$element'];
+            /**
+             * @param {JQLite} $element
+             */
+            constructor($element) {
+                this.$element = $element;
+            }
+            $postLink() {
+                this.panel.$transclude((clone, scope) => {
+                    scope.$panel = this.panel;
+                    this.$element.append(clone);
+                }, null, this.slot);
+            }
+        },
+        bindToController: {
+            slot: '@panelCollapsibleTransclude'
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/affinity.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/affinity.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/affinity.pug
index ca781da..ce2cad5 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/affinity.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/affinity.pug
@@ -27,63 +27,60 @@ include /app/helpers/jade/mixins
 -var rendPartitionsRequired = rendezvousAff + ' && ' + affModel + '.Rendezvous.affinityBackupFilter'
 -var fairPartitionsRequired = fairAff + ' && ' + affModel + '.Fair.affinityBackupFilter'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Affinity Collocation
-        .pca-panel-heading-description
-            | Collocate data with data to improve performance and scalability of your application. 
-            a.link-success(href="https://apacheignite.readme.io/docs/affinity-collocation" 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
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', 'affinityFunction',
-                        'Key topology resolver to provide mapping from keys to nodes<br/>\
-                        <ul>\
-                            <li>Rendezvous - Based on Highest Random Weight algorithm</li>\
-                            <li>Fair - Tries to ensure that all nodes get equal number of partitions with minimum amount of reassignments between existing nodes</li>\
-                            <li>Custom - Custom implementation of key affinity fynction</li>\
-                            <li>Default - By default rendezvous affinity function  with 1024 partitions is used</li>\
-                        </ul>')
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', 'affinityFunction',
-                        'Key topology resolver to provide mapping from keys to nodes<br/>\
-                        <ul>\
-                            <li>Rendezvous - Based on Highest Random Weight algorithm</li>\
-                            <li>Custom - Custom implementation of key affinity fynction</li>\
-                            <li>Default - By default rendezvous affinity function  with 1024 partitions is used</li>\
-                        </ul>')
-                .pc-form-group
-                    .pc-form-grid-row(ng-if=rendezvousAff)
-                        .pc-form-grid-col-60
-                            +number-required('Partitions', `${affModel}.Rendezvous.partitions`, '"RendPartitions"', 'true', rendPartitionsRequired, '1024', '1', 'Number of partitions')
-                        .pc-form-grid-col-60
-                            +java-class('Backup filter', `${affModel}.Rendezvous.affinityBackupFilter`, '"RendAffinityBackupFilter"', 'true', 'false',
-                                'Backups will be selected from all nodes that pass this filter')
-                        .pc-form-grid-col-60
-                            +checkbox('Exclude neighbors', `${affModel}.Rendezvous.excludeNeighbors`, '"RendExcludeNeighbors"',
-                                'Exclude same - host - neighbors from being backups of each other and specified number of backups')
-                    .pc-form-grid-row(ng-if=fairAff)
-                        .pc-form-grid-col-60
-                            +number-required('Partitions', `${affModel}.Fair.partitions`, '"FairPartitions"', 'true', fairPartitionsRequired, '256', '1', 'Number of partitions')
-                        .pc-form-grid-col-60
-                            +java-class('Backup filter', `${affModel}.Fair.affinityBackupFilter`, '"FairAffinityBackupFilter"', 'true', 'false',
-                                'Backups will be selected from all nodes that pass this filter')
-                        .pc-form-grid-col-60
-                            +checkbox('Exclude neighbors', `${affModel}.Fair.excludeNeighbors`, '"FairExcludeNeighbors"',
-                                'Exclude same - host - neighbors from being backups of each other and specified number of backups')
-                    .pc-form-grid-row(ng-if=customAff)
-                        .pc-form-grid-col-60
-                            +java-class('Class name:', `${affModel}.Custom.className`, '"AffCustomClassName"', 'true', customAff,
-                                'Custom key affinity function implementation class name')
-                .pc-form-grid-col-60
-                    +java-class('Mapper:', model + '.affinityMapper', '"AffMapCustomClassName"', 'true', 'false',
-                        'Provide custom affinity key for any given key')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Affinity Collocation
+    panel-description
+        | Collocate data with data to improve performance and scalability of your application. 
+        a.link-success(href="https://apacheignite.readme.io/docs/affinity-collocation" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', 'affinityFunction',
+                    'Key topology resolver to provide mapping from keys to nodes<br/>\
+                    <ul>\
+                        <li>Rendezvous - Based on Highest Random Weight algorithm</li>\
+                        <li>Fair - Tries to ensure that all nodes get equal number of partitions with minimum amount of reassignments between existing nodes</li>\
+                        <li>Custom - Custom implementation of key affinity fynction</li>\
+                        <li>Default - By default rendezvous affinity function  with 1024 partitions is used</li>\
+                    </ul>')
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +dropdown('Function:', `${affModel}.kind`, '"AffinityKind"', 'true', 'Default', 'affinityFunction',
+                    'Key topology resolver to provide mapping from keys to nodes<br/>\
+                    <ul>\
+                        <li>Rendezvous - Based on Highest Random Weight algorithm</li>\
+                        <li>Custom - Custom implementation of key affinity fynction</li>\
+                        <li>Default - By default rendezvous affinity function  with 1024 partitions is used</li>\
+                    </ul>')
+            .pc-form-group
+                .pc-form-grid-row(ng-if=rendezvousAff)
+                    .pc-form-grid-col-60
+                        +number-required('Partitions', `${affModel}.Rendezvous.partitions`, '"RendPartitions"', 'true', rendPartitionsRequired, '1024', '1', 'Number of partitions')
+                    .pc-form-grid-col-60
+                        +java-class('Backup filter', `${affModel}.Rendezvous.affinityBackupFilter`, '"RendAffinityBackupFilter"', 'true', 'false',
+                            'Backups will be selected from all nodes that pass this filter')
+                    .pc-form-grid-col-60
+                        +checkbox('Exclude neighbors', `${affModel}.Rendezvous.excludeNeighbors`, '"RendExcludeNeighbors"',
+                            'Exclude same - host - neighbors from being backups of each other and specified number of backups')
+                .pc-form-grid-row(ng-if=fairAff)
+                    .pc-form-grid-col-60
+                        +number-required('Partitions', `${affModel}.Fair.partitions`, '"FairPartitions"', 'true', fairPartitionsRequired, '256', '1', 'Number of partitions')
+                    .pc-form-grid-col-60
+                        +java-class('Backup filter', `${affModel}.Fair.affinityBackupFilter`, '"FairAffinityBackupFilter"', 'true', 'false',
+                            'Backups will be selected from all nodes that pass this filter')
+                    .pc-form-grid-col-60
+                        +checkbox('Exclude neighbors', `${affModel}.Fair.excludeNeighbors`, '"FairExcludeNeighbors"',
+                            'Exclude same - host - neighbors from being backups of each other and specified number of backups')
+                .pc-form-grid-row(ng-if=customAff)
+                    .pc-form-grid-col-60
+                        +java-class('Class name:', `${affModel}.Custom.className`, '"AffCustomClassName"', 'true', customAff,
+                            'Custom key affinity function implementation class name')
+            .pc-form-grid-col-60
+                +java-class('Mapper:', model + '.affinityMapper', '"AffMapCustomClassName"', 'true', 'false',
+                    'Provide custom affinity key for any given key')
 
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +java-class('Topology validator:', model + '.topologyValidator', '"topologyValidator"', 'true', 'false')
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +java-class('Topology validator:', model + '.topologyValidator', '"topologyValidator"', 'true', 'false')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheAffinity')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheAffinity')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.pug
index 2902f21..d99f894 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.pug
@@ -19,49 +19,46 @@ include /app/helpers/jade/mixins
 -var form = 'concurrency'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Concurrency control
-        .pca-panel-heading-description
-            | Cache concurrent asynchronous operations 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-30
-                    +number('Max async operations:', `${model}.maxConcurrentAsyncOperations`, '"maxConcurrentAsyncOperations"', 'true', '500', '0',
-                        'Maximum number of allowed concurrent asynchronous operations<br/>\
-                        If <b>0</b> then number of concurrent asynchronous operations is unlimited')
-                .pc-form-grid-col-30
-                    +number('Default lock timeout:', `${model}.defaultLockTimeout`, '"defaultLockTimeout"', 'true', '0', '0',
-                        'Default lock acquisition timeout in milliseconds<br/>\
-                        If <b>0</b> then lock acquisition will never timeout')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Concurrency control
+    panel-description
+        | Cache concurrent asynchronous operations settings.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +number('Max async operations:', `${model}.maxConcurrentAsyncOperations`, '"maxConcurrentAsyncOperations"', 'true', '500', '0',
+                    'Maximum number of allowed concurrent asynchronous operations<br/>\
+                    If <b>0</b> then number of concurrent asynchronous operations is unlimited')
+            .pc-form-grid-col-30
+                +number('Default lock timeout:', `${model}.defaultLockTimeout`, '"defaultLockTimeout"', 'true', '0', '0',
+                    'Default lock acquisition timeout in milliseconds<br/>\
+                    If <b>0</b> then lock acquisition will never timeout')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])' ng-hide=`${model}.atomicityMode === 'TRANSACTIONAL'`)
-                    +dropdown('Entry versioning:', `${model}.atomicWriteOrderMode`, '"atomicWriteOrderMode"', 'true', 'Choose versioning',
-                        '[\
-                            {value: "CLOCK", label: "CLOCK"},\
-                            {value: "PRIMARY", label: "PRIMARY"}\
-                        ]',
-                        'Write ordering mode determines which node assigns the write version, sender or the primary node\
-                        <ul>\
-                            <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance</li>\
-                            <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups</li>\
-                        </ul>')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])' ng-hide=`${model}.atomicityMode === 'TRANSACTIONAL'`)
+                +dropdown('Entry versioning:', `${model}.atomicWriteOrderMode`, '"atomicWriteOrderMode"', 'true', 'Choose versioning',
+                    '[\
+                        {value: "CLOCK", label: "CLOCK"},\
+                        {value: "PRIMARY", label: "PRIMARY"}\
+                    ]',
+                    'Write ordering mode determines which node assigns the write version, sender or the primary node\
+                    <ul>\
+                        <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance</li>\
+                        <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups</li>\
+                    </ul>')
 
-                .pc-form-grid-col-60
-                    +dropdown('Write synchronization mode:', `${model}.writeSynchronizationMode`, '"writeSynchronizationMode"', 'true', 'PRIMARY_SYNC',
-                        '[\
-                            {value: "FULL_SYNC", label: "FULL_SYNC"},\
-                            {value: "FULL_ASYNC", label: "FULL_ASYNC"},\
-                            {value: "PRIMARY_SYNC", label: "PRIMARY_SYNC"}\
-                        ]',
-                        'Write synchronization mode\
-                        <ul>\
-                            <li>FULL_SYNC - Ignite will wait for write or commit replies from all nodes</li>\
-                            <li>FULL_ASYNC - Ignite will not wait for write or commit responses from participating nodes</li>\
-                            <li>PRIMARY_SYNC - Makes sense for PARTITIONED mode. Ignite will wait for write or commit to complete on primary node</li>\
-                        </ul>')
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheConcurrency')
+            .pc-form-grid-col-60
+                +dropdown('Write synchronization mode:', `${model}.writeSynchronizationMode`, '"writeSynchronizationMode"', 'true', 'PRIMARY_SYNC',
+                    '[\
+                        {value: "FULL_SYNC", label: "FULL_SYNC"},\
+                        {value: "FULL_ASYNC", label: "FULL_ASYNC"},\
+                        {value: "PRIMARY_SYNC", label: "PRIMARY_SYNC"}\
+                    ]',
+                    'Write synchronization mode\
+                    <ul>\
+                        <li>FULL_SYNC - Ignite will wait for write or commit replies from all nodes</li>\
+                        <li>FULL_ASYNC - Ignite will not wait for write or commit responses from participating nodes</li>\
+                        <li>PRIMARY_SYNC - Makes sense for PARTITIONED mode. Ignite will wait for write or commit to complete on primary node</li>\
+                    </ul>')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheConcurrency')


[7/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/general.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/general.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/general.pug
index df4d3f8..29977be 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/general.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/general.pug
@@ -19,99 +19,95 @@ include /app/helpers/jade/mixins
 -var form = 'general'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title General
-        .pca-panel-heading-description
-            | Common cache configuration. 
-            a.link-success(href="https://apacheignite.readme.io/docs/data-grid" target="_blank") More info
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id='general')
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                
-                .pc-form-grid-col-60
-                    +sane-ignite-form-field-text({
-                        label: 'Name:',
-                        model: `${model}.name`,
-                        name: '"cacheName"',
-                        placeholder: 'Input name',
-                        required: true
-                    })(
-                        ignite-unique='$ctrl.caches'
-                        ignite-unique-property='name'
-                        ignite-unique-skip=`["_id", ${model}]`
-                    )
-                        +unique-feedback(`${model}.name`, 'Cache name should be unique')
-                .pc-form-grid-col-60
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Domain models:',
-                        model: `${model}.domains`,
-                        name: '"domains"',
-                        multiple: true,
-                        placeholder: 'Choose domain models',
-                        placeholderEmpty: 'No valid domain models configured',
-                        options: '$ctrl.modelsMenu',
-                        tip: 'Select domain models to describe types in cache'
-                    })
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.1.0")')
-                    +text('Group:', `${model}.groupName`, '"groupName"', 'false', 'Input group name',
-                        'Cache group name.<br/>\
-                        Caches with the same group name share single underlying "physical" cache (partition set), but are logically isolated.')
-                .pc-form-grid-col-30
-                    +cacheMode('Mode:', `${model}.cacheMode`, '"cacheMode"', 'PARTITIONED')
+panel-collapsible(opened=`::true` ng-form=form)
+    panel-title General
+    panel-description
+        | Common cache configuration. 
+        a.link-success(href="https://apacheignite.readme.io/docs/data-grid" target="_blank") More info
+    panel-content.pca-form-row
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +sane-ignite-form-field-text({
+                    label: 'Name:',
+                    model: `${model}.name`,
+                    name: '"cacheName"',
+                    placeholder: 'Input name',
+                    required: true
+                })(
+                    ignite-unique='$ctrl.caches'
+                    ignite-unique-property='name'
+                    ignite-unique-skip=`["_id", ${model}]`
+                )
+                    +unique-feedback(`${model}.name`, 'Cache name should be unique')
+            .pc-form-grid-col-60
+                +sane-ignite-form-field-dropdown({
+                    label: 'Domain models:',
+                    model: `${model}.domains`,
+                    name: '"domains"',
+                    multiple: true,
+                    placeholder: 'Choose domain models',
+                    placeholderEmpty: 'No valid domain models configured',
+                    options: '$ctrl.modelsMenu',
+                    tip: 'Select domain models to describe types in cache'
+                })
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.1.0")')
+                +text('Group:', `${model}.groupName`, '"groupName"', 'false', 'Input group name',
+                    'Cache group name.<br/>\
+                    Caches with the same group name share single underlying "physical" cache (partition set), but are logically isolated.')
+            .pc-form-grid-col-30
+                +cacheMode('Mode:', `${model}.cacheMode`, '"cacheMode"', 'PARTITIONED')
 
-                .pc-form-grid-col-30
-                    +dropdown('Atomicity:', `${model}.atomicityMode`, '"atomicityMode"', 'true', 'ATOMIC',
-                        '[\
-                            {value: "ATOMIC", label: "ATOMIC"},\
-                            {value: "TRANSACTIONAL", label: "TRANSACTIONAL"}\
-                        ]',
-                        'Atomicity:\
-                        <ul>\
-                            <li>ATOMIC - in this mode distributed transactions and distributed locking are not supported</li>\
-                            <li>TRANSACTIONAL - in this mode specified fully ACID-compliant transactional cache behavior</li>\
-                        </ul>')
-                .pc-form-grid-col-30(ng-is=`${model}.cacheMode === 'PARTITIONED'`)
-                    +number('Backups:', `${model}.backups`, '"backups"', 'true', '0', '0', 'Number of nodes used to back up single partition for partitioned cache')
-                //- Since ignite 2.0
-                .pc-form-grid-col-30(ng-if='$ctrl.available("2.0.0")')
-                    +dropdown('Partition loss policy:', `${model}.partitionLossPolicy`, '"partitionLossPolicy"', 'true', 'IGNORE',
+            .pc-form-grid-col-30
+                +dropdown('Atomicity:', `${model}.atomicityMode`, '"atomicityMode"', 'true', 'ATOMIC',
                     '[\
-                        {value: "READ_ONLY_SAFE", label: "READ_ONLY_SAFE"},\
-                        {value: "READ_ONLY_ALL", label: "READ_ONLY_ALL"},\
-                        {value: "READ_WRITE_SAFE", label: "READ_WRITE_SAFE"},\
-                        {value: "READ_WRITE_ALL", label: "READ_WRITE_ALL"},\
-                        {value: "IGNORE", label: "IGNORE"}\
+                        {value: "ATOMIC", label: "ATOMIC"},\
+                        {value: "TRANSACTIONAL", label: "TRANSACTIONAL"}\
                     ]',
-                    'Partition loss policies:\
+                    'Atomicity:\
                     <ul>\
-                        <li>READ_ONLY_SAFE - in this mode all writes to the cache will be failed with an exception,\
-                            reads will only be allowed for keys in  non-lost partitions.\
-                            Reads from lost partitions will be failed with an exception.</li>\
-                        <li>READ_ONLY_ALL - in this mode all writes to the cache will be failed with an exception.\
-                            All reads will proceed as if all partitions were in a consistent state.\
-                            The result of reading from a lost partition is undefined and may be different on different nodes in the cluster.</li>\
-                        <li>READ_WRITE_SAFE - in this mode all reads and writes will be allowed for keys in valid partitions.\
-                            All reads and writes for keys in lost partitions will be failed with an exception.</li>\
-                        <li>READ_WRITE_ALL - in this mode all reads and writes will proceed as if all partitions were in a consistent state.\
-                            The result of reading from a lost partition is undefined and may be different on different nodes in the cluster.</li>\
-                        <li>IGNORE - in this mode if partition is lost, reset it state and do not clear intermediate data.\
-                            The result of reading from a previously lost and not cleared partition is undefined and may be different\
-                            on different nodes in the cluster.</li>\
+                        <li>ATOMIC - in this mode distributed transactions and distributed locking are not supported</li>\
+                        <li>TRANSACTIONAL - in this mode specified fully ACID-compliant transactional cache behavior</li>\
                     </ul>')
-                .pc-form-grid-col-60(ng-show=`${model}.cacheMode === 'PARTITIONED' && ${model}.backups`)
-                    +checkbox('Read from backup', `${model}.readFromBackup`, '"readFromBackup"',
-                        'Flag indicating whether data can be read from backup<br/>\
-                        If not set then always get data from primary node (never from backup)')
-                .pc-form-grid-col-60
-                    +checkbox('Copy on read', `${model}.copyOnRead`, '"copyOnRead"',
-                        'Flag indicating whether copy of the value stored in cache should be created for cache operation implying return value<br/>\
-                        Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor')
-                .pc-form-grid-col-60(ng-show=`${model}.cacheMode === 'PARTITIONED' && ${model}.atomicityMode === 'TRANSACTIONAL'`)
-                    +checkbox('Invalidate near cache', `${model}.isInvalidate`, '"isInvalidate"',
-                        'Invalidation flag for near cache entries in transaction<br/>\
-                        If set then values will be invalidated (nullified) upon commit in near cache')
+            .pc-form-grid-col-30(ng-is=`${model}.cacheMode === 'PARTITIONED'`)
+                +number('Backups:', `${model}.backups`, '"backups"', 'true', '0', '0', 'Number of nodes used to back up single partition for partitioned cache')
+            //- Since ignite 2.0
+            .pc-form-grid-col-30(ng-if='$ctrl.available("2.0.0")')
+                +dropdown('Partition loss policy:', `${model}.partitionLossPolicy`, '"partitionLossPolicy"', 'true', 'IGNORE',
+                '[\
+                    {value: "READ_ONLY_SAFE", label: "READ_ONLY_SAFE"},\
+                    {value: "READ_ONLY_ALL", label: "READ_ONLY_ALL"},\
+                    {value: "READ_WRITE_SAFE", label: "READ_WRITE_SAFE"},\
+                    {value: "READ_WRITE_ALL", label: "READ_WRITE_ALL"},\
+                    {value: "IGNORE", label: "IGNORE"}\
+                ]',
+                'Partition loss policies:\
+                <ul>\
+                    <li>READ_ONLY_SAFE - in this mode all writes to the cache will be failed with an exception,\
+                        reads will only be allowed for keys in  non-lost partitions.\
+                        Reads from lost partitions will be failed with an exception.</li>\
+                    <li>READ_ONLY_ALL - in this mode all writes to the cache will be failed with an exception.\
+                        All reads will proceed as if all partitions were in a consistent state.\
+                        The result of reading from a lost partition is undefined and may be different on different nodes in the cluster.</li>\
+                    <li>READ_WRITE_SAFE - in this mode all reads and writes will be allowed for keys in valid partitions.\
+                        All reads and writes for keys in lost partitions will be failed with an exception.</li>\
+                    <li>READ_WRITE_ALL - in this mode all reads and writes will proceed as if all partitions were in a consistent state.\
+                        The result of reading from a lost partition is undefined and may be different on different nodes in the cluster.</li>\
+                    <li>IGNORE - in this mode if partition is lost, reset it state and do not clear intermediate data.\
+                        The result of reading from a previously lost and not cleared partition is undefined and may be different\
+                        on different nodes in the cluster.</li>\
+                </ul>')
+            .pc-form-grid-col-60(ng-show=`${model}.cacheMode === 'PARTITIONED' && ${model}.backups`)
+                +checkbox('Read from backup', `${model}.readFromBackup`, '"readFromBackup"',
+                    'Flag indicating whether data can be read from backup<br/>\
+                    If not set then always get data from primary node (never from backup)')
+            .pc-form-grid-col-60
+                +checkbox('Copy on read', `${model}.copyOnRead`, '"copyOnRead"',
+                    'Flag indicating whether copy of the value stored in cache should be created for cache operation implying return value<br/>\
+                    Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor')
+            .pc-form-grid-col-60(ng-show=`${model}.cacheMode === 'PARTITIONED' && ${model}.atomicityMode === 'TRANSACTIONAL'`)
+                +checkbox('Invalidate near cache', `${model}.isInvalidate`, '"isInvalidate"',
+                    'Invalidation flag for near cache entries in transaction<br/>\
+                    If set then values will be invalidated (nullified) upon commit in near cache')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheGeneral')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/memory.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.pug
index bcb8cda..10eb488 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.pug
@@ -19,143 +19,140 @@ include /app/helpers/jade/mixins
 -var form = 'memory'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Memory
-        .pca-panel-heading-description
-            | Cache memory settings. 
-            a.link-success(
-                href="https://apacheignite.readme.io/v1.9/docs/off-heap-memory"
-                target="_blank"
-                ng-show='$ctrl.available(["1.0.0", "2.0.0"])'
-            ) More info
-            a.link-success(
-                href="https://apacheignite.readme.io/docs/evictions"
-                target="_blank"
-                ng-show='$ctrl.available("2.0.0")'
-            ) 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
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +checkbox('Onheap cache enabled', model + '.onheapCacheEnabled', '"OnheapCacheEnabled"', 'Checks if the on-heap cache is enabled for the off-heap based page memory')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Memory
+    panel-description
+        | Cache memory settings. 
+        a.link-success(
+            href="https://apacheignite.readme.io/v1.9/docs/off-heap-memory"
+            target="_blank"
+            ng-show='$ctrl.available(["1.0.0", "2.0.0"])'
+        ) More info
+        a.link-success(
+            href="https://apacheignite.readme.io/docs/evictions"
+            target="_blank"
+            ng-show='$ctrl.available("2.0.0")'
+        ) More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +checkbox('Onheap cache enabled', model + '.onheapCacheEnabled', '"OnheapCacheEnabled"', 'Checks if the on-heap cache is enabled for the off-heap based page memory')
 
-                //- Since ignite 2.0 deprecated in ignite 2.3
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["2.0.0", "2.3.0"])')
-                    +text('Memory policy name:', model + '.memoryPolicyName', '"MemoryPolicyName"', 'false', 'default',
-                        'Name of memory policy configuration for this cache')
+            //- Since ignite 2.0 deprecated in ignite 2.3
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["2.0.0", "2.3.0"])')
+                +text('Memory policy name:', model + '.memoryPolicyName', '"MemoryPolicyName"', 'false', 'default',
+                    'Name of memory policy configuration for this cache')
 
-                //- Since ignite 2.3
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.3.0")')
-                    +text('Data region name:', model + '.dataRegionName', '"DataRegionName"', 'false', 'default',
-                        'Name of data region configuration for this cache')
+            //- Since ignite 2.3
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.3.0")')
+                +text('Data region name:', model + '.dataRegionName', '"DataRegionName"', 'false', 'default',
+                    'Name of data region configuration for this cache')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Mode:',
-                        model: `${model}.memoryMode`,
-                        name: '"memoryMode"',
-                        placeholder: '{{ ::$ctrl.Caches.memoryMode.default }}',
-                        options: '::$ctrl.Caches.memoryModes',
-                        tip: `Memory modes control whether value is stored in on-heap memory, off-heap memory, or swap space
-                        <ul>
-                            <li>
-                                ONHEAP_TIERED - entries are cached on heap memory first<br/>
-                                <ul>
-                                    <li>
-                                        If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory<br/>
-                                        If offheap memory is disabled, then entry is simply discarded
-                                    </li>
-                                    <li>
-                                        If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space<br/>
-                                        If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap
-                                    </li>
-                                </ul>
-                            </li>
-                            <li>
-                                OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away<br/>
-                                Entries get cached in offheap memory first and then get evicted to swap, if one is configured
-                            </li>
-                            <li>
-                                OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory<br/>
-                                Note that in this mode entries can be evicted only to swap
-                            </li>
-                        </ul>`
-                    })(
-                        ui-validate=`{
-                            offheapAndDomains: '$ctrl.Caches.memoryMode.offheapAndDomains(${model})'
-                        }`
-                        ui-validate-watch=`"${model}.domains.length"`
-                        ng-model-options='{allowInvalid: true}'
-                    )
-                        +form-field-feedback(null, 'offheapAndDomains', 'Query indexing could not be enabled while values are stored off-heap')
-                .pc-form-grid-col-60(ng-if=`${model}.memoryMode !== 'OFFHEAP_VALUES'`)
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Off-heap memory:',
-                        model: `${model}.offHeapMode`,
-                        name: '"offHeapMode"',
-                        required: `$ctrl.Caches.offHeapMode.required(${model})`,
-                        placeholder: '{{::$ctrl.Caches.offHeapMode.default}}',
-                        options: '{{::$ctrl.Caches.offHeapModes}}',
-                        tip: `Off-heap storage mode
-                        <ul>
-                            <li>Disabled - Off-heap storage is disabled</li>
-                            <li>Limited - Off-heap storage has limited size</li>
-                            <li>Unlimited - Off-heap storage grow infinitely (it is up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely)</li>
-                        </ul>`
-                    })(
-                        ng-change=`$ctrl.Caches.offHeapMode.onChange(${model})`
-                        ui-validate=`{
-                            offheapDisabled: '$ctrl.Caches.offHeapMode.offheapDisabled(${model})'
-                        }`
-                        ui-validate-watch=`'${model}.memoryMode'`
-                        ng-model-options='{allowInvalid: true}'
-                    )
-                        +form-field-feedback(null, 'offheapDisabled', 'Off-heap storage can\'t be disabled when memory mode is OFFHEAP_TIERED')
-                .pc-form-grid-col-60(
-                    ng-if=`${model}.offHeapMode === 1 && ${model}.memoryMode !== 'OFFHEAP_VALUES'`
-                    ng-if-end
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
+                +sane-ignite-form-field-dropdown({
+                    label: 'Mode:',
+                    model: `${model}.memoryMode`,
+                    name: '"memoryMode"',
+                    placeholder: '{{ ::$ctrl.Caches.memoryMode.default }}',
+                    options: '::$ctrl.Caches.memoryModes',
+                    tip: `Memory modes control whether value is stored in on-heap memory, off-heap memory, or swap space
+                    <ul>
+                        <li>
+                            ONHEAP_TIERED - entries are cached on heap memory first<br/>
+                            <ul>
+                                <li>
+                                    If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory<br/>
+                                    If offheap memory is disabled, then entry is simply discarded
+                                </li>
+                                <li>
+                                    If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space<br/>
+                                    If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap
+                                </li>
+                            </ul>
+                        </li>
+                        <li>
+                            OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away<br/>
+                            Entries get cached in offheap memory first and then get evicted to swap, if one is configured
+                        </li>
+                        <li>
+                            OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory<br/>
+                            Note that in this mode entries can be evicted only to swap
+                        </li>
+                    </ul>`
+                })(
+                    ui-validate=`{
+                        offheapAndDomains: '$ctrl.Caches.memoryMode.offheapAndDomains(${model})'
+                    }`
+                    ui-validate-watch=`"${model}.domains.length"`
+                    ng-model-options='{allowInvalid: true}'
                 )
-                    pc-form-field-size(
-                        label='Off-heap memory max size:'
-                        ng-model=`${model}.offHeapMaxMemory`
-                        name='offHeapMaxMemory'
-                        placeholder='Enter off-heap memory size'
-                        min='{{ ::$ctrl.Caches.offHeapMaxMemory.min }}'
-                        tip='Maximum amount of memory available to off-heap storage'
-                        size-scale-label='mb'
-                        size-type='bytes'
-                        required='true'
-                    )
-                +evictionPolicy(`${model}.evictionPolicy`, '"evictionPolicy"', 'true',
-                    `$ctrl.Caches.evictionPolicy.required(${model})`,
-                    'Optional cache eviction policy<br/>\
-                    Must be set for entries to be evicted from on-heap to off-heap or swap\
-                    <ul>\
-                        <li>Least Recently Used(LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
-                        <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
-                        <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
-                    </ul>')
+                    +form-field-feedback(null, 'offheapAndDomains', 'Query indexing could not be enabled while values are stored off-heap')
+            .pc-form-grid-col-60(ng-if=`${model}.memoryMode !== 'OFFHEAP_VALUES'`)
+                +sane-ignite-form-field-dropdown({
+                    label: 'Off-heap memory:',
+                    model: `${model}.offHeapMode`,
+                    name: '"offHeapMode"',
+                    required: `$ctrl.Caches.offHeapMode.required(${model})`,
+                    placeholder: '{{::$ctrl.Caches.offHeapMode.default}}',
+                    options: '{{::$ctrl.Caches.offHeapModes}}',
+                    tip: `Off-heap storage mode
+                    <ul>
+                        <li>Disabled - Off-heap storage is disabled</li>
+                        <li>Limited - Off-heap storage has limited size</li>
+                        <li>Unlimited - Off-heap storage grow infinitely (it is up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely)</li>
+                    </ul>`
+                })(
+                    ng-change=`$ctrl.Caches.offHeapMode.onChange(${model})`
+                    ui-validate=`{
+                        offheapDisabled: '$ctrl.Caches.offHeapMode.offheapDisabled(${model})'
+                    }`
+                    ui-validate-watch=`'${model}.memoryMode'`
+                    ng-model-options='{allowInvalid: true}'
+                )
+                    +form-field-feedback(null, 'offheapDisabled', 'Off-heap storage can\'t be disabled when memory mode is OFFHEAP_TIERED')
+            .pc-form-grid-col-60(
+                ng-if=`${model}.offHeapMode === 1 && ${model}.memoryMode !== 'OFFHEAP_VALUES'`
+                ng-if-end
+            )
+                pc-form-field-size(
+                    label='Off-heap memory max size:'
+                    ng-model=`${model}.offHeapMaxMemory`
+                    name='offHeapMaxMemory'
+                    placeholder='Enter off-heap memory size'
+                    min='{{ ::$ctrl.Caches.offHeapMaxMemory.min }}'
+                    tip='Maximum amount of memory available to off-heap storage'
+                    size-scale-label='mb'
+                    size-type='bytes'
+                    required='true'
+                )
+            +evictionPolicy(`${model}.evictionPolicy`, '"evictionPolicy"', 'true',
+                `$ctrl.Caches.evictionPolicy.required(${model})`,
+                'Optional cache eviction policy<br/>\
+                Must be set for entries to be evicted from on-heap to off-heap or swap\
+                <ul>\
+                    <li>Least Recently Used(LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
+                    <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
+                    <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
+                </ul>')
 
-                //- Since ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
-                    +java-class('Eviction filter:', model + '.evictionFilter', '"EvictionFilter"', 'true', 'false', 'Eviction filter to specify which entries should not be evicted')
+            //- Since ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available("2.0.0")')
+                +java-class('Eviction filter:', model + '.evictionFilter', '"EvictionFilter"', 'true', 'false', 'Eviction filter to specify which entries should not be evicted')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Start size:', `${model}.startSize`, '"startSize"', 'true', '1500000', '0',
-                        'In terms of size and capacity, Ignite internal cache map acts exactly like a normal Java HashMap: it has some initial capacity\
-                        (which is pretty small by default), which doubles as data arrives. The process of internal cache map resizing is CPU-intensive\
-                        and time-consuming, and if you load a huge dataset into cache (which is a normal use case), the map will have to resize a lot of times.\
-                        To avoid that, you can specify the initial cache map capacity, comparable to the expected size of your dataset.\
-                        This will save a lot of CPU resources during the load time, because the map would not have to resize.\
-                        For example, if you expect to load 10 million entries into cache, you can set this property to 10 000 000.\
-                        This will save you from cache internal map resizes.')
-                .pc-form-grid-col-60(ng-if-end)
-                    +checkbox('Swap enabled', `${model}.swapEnabled`, '"swapEnabled"', 'Flag indicating whether swap storage is enabled or not for this cache')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Start size:', `${model}.startSize`, '"startSize"', 'true', '1500000', '0',
+                    'In terms of size and capacity, Ignite internal cache map acts exactly like a normal Java HashMap: it has some initial capacity\
+                    (which is pretty small by default), which doubles as data arrives. The process of internal cache map resizing is CPU-intensive\
+                    and time-consuming, and if you load a huge dataset into cache (which is a normal use case), the map will have to resize a lot of times.\
+                    To avoid that, you can specify the initial cache map capacity, comparable to the expected size of your dataset.\
+                    This will save a lot of CPU resources during the load time, because the map would not have to resize.\
+                    For example, if you expect to load 10 million entries into cache, you can set this property to 10 000 000.\
+                    This will save you from cache internal map resizes.')
+            .pc-form-grid-col-60(ng-if-end)
+                +checkbox('Swap enabled', `${model}.swapEnabled`, '"swapEnabled"', 'Flag indicating whether swap storage is enabled or not for this cache')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheMemory')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheMemory')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.pug
index ff51361..2b6705d 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.pug
@@ -19,31 +19,32 @@ include /app/helpers/jade/mixins
 -var form = 'clientNearCache'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate ng-show=`${model}.cacheMode === 'PARTITIONED'`)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Near cache on client node
-        .pca-panel-heading-description
-            | Near cache settings for client nodes. 
-            | Near cache is a small local cache that stores most recently or most frequently accessed data. 
-            | Should be used in case when it is impossible to send computations to remote nodes.
-    .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 nearCfg = `${model}.clientNearConfiguration`
-                -var enabled = `${nearCfg}.enabled`
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show=`${model}.cacheMode === 'PARTITIONED'`
+)
+    panel-title Near cache on client node
+    panel-description
+        | Near cache settings for client nodes. 
+        | Near cache is a small local cache that stores most recently or most frequently accessed data. 
+        | Should be used in case when it is impossible to send computations to remote nodes.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            -var nearCfg = `${model}.clientNearConfiguration`
+            -var enabled = `${nearCfg}.enabled`
 
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', enabled, '"clientNearEnabled"', 'Flag indicating whether to configure near cache')
-                .pc-form-grid-col-60
-                    +number('Start size:', `${nearCfg}.nearStartSize`, '"clientNearStartSize"', enabled, '375000', '0',
-                        'Initial cache size for near cache which will be used to pre-create internal hash table after start')
-                +evictionPolicy(`${nearCfg}.nearEvictionPolicy`, '"clientNearCacheEvictionPolicy"', enabled, 'false',
-                    'Near cache eviction policy\
-                    <ul>\
-                        <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
-                        <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
-                        <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
-                    </ul>')
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheNearClient')
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"clientNearEnabled"', 'Flag indicating whether to configure near cache')
+            .pc-form-grid-col-60
+                +number('Start size:', `${nearCfg}.nearStartSize`, '"clientNearStartSize"', enabled, '375000', '0',
+                    'Initial cache size for near cache which will be used to pre-create internal hash table after start')
+            +evictionPolicy(`${nearCfg}.nearEvictionPolicy`, '"clientNearCacheEvictionPolicy"', enabled, 'false',
+                'Near cache eviction policy\
+                <ul>\
+                    <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
+                    <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
+                    <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
+                </ul>')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheNearClient')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.pug
index 40f7024..3a91fd2 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.pug
@@ -19,32 +19,33 @@ include /app/helpers/jade/mixins
 -var form = 'serverNearCache'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate ng-show=`${model}.cacheMode === 'PARTITIONED'`)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Near cache on server node
-        .pca-panel-heading-description
-            | Near cache settings. 
-            | Near cache is a small local cache that stores most recently or most frequently accessed data. 
-            | Should be used in case when it is impossible to send computations to remote nodes. 
-            a.link-success(href="https://apacheignite.readme.io/docs/near-caches" 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 nearCfg = `${model}.nearConfiguration`
-                -var enabled = `${nearCfg}.enabled`
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show=`${model}.cacheMode === 'PARTITIONED'`
+)
+    panel-title Near cache on server node
+    panel-description
+        | Near cache settings. 
+        | Near cache is a small local cache that stores most recently or most frequently accessed data. 
+        | Should be used in case when it is impossible to send computations to remote nodes. 
+        a.link-success(href="https://apacheignite.readme.io/docs/near-caches" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            -var nearCfg = `${model}.nearConfiguration`
+            -var enabled = `${nearCfg}.enabled`
 
-                .pc-form-grid-col-60
-                    +checkbox('Enabled', enabled, '"nearCacheEnabled"', 'Flag indicating whether to configure near cache')
-                .pc-form-grid-col-60
-                    +number('Start size:', `${nearCfg}.nearStartSize`, '"nearStartSize"', enabled, '375000', '0',
-                        'Initial cache size for near cache which will be used to pre-create internal hash table after start')
-                +evictionPolicy(`${model}.nearConfiguration.nearEvictionPolicy`, '"nearCacheEvictionPolicy"', enabled, 'false',
-                    'Near cache eviction policy\
-                    <ul>\
-                        <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
-                        <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
-                        <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
-                    </ul>')
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheNearServer')
+            .pc-form-grid-col-60
+                +checkbox('Enabled', enabled, '"nearCacheEnabled"', 'Flag indicating whether to configure near cache')
+            .pc-form-grid-col-60
+                +number('Start size:', `${nearCfg}.nearStartSize`, '"nearStartSize"', enabled, '375000', '0',
+                    'Initial cache size for near cache which will be used to pre-create internal hash table after start')
+            +evictionPolicy(`${model}.nearConfiguration.nearEvictionPolicy`, '"nearCacheEvictionPolicy"', enabled, 'false',
+                'Near cache eviction policy\
+                <ul>\
+                    <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
+                    <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
+                    <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
+                </ul>')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheNearServer')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.pug
index c40ea59..11938f9 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.pug
@@ -23,35 +23,31 @@ include /app/helpers/jade/mixins
 -var igfsFilter = nodeFilterKind + ' === "IGFS"'
 -var customFilter = nodeFilterKind + ' === "Custom"'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title(id='nodeFilter-title') Node filter
-        .pca-panel-heading-description
-            | Determines on what nodes the cache should be started.
-    .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
-                    +dropdown('Node filter:', nodeFilterKind, '"nodeFilter"', 'true', 'Not set', '::$ctrl.Caches.nodeFilterKinds', 'Node filter variant')
-                .pc-form-grid-col-60(
-                    ng-if=igfsFilter
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Node filter
+    panel-description Determines on what nodes the cache should be started.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('Node filter:', nodeFilterKind, '"nodeFilter"', 'true', 'Not set', '::$ctrl.Caches.nodeFilterKinds', 'Node filter variant')
+            .pc-form-grid-col-60(
+                ng-if=igfsFilter
+            )
+                +sane-ignite-form-field-dropdown({
+                    label: 'IGFS:',
+                    model: `${nodeFilter}.IGFS.igfs`,
+                    name: '"igfsNodeFilter"',
+                    required: true,
+                    placeholder: 'Choose IGFS',
+                    placeholderEmpty: 'No IGFS configured',
+                    options: '$ctrl.igfssMenu',
+                    tip: 'Select IGFS to filter nodes'
+                })(
+                    pc-is-in-collection='$ctrl.igfsIDs'
                 )
-                    +sane-ignite-form-field-dropdown({
-                        label: 'IGFS:',
-                        model: `${nodeFilter}.IGFS.igfs`,
-                        name: '"igfsNodeFilter"',
-                        required: true,
-                        placeholder: 'Choose IGFS',
-                        placeholderEmpty: 'No IGFS configured',
-                        options: '$ctrl.igfssMenu',
-                        tip: 'Select IGFS to filter nodes'
-                    })(
-                        pc-is-in-collection='$ctrl.igfsIDs'
-                    )
-                        +form-field-feedback(_, 'isInCollection', `Cluster doesn't have such an IGFS`)
-                .pc-form-grid-col-60(ng-show=customFilter)
-                    +java-class('Class name:', `${nodeFilter}.Custom.className`, '"customNodeFilter"',
-                        'true', customFilter, 'Class name of custom node filter implementation', customFilter)
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheNodeFilter', 'igfss')
+                    +form-field-feedback(_, 'isInCollection', `Cluster doesn't have such an IGFS`)
+            .pc-form-grid-col-60(ng-show=customFilter)
+                +java-class('Class name:', `${nodeFilter}.Custom.className`, '"customNodeFilter"',
+                    'true', customFilter, 'Class name of custom node filter implementation', customFilter)
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheNodeFilter', 'igfss')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/query.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/query.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/query.pug
index 471b011..20869f5 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/query.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/query.pug
@@ -19,99 +19,96 @@ include /app/helpers/jade/mixins
 -var form = 'query'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Queries & Indexing
-        .pca-panel-heading-description
-            | Cache queries settings. 
-            a.link-success(href="https://apacheignite-sql.readme.io/docs/select" 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
-                .pc-form-grid-col-60
-                    +text('SQL schema name:', `${model}.sqlSchema`, '"sqlSchema"', 'false', 'Input schema name',
-                        'Specify any custom name to be used as SQL schema for current cache. This name will correspond to SQL ANSI-99 standard.\
-                        Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive.\
-                        When SQL schema is not specified, quoted cache name should used instead.<br/>\
-                        For example:\
-                        <ul>\
-                            <li>\
-                                Query without schema names (quoted cache names will be used):\
-                                SELECT * FROM "PersonsCache".Person p INNER JOIN "OrganizationsCache".Organization o on p.org = o.id\
-                            </li>\
-                            <li>\
-                                The same query using schema names "Persons" and "Organizations":\
-                                SELECT * FROM Persons.Person p INNER JOIN Organizations.Organization o on p.org = o.id\
-                            </li>\
-                        </ul>')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Queries & Indexing
+    panel-description 
+        | Cache queries settings. 
+        a.link-success(href="https://apacheignite-sql.readme.io/docs/select" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +text('SQL schema name:', `${model}.sqlSchema`, '"sqlSchema"', 'false', 'Input schema name',
+                    'Specify any custom name to be used as SQL schema for current cache. This name will correspond to SQL ANSI-99 standard.\
+                    Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive.\
+                    When SQL schema is not specified, quoted cache name should used instead.<br/>\
+                    For example:\
+                    <ul>\
+                        <li>\
+                            Query without schema names (quoted cache names will be used):\
+                            SELECT * FROM "PersonsCache".Person p INNER JOIN "OrganizationsCache".Organization o on p.org = o.id\
+                        </li>\
+                        <li>\
+                            The same query using schema names "Persons" and "Organizations":\
+                            SELECT * FROM Persons.Person p INNER JOIN Organizations.Organization o on p.org = o.id\
+                        </li>\
+                    </ul>')
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('On-heap cache for off-heap indexes:', `${model}.sqlOnheapRowCacheSize`, '"sqlOnheapRowCacheSize"', 'true', '10240', '1',
-                        'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('On-heap cache for off-heap indexes:', `${model}.sqlOnheapRowCacheSize`, '"sqlOnheapRowCacheSize"', 'true', '10240', '1',
+                    'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access')
 
-                //- Deprecated in ignite 2.1
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.1.0"])')
-                    +number('Long query timeout:', `${model}.longQueryWarningTimeout`, '"longQueryWarningTimeout"', 'true', '3000', '0',
-                        'Timeout in milliseconds after which long query warning will be printed')
-                .pc-form-grid-col-60
-                    +number('History size:', `${model}.queryDetailMetricsSize`, '"queryDetailMetricsSize"', 'true', '0', '0',
-                        'Size of queries detail metrics that will be stored in memory for monitoring purposes')
-                .pc-form-grid-col-60
-                    mixin caches-query-list-sql-functions()
-                        .ignite-form-field
-                            -let items = `${model}.sqlFunctionClasses`;
-                            -let uniqueTip = 'SQL function with such class name already exists!'
+            //- Deprecated in ignite 2.1
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.1.0"])')
+                +number('Long query timeout:', `${model}.longQueryWarningTimeout`, '"longQueryWarningTimeout"', 'true', '3000', '0',
+                    'Timeout in milliseconds after which long query warning will be printed')
+            .pc-form-grid-col-60
+                +number('History size:', `${model}.queryDetailMetricsSize`, '"queryDetailMetricsSize"', 'true', '0', '0',
+                    'Size of queries detail metrics that will be stored in memory for monitoring purposes')
+            .pc-form-grid-col-60
+                mixin caches-query-list-sql-functions()
+                    .ignite-form-field
+                        -let items = `${model}.sqlFunctionClasses`;
+                        -let uniqueTip = 'SQL function with such class name already exists!'
 
-                            list-editable(
-                                ng-model=items
-                                list-editable-cols=`::[{
-                                    name: 'SQL functions:',
-                                    tip: 'Collections of classes with user-defined functions for SQL queries'
-                                }]`
-                            )
-                                list-editable-item-view {{ $item }}
+                        list-editable(
+                            ng-model=items
+                            list-editable-cols=`::[{
+                                name: 'SQL functions:',
+                                tip: 'Collections of classes with user-defined functions for SQL queries'
+                            }]`
+                        )
+                            list-editable-item-view {{ $item }}
 
-                                list-editable-item-edit
-                                    +list-java-class-field('SQL function', '$item', '"sqlFunction"', items)
-                                        +unique-feedback('"sqlFunction"', uniqueTip)
+                            list-editable-item-edit
+                                +list-java-class-field('SQL function', '$item', '"sqlFunction"', items)
+                                    +unique-feedback('"sqlFunction"', uniqueTip)
 
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$editLast((${items} = ${items} || []).push(""))`
-                                        label-single='SQL function'
-                                        label-multiple='SQL functions'
-                                    )
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$editLast((${items} = ${items} || []).push(""))`
+                                    label-single='SQL function'
+                                    label-multiple='SQL functions'
+                                )
 
-                    - var form = '$parent.form'
-                    +caches-query-list-sql-functions
-                    - var form = 'query'
+                - var form = '$parent.form'
+                +caches-query-list-sql-functions
+                - var form = 'query'
 
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +checkbox('Snapshotable index', `${model}.snapshotableIndex`, '"snapshotableIndex"',
-                        'Flag indicating whether SQL indexes should support snapshots')
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-60(ng-if='$ctrl.available(["1.0.0", "2.0.0"])')
+                +checkbox('Snapshotable index', `${model}.snapshotableIndex`, '"snapshotableIndex"',
+                    'Flag indicating whether SQL indexes should support snapshots')
 
-                .pc-form-grid-col-60
-                    +checkbox('Escape table and filed names', `${model}.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 creation internal structures in Ignite SQL engine.')
+            .pc-form-grid-col-60
+                +checkbox('Escape table and filed names', `${model}.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 creation internal structures in Ignite SQL engine.')
 
-                //- Since ignite 2.0
-                .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
-                    +number('Query parallelism', model + '.queryParallelism', '"queryParallelism"', 'true', '1', '1',
-                        'A hint to query execution engine on desired degree of parallelism within a single node')
-                .pc-form-grid-col-30(ng-if-end)
-                    +sane-ignite-form-field-number({
-                        label: 'SQL index max inline size:',
-                        model: `${model}.sqlIndexMaxInlineSize`,
-                        name: '"sqlIndexMaxInlineSize"',
-                        placeholder: '-1',
-                        min: '-1',
-                        tip: 'Maximum inline size for sql indexes'
-                    })
+            //- Since ignite 2.0
+            .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
+                +number('Query parallelism', model + '.queryParallelism', '"queryParallelism"', 'true', '1', '1',
+                    'A hint to query execution engine on desired degree of parallelism within a single node')
+            .pc-form-grid-col-30(ng-if-end)
+                +sane-ignite-form-field-number({
+                    label: 'SQL index max inline size:',
+                    model: `${model}.sqlIndexMaxInlineSize`,
+                    name: '"sqlIndexMaxInlineSize"',
+                    placeholder: '-1',
+                    min: '-1',
+                    tip: 'Maximum inline size for sql indexes'
+                })
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheQuery', 'domains')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheQuery', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.pug b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.pug
index 79ed803e..7563435 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.pug
@@ -19,47 +19,48 @@ include /app/helpers/jade/mixins
 -var form = 'rebalance'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate ng-hide=`${model}.cacheMode === "LOCAL"`)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Rebalance
-        .pca-panel-heading-description
-            | Cache rebalance settings. 
-            a.link-success(href="https://apacheignite.readme.io/docs/rebalancing" 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
-                .pc-form-grid-col-30
-                    +dropdown('Mode:', `${model}.rebalanceMode`, '"rebalanceMode"', 'true', 'ASYNC',
-                        '[\
-                            {value: "SYNC", label: "SYNC"},\
-                            {value: "ASYNC", label: "ASYNC"},\
-                            {value: "NONE", label: "NONE"}\
-                        ]',
-                        'Rebalance modes\
-                        <ul>\
-                            <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes</li>\
-                            <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background</li>\
-                            <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly</li>\
-                        </ul>')
-                .pc-form-grid-col-30
-                    +number('Batch size:', `${model}.rebalanceBatchSize`, '"rebalanceBatchSize"', 'true', '512 * 1024', '1',
-                        'Size (in bytes) to be loaded within a single rebalance message<br/>\
-                        Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data')
-                .pc-form-grid-col-30
-                    +number('Batches prefetch count:', `${model}.rebalanceBatchesPrefetchCount`, '"rebalanceBatchesPrefetchCount"', 'true', '2', '1',
-                        'Number of batches generated by supply node at rebalancing start')
-                .pc-form-grid-col-30
-                    +number('Order:', `${model}.rebalanceOrder`, '"rebalanceOrder"', 'true', '0', Number.MIN_SAFE_INTEGER,
-                        'If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed')
-                .pc-form-grid-col-20
-                    +number('Delay:', `${model}.rebalanceDelay`, '"rebalanceDelay"', 'true', '0', '0',
-                        'Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically')
-                .pc-form-grid-col-20
-                    +number('Timeout:', `${model}.rebalanceTimeout`, '"rebalanceTimeout"', 'true', '10000', '0',
-                        'Rebalance timeout in milliseconds')
-                .pc-form-grid-col-20
-                    +number('Throttle:', `${model}.rebalanceThrottle`, '"rebalanceThrottle"', 'true', '0', '0',
-                        'Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network')
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheRebalance')
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-hide=`${model}.cacheMode === "LOCAL"`
+)
+    panel-title Rebalance
+    panel-description
+        | Cache rebalance settings. 
+        a.link-success(href="https://apacheignite.readme.io/docs/rebalancing" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +dropdown('Mode:', `${model}.rebalanceMode`, '"rebalanceMode"', 'true', 'ASYNC',
+                    '[\
+                        {value: "SYNC", label: "SYNC"},\
+                        {value: "ASYNC", label: "ASYNC"},\
+                        {value: "NONE", label: "NONE"}\
+                    ]',
+                    'Rebalance modes\
+                    <ul>\
+                        <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes</li>\
+                        <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background</li>\
+                        <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly</li>\
+                    </ul>')
+            .pc-form-grid-col-30
+                +number('Batch size:', `${model}.rebalanceBatchSize`, '"rebalanceBatchSize"', 'true', '512 * 1024', '1',
+                    'Size (in bytes) to be loaded within a single rebalance message<br/>\
+                    Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data')
+            .pc-form-grid-col-30
+                +number('Batches prefetch count:', `${model}.rebalanceBatchesPrefetchCount`, '"rebalanceBatchesPrefetchCount"', 'true', '2', '1',
+                    'Number of batches generated by supply node at rebalancing start')
+            .pc-form-grid-col-30
+                +number('Order:', `${model}.rebalanceOrder`, '"rebalanceOrder"', 'true', '0', Number.MIN_SAFE_INTEGER,
+                    'If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed')
+            .pc-form-grid-col-20
+                +number('Delay:', `${model}.rebalanceDelay`, '"rebalanceDelay"', 'true', '0', '0',
+                    'Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically')
+            .pc-form-grid-col-20
+                +number('Timeout:', `${model}.rebalanceTimeout`, '"rebalanceTimeout"', 'true', '10000', '0',
+                    'Rebalance timeout in milliseconds')
+            .pc-form-grid-col-20
+                +number('Throttle:', `${model}.rebalanceThrottle`, '"rebalanceThrottle"', 'true', '0', '0',
+                    'Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheRebalance')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/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 676234f..bf58354 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
@@ -19,20 +19,16 @@ include /app/helpers/jade/mixins
 -var form = 'statistics'
 -var model = '$ctrl.clonedCache'
 
-.pca-panel(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .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')
-                .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')
-            .pca-form-column-6
-                +preview-xml-java(model, 'cacheStatistics')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Statistics
+    panel-description Cache statistics and management settings.
+    panel-content.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')
+            .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')
+        .pca-form-column-6
+            +preview-xml-java(model, 'cacheStatistics')


[2/8] ignite git commit: IGNITE-7894 Web Console: Refactored panel-collapsible to component.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.pug
index e44e6a1..ef73ab9 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.pug
@@ -21,53 +21,54 @@ include /app/helpers/jade/mixins
 -var swapModel = model + '.swapSpaceSpi'
 -var fileSwapModel = swapModel + '.FileSwapSpaceSpi'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["1.0.0", "2.0.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Swap
-        .pca-panel-heading-description
-            | Settings for overflow data to disk if it cannot fit in memory. 
-            | #[a.link-success(href="https://apacheignite.readme.io/v1.9/docs/off-heap-memory#swap-space" target="_blank") More info]
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body(ng-if=`$ctrl.available(["1.0.0", "2.0.0"]) && ui.isPanelLoaded('${form}')`).pca-form-row
-            .pca-form-column-6.pc-form-grid-row
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-show='$ctrl.available(["1.0.0", "2.0.0"])'
+)
+    panel-title Swap
+    panel-description
+        | Settings for overflow data to disk if it cannot fit in memory. 
+        | #[a.link-success(href="https://apacheignite.readme.io/v1.9/docs/off-heap-memory#swap-space" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`$ctrl.available(["1.0.0", "2.0.0"]) && ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +dropdown('Swap space SPI:', `${swapModel}.kind`, '"swapSpaceSpi"', 'true', 'Choose swap SPI',
+                    '::$ctrl.Clusters.swapSpaceSpis',
+                    'Provides a mechanism in grid for storing data on disk<br/>\
+                    Ignite cache uses swap space to overflow data to disk if it cannot fit in memory\
+                    <ul>\
+                        <li>File-based swap - File-based swap space SPI implementation which holds keys in memory</li>\
+                        <li>Not set - File-based swap space SPI with default configuration when it needed</li>\
+                    </ul>')
+            .pc-form-group.pc-form-grid-row(ng-show=`${swapModel}.kind`)
                 .pc-form-grid-col-60
-                    +dropdown('Swap space SPI:', `${swapModel}.kind`, '"swapSpaceSpi"', 'true', 'Choose swap SPI',
-                        '::$ctrl.Clusters.swapSpaceSpis',
-                        'Provides a mechanism in grid for storing data on disk<br/>\
-                        Ignite cache uses swap space to overflow data to disk if it cannot fit in memory\
-                        <ul>\
-                            <li>File-based swap - File-based swap space SPI implementation which holds keys in memory</li>\
-                            <li>Not set - File-based swap space SPI with default configuration when it needed</li>\
-                        </ul>')
-                .pc-form-group.pc-form-grid-row(ng-show=`${swapModel}.kind`)
-                    .pc-form-grid-col-60
-                        +text('Base directory:', `${fileSwapModel}.baseDirectory`, '"baseDirectory"', 'false', 'swapspace',
-                            'Base directory where to write files')
-                    .pc-form-grid-col-30
-                        +sane-ignite-form-field-number({
-                            label: 'Read stripe size:',
-                            model: `${fileSwapModel}.readStripesNumber`,
-                            name: '"readStripesNumber"',
-                            placeholder: '{{ ::$ctrl.Clusters.swapSpaceSpi.readStripesNumber.default }}',
-                            tip: 'Read stripe size defines number of file channels to be used concurrently'
-                        })(
-                            ui-validate=`{
-                                powerOfTwo: '$ctrl.Clusters.swapSpaceSpi.readStripesNumber.customValidators.powerOfTwo($value)'
-                            }`
-                        )
-                            +form-field-feedback('"readStripesNumber"', 'powerOfTwo', 'Read stripe size must be positive and power of two')
-                    .pc-form-grid-col-30
-                        +number-min-max-step('Maximum sparsity:', `${fileSwapModel}.maximumSparsity`, '"maximumSparsity"', 'true', '0.5', '0', '0.999', '0.05',
-                            'This property defines maximum acceptable wasted file space to whole file size ratio<br/>\
-                            When this ratio becomes higher than specified number compacting thread starts working')
-                    .pc-form-grid-col-30
-                        +number('Max write queue size:', `${fileSwapModel}.maxWriteQueueSize`, '"maxWriteQueueSize"', 'true', '1024 * 1024', '0',
-                            'Max write queue size in bytes<br/>\
-                            If there are more values are waiting for being written to disk then specified size, SPI will block on store operation')
-                    .pc-form-grid-col-30
-                        +number('Write buffer size:', `${fileSwapModel}.writeBufferSize`, '"writeBufferSize"', 'true', '64 * 1024', '0',
-                            'Write buffer size in bytes<br/>\
-                            Write to disk occurs only when this buffer is full')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterSwap')
+                    +text('Base directory:', `${fileSwapModel}.baseDirectory`, '"baseDirectory"', 'false', 'swapspace',
+                        'Base directory where to write files')
+                .pc-form-grid-col-30
+                    +sane-ignite-form-field-number({
+                        label: 'Read stripe size:',
+                        model: `${fileSwapModel}.readStripesNumber`,
+                        name: '"readStripesNumber"',
+                        placeholder: '{{ ::$ctrl.Clusters.swapSpaceSpi.readStripesNumber.default }}',
+                        tip: 'Read stripe size defines number of file channels to be used concurrently'
+                    })(
+                        ui-validate=`{
+                            powerOfTwo: '$ctrl.Clusters.swapSpaceSpi.readStripesNumber.customValidators.powerOfTwo($value)'
+                        }`
+                    )
+                        +form-field-feedback('"readStripesNumber"', 'powerOfTwo', 'Read stripe size must be positive and power of two')
+                .pc-form-grid-col-30
+                    +number-min-max-step('Maximum sparsity:', `${fileSwapModel}.maximumSparsity`, '"maximumSparsity"', 'true', '0.5', '0', '0.999', '0.05',
+                        'This property defines maximum acceptable wasted file space to whole file size ratio<br/>\
+                        When this ratio becomes higher than specified number compacting thread starts working')
+                .pc-form-grid-col-30
+                    +number('Max write queue size:', `${fileSwapModel}.maxWriteQueueSize`, '"maxWriteQueueSize"', 'true', '1024 * 1024', '0',
+                        'Max write queue size in bytes<br/>\
+                        If there are more values are waiting for being written to disk then specified size, SPI will block on store operation')
+                .pc-form-grid-col-30
+                    +number('Write buffer size:', `${fileSwapModel}.writeBufferSize`, '"writeBufferSize"', 'true', '64 * 1024', '0',
+                        'Write buffer size in bytes<br/>\
+                        Write to disk occurs only when this buffer is full')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterSwap')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.pug
index 4efa987..ebe3bcd 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.pug
@@ -20,129 +20,125 @@ include /app/helpers/jade/mixins
 -var model = '$ctrl.clonedCluster'
 -var executors = model + '.executorConfiguration'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Thread pools size
-        .pca-panel-heading-description
-            | Settings for node thread pools.
-    .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
-                    +number('Public:', model + '.publicThreadPoolSize', '"publicThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'System:',
-                        model: `${model}.systemThreadPoolSize`,
-                        name: '"systemThreadPoolSize"',
-                        placeholder: '{{ ::$ctrl.Clusters.systemThreadPoolSize.default }}',
-                        min: '{{ ::$ctrl.Clusters.systemThreadPoolSize.min }}',
-                        tip: 'Thread pool that is in charge of processing internal system messages'
-                    })
-                .pc-form-grid-col-30
-                    +number('Service:', model + '.serviceThreadPoolSize', '"serviceThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool that is in charge of processing proxy invocation')
-                .pc-form-grid-col-30
-                    +number('Management:', model + '.managementThreadPoolSize', '"managementThreadPoolSize"', 'true', '4', '1',
-                        'Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs')
-                .pc-form-grid-col-30
-                    +number('IGFS:', model + '.igfsThreadPoolSize', '"igfsThreadPoolSize"', 'true', 'availableProcessors', '1',
-                        'Thread pool that is in charge of processing outgoing IGFS messages')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-number({
-                        label: 'Rebalance:',
-                        model: `${model}.rebalanceThreadPoolSize`,
-                        name: '"rebalanceThreadPoolSize"',
-                        placeholder: '{{ ::$ctrl.Clusters.rebalanceThreadPoolSize.default }}',
-                        min: '{{ ::$ctrl.Clusters.rebalanceThreadPoolSize.min }}',
-                        max: `{{ $ctrl.Clusters.rebalanceThreadPoolSize.max(${model}) }}`,
-                        tip: 'Max count of threads can be used at rebalancing'
-                    })
-                        +form-field-feedback('max', 'Rebalance thread pool size should not exceed or be equal to System thread pool size')
-                .pc-form-grid-col-30
-                    +number('Utility cache:', model + '.utilityCacheThreadPoolSize', '"utilityCacheThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
-                        'Default thread pool size that will be used to process utility cache messages')
-                .pc-form-grid-col-30
-                    pc-form-field-size(
-                        label='Utility cache keep alive time:'
-                        ng-model=`${model}.utilityCacheKeepAliveTime`
-                        name='utilityCacheKeepAliveTime'
-                        size-type='seconds'
-                        size-scale-label='s'
-                        tip='Keep alive time of thread pool size that will be used to process utility cache messages'
-                        min='0'
-                        placeholder='{{ 60000 / _s1.value }}'
-                        on-scale-change='_s1 = $event'
-                    )
-                .pc-form-grid-col-30
-                    +number('Async callback:', model + '.asyncCallbackPoolSize', '"asyncCallbackPoolSize"', 'true', 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing asynchronous callbacks')
-                .pc-form-grid-col-30
-                    +number('Striped:', model + '.stripedPoolSize', '"stripedPoolSize"', 'true', 'max(8, availableProcessors)', '1',
-                        'Striped pool size that should be used for cache requests processing')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Thread pools size
+    panel-description Settings for node thread pools.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +number('Public:', model + '.publicThreadPoolSize', '"publicThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                    'Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'System:',
+                    model: `${model}.systemThreadPoolSize`,
+                    name: '"systemThreadPoolSize"',
+                    placeholder: '{{ ::$ctrl.Clusters.systemThreadPoolSize.default }}',
+                    min: '{{ ::$ctrl.Clusters.systemThreadPoolSize.min }}',
+                    tip: 'Thread pool that is in charge of processing internal system messages'
+                })
+            .pc-form-grid-col-30
+                +number('Service:', model + '.serviceThreadPoolSize', '"serviceThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                    'Thread pool that is in charge of processing proxy invocation')
+            .pc-form-grid-col-30
+                +number('Management:', model + '.managementThreadPoolSize', '"managementThreadPoolSize"', 'true', '4', '1',
+                    'Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs')
+            .pc-form-grid-col-30
+                +number('IGFS:', model + '.igfsThreadPoolSize', '"igfsThreadPoolSize"', 'true', 'availableProcessors', '1',
+                    'Thread pool that is in charge of processing outgoing IGFS messages')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-number({
+                    label: 'Rebalance:',
+                    model: `${model}.rebalanceThreadPoolSize`,
+                    name: '"rebalanceThreadPoolSize"',
+                    placeholder: '{{ ::$ctrl.Clusters.rebalanceThreadPoolSize.default }}',
+                    min: '{{ ::$ctrl.Clusters.rebalanceThreadPoolSize.min }}',
+                    max: `{{ $ctrl.Clusters.rebalanceThreadPoolSize.max(${model}) }}`,
+                    tip: 'Max count of threads can be used at rebalancing'
+                })
+                    +form-field-feedback('max', 'Rebalance thread pool size should not exceed or be equal to System thread pool size')
+            .pc-form-grid-col-30
+                +number('Utility cache:', model + '.utilityCacheThreadPoolSize', '"utilityCacheThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
+                    'Default thread pool size that will be used to process utility cache messages')
+            .pc-form-grid-col-30
+                pc-form-field-size(
+                    label='Utility cache keep alive time:'
+                    ng-model=`${model}.utilityCacheKeepAliveTime`
+                    name='utilityCacheKeepAliveTime'
+                    size-type='seconds'
+                    size-scale-label='s'
+                    tip='Keep alive time of thread pool size that will be used to process utility cache messages'
+                    min='0'
+                    placeholder='{{ 60000 / _s1.value }}'
+                    on-scale-change='_s1 = $event'
+                )
+            .pc-form-grid-col-30
+                +number('Async callback:', model + '.asyncCallbackPoolSize', '"asyncCallbackPoolSize"', 'true', 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing asynchronous callbacks')
+            .pc-form-grid-col-30
+                +number('Striped:', model + '.stripedPoolSize', '"stripedPoolSize"', 'true', 'max(8, availableProcessors)', '1',
+                    'Striped pool size that should be used for cache requests processing')
 
-                //- Since ignite 2.0
-                .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
-                    +number('Data streamer:', model + '.dataStreamerThreadPoolSize', '"dataStreamerThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing data stream messages')
-                .pc-form-grid-col-30
-                    +number('Query:', model + '.queryThreadPoolSize', '"queryThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
-                        'Size of thread pool that is in charge of processing query messages')
-                .pc-form-grid-col-60(ng-if-end)
-                    .ignite-form-field
-                        +ignite-form-field__label('Executor configurations:', '"executorConfigurations"')
-                            +tooltip(`Custom thread pool configurations for compute tasks`)
-                        .ignite-form-field__control
-                            list-editable(
-                                ng-model=executors
-                                ng-model-options='{allowInvalid: true}'
-                                name='executorConfigurations'
-                                ui-validate=`{
-                                    allNamesExist: '$ctrl.Clusters.executorConfigurations.allNamesExist($value)',
-                                    allNamesUnique: '$ctrl.Clusters.executorConfigurations.allNamesUnique($value)'
-                                }`
-                            )
-                                list-editable-item-view
-                                    | {{ $item.name }} / 
-                                    | {{ $item.size || 'max(8, availableProcessors)'}}
+            //- Since ignite 2.0
+            .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
+                +number('Data streamer:', model + '.dataStreamerThreadPoolSize', '"dataStreamerThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing data stream messages')
+            .pc-form-grid-col-30
+                +number('Query:', model + '.queryThreadPoolSize', '"queryThreadPoolSize"', 'true', 'max(8, availableProcessors)', '1',
+                    'Size of thread pool that is in charge of processing query messages')
+            .pc-form-grid-col-60(ng-if-end)
+                .ignite-form-field
+                    +ignite-form-field__label('Executor configurations:', '"executorConfigurations"')
+                        +tooltip(`Custom thread pool configurations for compute tasks`)
+                    .ignite-form-field__control
+                        list-editable(
+                            ng-model=executors
+                            ng-model-options='{allowInvalid: true}'
+                            name='executorConfigurations'
+                            ui-validate=`{
+                                allNamesExist: '$ctrl.Clusters.executorConfigurations.allNamesExist($value)',
+                                allNamesUnique: '$ctrl.Clusters.executorConfigurations.allNamesUnique($value)'
+                            }`
+                        )
+                            list-editable-item-view
+                                | {{ $item.name }} / 
+                                | {{ $item.size || 'max(8, availableProcessors)'}}
 
-                                list-editable-item-edit
-                                    .pc-form-grid-row
-                                        .pc-form-grid-col-30
-                                            +sane-ignite-form-field-text({
-                                                label: 'Name:',
-                                                model: '$item.name',
-                                                name: '"ExecutorName"',
-                                                required: true,
-                                                placeholder: 'Input executor name',
-                                                tip: 'Thread pool name'
-                                            })(
-                                                ui-validate=`{
-                                                    uniqueName: '$ctrl.Clusters.executorConfiguration.name.customValidators.uniqueName($item, ${executors})'
-                                                }`
-                                                ui-validate-watch=`"${executors}"`
-                                                ui-validate-watch-object-equality='true'
-                                                ng-model-options='{allowInvalid: true}'
-                                                data-ignite-form-field-input-autofocus='true'
-                                            )
-                                                +form-field-feedback(null, 'uniqueName', 'Service with that name is already configured')
-                                        .pc-form-grid-col-30
-                                            +number('Pool size:', '$item.size', '"ExecutorPoolSize"', 'true', 'max(8, availableProcessors)', '1', 'Thread pool size')
+                            list-editable-item-edit
+                                .pc-form-grid-row
+                                    .pc-form-grid-col-30
+                                        +sane-ignite-form-field-text({
+                                            label: 'Name:',
+                                            model: '$item.name',
+                                            name: '"ExecutorName"',
+                                            required: true,
+                                            placeholder: 'Input executor name',
+                                            tip: 'Thread pool name'
+                                        })(
+                                            ui-validate=`{
+                                                uniqueName: '$ctrl.Clusters.executorConfiguration.name.customValidators.uniqueName($item, ${executors})'
+                                            }`
+                                            ui-validate-watch=`"${executors}"`
+                                            ui-validate-watch-object-equality='true'
+                                            ng-model-options='{allowInvalid: true}'
+                                            data-ignite-form-field-input-autofocus='true'
+                                        )
+                                            +form-field-feedback(null, 'uniqueName', 'Service with that name is already configured')
+                                    .pc-form-grid-col-30
+                                        +number('Pool size:', '$item.size', '"ExecutorPoolSize"', 'true', 'max(8, availableProcessors)', '1', 'Thread pool size')
 
-                                list-editable-no-items
-                                    list-editable-add-item-button(
-                                        add-item=`$edit($ctrl.Clusters.addExecutorConfiguration(${model}))`
-                                        label-single='executor configuration'
-                                        label-multiple='executor configurations'
-                                    )
-                        .ignite-form-field__errors(
-                            ng-messages=`pools.executorConfigurations.$error`
-                            ng-show=`pools.executorConfigurations.$invalid`
-                        )
-                            +form-field-feedback(_, 'allNamesExist', 'All executor configurations should have a name')
-                            +form-field-feedback(_, 'allNamesUnique', 'All executor configurations should have a unique name')
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$edit($ctrl.Clusters.addExecutorConfiguration(${model}))`
+                                    label-single='executor configuration'
+                                    label-multiple='executor configurations'
+                                )
+                    .ignite-form-field__errors(
+                        ng-messages=`pools.executorConfigurations.$error`
+                        ng-show=`pools.executorConfigurations.$invalid`
+                    )
+                        +form-field-feedback(_, 'allNamesExist', 'All executor configurations should have a name')
+                        +form-field-feedback(_, 'allNamesUnique', 'All executor configurations should have a unique name')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterPools')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterPools')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/time.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/time.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/time.pug
index 61c9155..fa85a5d 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/time.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/time.pug
@@ -19,30 +19,26 @@ include /app/helpers/jade/mixins
 -var form = 'time'
 -var model = '$ctrl.clonedCluster'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Time configuration
-        .pca-panel-heading-description
-            | Time settings for CLOCK write ordering mode.
-    .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
-                //- Removed in ignite 2.0
-                .pc-form-grid-col-30(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
-                    +number('Samples size:', `${model}.clockSyncSamples`, '"clockSyncSamples"', 'true', '8', '0',
-                        'Number of samples used to synchronize clocks between different nodes<br/>\
-                        Clock synchronization is used for cache version assignment in CLOCK order mode')
-                .pc-form-grid-col-30(ng-if-end)
-                    +number('Frequency:', `${model}.clockSyncFrequency`, '"clockSyncFrequency"', 'true', '120000', '0',
-                        'Frequency at which clock is synchronized between nodes, in milliseconds<br/>\
-                        Clock synchronization is used for cache version assignment in CLOCK order mode')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Time configuration
+    panel-description Time settings for CLOCK write ordering mode.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            //- Removed in ignite 2.0
+            .pc-form-grid-col-30(ng-if-start='$ctrl.available(["1.0.0", "2.0.0"])')
+                +number('Samples size:', `${model}.clockSyncSamples`, '"clockSyncSamples"', 'true', '8', '0',
+                    'Number of samples used to synchronize clocks between different nodes<br/>\
+                    Clock synchronization is used for cache version assignment in CLOCK order mode')
+            .pc-form-grid-col-30(ng-if-end)
+                +number('Frequency:', `${model}.clockSyncFrequency`, '"clockSyncFrequency"', 'true', '120000', '0',
+                    'Frequency at which clock is synchronized between nodes, in milliseconds<br/>\
+                    Clock synchronization is used for cache version assignment in CLOCK order mode')
 
-                .pc-form-grid-col-30
-                    +number-min-max('Port base:', `${model}.timeServerPortBase`, '"timeServerPortBase"', 'true', '31100', '0', '65535',
-                        'Time server provides clock synchronization between nodes<br/>\
-                        Base UPD port number for grid time server. Time server will be started on one of free ports in range')
-                .pc-form-grid-col-30
-                    +number('Port range:', `${model}.timeServerPortRange`, '"timeServerPortRange"', 'true', '100', '1', 'Time server port range')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterTime')
+            .pc-form-grid-col-30
+                +number-min-max('Port base:', `${model}.timeServerPortBase`, '"timeServerPortBase"', 'true', '31100', '0', '65535',
+                    'Time server provides clock synchronization between nodes<br/>\
+                    Base UPD port number for grid time server. Time server will be started on one of free ports in range')
+            .pc-form-grid-col-30
+                +number('Port range:', `${model}.timeServerPortRange`, '"timeServerPortRange"', 'true', '100', '1', 'Time server port range')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterTime')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.pug b/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.pug
index c888174..b5f80df 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.pug
@@ -19,50 +19,47 @@ include /app/helpers/jade/mixins
 -var form = 'transactions'
 -var model = '$ctrl.clonedCluster.transactionConfiguration'
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Transactions
-        .pca-panel-heading-description
-            | Settings for transactions. 
-            | #[a.link-success(href="https://apacheignite.readme.io/docs/transactions" 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('Concurrency:', `${model}.defaultTxConcurrency`, '"defaultTxConcurrency"', 'true', 'PESSIMISTIC',
-                        '[\
-                            {value: "OPTIMISTIC", label: "OPTIMISTIC"},\
-                            {value: "PESSIMISTIC", label: "PESSIMISTIC"}\
-                        ]',
-                        'Cache transaction concurrency to use when one is not explicitly specified\
-                        <ul>\
-                            <li>OPTIMISTIC - All cache operations are not distributed to other nodes until commit is called</li>\
-                            <li>PESSIMISTIC - A lock is acquired on all cache operations with exception of read operations in READ_COMMITTED mode</li>\
-                        </ul>')
-                .pc-form-grid-col-30
-                    +dropdown('Isolation:', `${model}.defaultTxIsolation`, '"defaultTxIsolation"', 'true', 'REPEATABLE_READ',
-                        '[\
-                            {value: "READ_COMMITTED", label: "READ_COMMITTED"},\
-                            {value: "REPEATABLE_READ", label: "REPEATABLE_READ"},\
-                            {value: "SERIALIZABLE", label: "SERIALIZABLE"}\
-                        ]',
-                        'Default transaction isolation\
-                        <ul>\
-                            <li>READ_COMMITTED - Always a committed value will be provided for read operations</li>\
-                            <li>REPEATABLE_READ - If a value was read once within transaction, then all consecutive reads will provide the same in-transaction value</li>\
-                            <li>SERIALIZABLE - All transactions occur in a completely isolated fashion, as if all transactions in the system had executed serially, one after the other.</li>\
-                        </ul>')
-                .pc-form-grid-col-60
-                    +number('Default timeout:', `${model}.defaultTxTimeout`, '"defaultTxTimeout"', 'true', '0', '0', 'Default transaction timeout')
-                .pc-form-grid-col-30
-                    +number('Pessimistic log cleanup delay:', `${model}.pessimisticTxLogLinger`, '"pessimisticTxLogLinger"', 'true', '10000', '0',
-                        'Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node')
-                .pc-form-grid-col-30
-                    +number('Pessimistic log size:', `${model}.pessimisticTxLogSize`, '"pessimisticTxLogSize"', 'true', '0', '0',
-                        'Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes')
-                .pc-form-grid-col-60
-                    +java-class('Manager factory:', `${model}.txManagerFactory`, '"txManagerFactory"', 'true', 'false',
-                        'Class name of transaction manager factory for integration with JEE app servers')
-            .pca-form-column-6
-                +preview-xml-java(model, 'clusterTransactions')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title Transactions
+    panel-description 
+        | Settings for transactions. 
+        | #[a.link-success(href="https://apacheignite.readme.io/docs/transactions" target="_blank") More info]
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +dropdown('Concurrency:', `${model}.defaultTxConcurrency`, '"defaultTxConcurrency"', 'true', 'PESSIMISTIC',
+                    '[\
+                        {value: "OPTIMISTIC", label: "OPTIMISTIC"},\
+                        {value: "PESSIMISTIC", label: "PESSIMISTIC"}\
+                    ]',
+                    'Cache transaction concurrency to use when one is not explicitly specified\
+                    <ul>\
+                        <li>OPTIMISTIC - All cache operations are not distributed to other nodes until commit is called</li>\
+                        <li>PESSIMISTIC - A lock is acquired on all cache operations with exception of read operations in READ_COMMITTED mode</li>\
+                    </ul>')
+            .pc-form-grid-col-30
+                +dropdown('Isolation:', `${model}.defaultTxIsolation`, '"defaultTxIsolation"', 'true', 'REPEATABLE_READ',
+                    '[\
+                        {value: "READ_COMMITTED", label: "READ_COMMITTED"},\
+                        {value: "REPEATABLE_READ", label: "REPEATABLE_READ"},\
+                        {value: "SERIALIZABLE", label: "SERIALIZABLE"}\
+                    ]',
+                    'Default transaction isolation\
+                    <ul>\
+                        <li>READ_COMMITTED - Always a committed value will be provided for read operations</li>\
+                        <li>REPEATABLE_READ - If a value was read once within transaction, then all consecutive reads will provide the same in-transaction value</li>\
+                        <li>SERIALIZABLE - All transactions occur in a completely isolated fashion, as if all transactions in the system had executed serially, one after the other.</li>\
+                    </ul>')
+            .pc-form-grid-col-60
+                +number('Default timeout:', `${model}.defaultTxTimeout`, '"defaultTxTimeout"', 'true', '0', '0', 'Default transaction timeout')
+            .pc-form-grid-col-30
+                +number('Pessimistic log cleanup delay:', `${model}.pessimisticTxLogLinger`, '"pessimisticTxLogLinger"', 'true', '10000', '0',
+                    'Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node')
+            .pc-form-grid-col-30
+                +number('Pessimistic log size:', `${model}.pessimisticTxLogSize`, '"pessimisticTxLogSize"', 'true', '0', '0',
+                    'Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes')
+            .pc-form-grid-col-60
+                +java-class('Manager factory:', `${model}.txManagerFactory`, '"txManagerFactory"', 'true', 'false',
+                    'Class name of transaction manager factory for integration with JEE app servers')
+        .pca-form-column-6
+            +preview-xml-java(model, 'clusterTransactions')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/domains/general.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/general.pug b/modules/web-console/frontend/app/modules/states/configuration/domains/general.pug
index 0238972..a6c8194 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/domains/general.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/general.pug
@@ -20,41 +20,38 @@ include /app/helpers/jade/mixins
 -var model = 'backupItem'
 -var generatePojo = `${model}.generatePojo`
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title General
-        .pca-panel-heading-description
-            | Domain model properties common for Query and Store. 
-            a.link-success(href="https://apacheignite.readme.io/docs/cache-queries" target="_blank") More info about query configuration. 
-            a.link-success(href="https://apacheignite.readme.io/docs/3rd-party-store" target="_blank") More info about store.
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .pc-form-grid-col-60
-                    +checkbox('Generate POJO classes', generatePojo, '"generatePojo"', 'If selected then POJO classes will be generated from database tables')
-                .pc-form-grid-col-30
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Caches:',
-                        model: `${model}.caches`,
-                        name: '"caches"',
-                        multiple: true,
-                        placeholder: 'Choose caches',
-                        placeholderEmpty: 'No valid caches configured',
-                        options: '$ctrl.cachesMenu',
-                        tip: 'Select caches to describe types in cache'
-                    })
-                .pc-form-grid-col-30
-                    +dropdown-required('Query metadata:', `${model}.queryMetadata`, '"queryMetadata"', 'true', 'true', '', '::$ctrl.Models.queryMetadata.values',
-                        'Query metadata configured with:\
-                        <ul>\
-                            <li>Java annotations like @QuerySqlField</li>\
-                            <li>Configuration via QueryEntity class</li>\
-                        </ul>')
-                .pc-form-grid-col-60
-                    +java-class-typeahead('Key type:', `${model}.keyType`, '"keyType"', '$ctrl.javaBuiltInClassesBase', 'true', 'true', '{{ ' + generatePojo + ' ? "Full class name for Key" : "Key type name" }}', 'Key class used to store key in cache', generatePojo)
-                .pc-form-grid-col-60
-                    +java-class-autofocus-placholder('Value type:', `${model}.valueType`, '"valueType"', 'true', 'true', 'false', '{{ ' + generatePojo +' ? "Enter fully qualified class name" : "Value type name" }}', 'Value class used to store value in cache', generatePojo)
+panel-collapsible(opened=`::true` ng-form=form)
+    panel-title General
+    panel-description
+        | Domain model properties common for Query and Store. 
+        a.link-success(href="https://apacheignite.readme.io/docs/cache-queries" target="_blank") More info about query configuration. 
+        a.link-success(href="https://apacheignite.readme.io/docs/3rd-party-store" target="_blank") More info about store.
+    panel-content.pca-form-row
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-60
+                +checkbox('Generate POJO classes', generatePojo, '"generatePojo"', 'If selected then POJO classes will be generated from database tables')
+            .pc-form-grid-col-30
+                +sane-ignite-form-field-dropdown({
+                    label: 'Caches:',
+                    model: `${model}.caches`,
+                    name: '"caches"',
+                    multiple: true,
+                    placeholder: 'Choose caches',
+                    placeholderEmpty: 'No valid caches configured',
+                    options: '$ctrl.cachesMenu',
+                    tip: 'Select caches to describe types in cache'
+                })
+            .pc-form-grid-col-30
+                +dropdown-required('Query metadata:', `${model}.queryMetadata`, '"queryMetadata"', 'true', 'true', '', '::$ctrl.Models.queryMetadata.values',
+                    'Query metadata configured with:\
+                    <ul>\
+                        <li>Java annotations like @QuerySqlField</li>\
+                        <li>Configuration via QueryEntity class</li>\
+                    </ul>')
+            .pc-form-grid-col-60
+                +java-class-typeahead('Key type:', `${model}.keyType`, '"keyType"', '$ctrl.javaBuiltInClassesBase', 'true', 'true', '{{ ' + generatePojo + ' ? "Full class name for Key" : "Key type name" }}', 'Key class used to store key in cache', generatePojo)
+            .pc-form-grid-col-60
+                +java-class-autofocus-placholder('Value type:', `${model}.valueType`, '"valueType"', 'true', 'true', 'false', '{{ ' + generatePojo +' ? "Enter fully qualified class name" : "Value type name" }}', 'Value class used to store value in cache', generatePojo)
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'domainModelGeneral')
+        .pca-form-column-6
+            +preview-xml-java(model, 'domainModelGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/domains/query.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/query.pug b/modules/web-console/frontend/app/modules/states/configuration/domains/query.pug
index 9dc513a..ed91ec4 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/domains/query.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/query.pug
@@ -23,236 +23,233 @@ include /app/helpers/jade/mixins
 -var queryAliases = `${model}.aliases`
 -var queryIndexes = `${model}.indexes`
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title(id='query-title') Domain model for SQL query
-        .pca-panel-heading-description
-            | Domain model properties for fields queries. 
-            a.link-success(href='https://apacheignite.readme.io/docs/cache-queries' target='_blank') More info
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id='query')
-        .pca-panel-body.pca-form-row
-            .pca-form-column-6.pc-form-grid-row
-                .content-not-available(
-                    ng-if=`${model}.queryMetadata === 'Annotations'`
-                    style='margin-top: 10px'
-                )
-                    label Not available for annotated types
-
-                .pc-form-grid-col-60(ng-if-start=`${model}.queryMetadata === 'Configuration'`)
-                    +text('Table name:', `${model}.tableName`, '"tableName"', 'false', 'Enter table name')
-
-                .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
-                    +text('Key field name:', `${model}.keyFieldName`, '"keyFieldName"', 'false', 'Enter key field name',
-                        'Key name.<br/>' +
-                        'Can be used in field list to denote the key as a whole')
-                .pc-form-grid-col-30(ng-if-end)
-                    +text('Value field name:', `${model}.valueFieldName`, '"valueFieldName"', 'false', 'Enter value field name',
-                        'Value name.<br/>' +
-                        'Can be used in field list to denote the entire value')
-
-                .pc-form-grid-col-60
-                    mixin domains-query-fields
-                        .ignite-form-field
-                            +ignite-form-field__label('Fields:', '"fields"')
-                                +tooltip(`Collection of name-to-type mappings to be queried, in addition to indexed fields`)
-                            .ignite-form-field__control
-                                -let items = queryFields
-                                list-editable(
-                                    ng-model=items
-                                    name='queryFields'
-                                    ng-change=`$ctrl.onQueryFieldsChange(${model})`
-                                )
-                                    list-editable-item-view
-                                        | {{ $item.name}} / {{ $item.className}}
-
-                                    list-editable-item-edit
-                                        - form = '$parent.form'
-                                        .pc-form-grid-row
-                                            .pc-form-grid-col-30(divider='/')
-                                                +ignite-form-field-text('Field name:', '$item.name', '"name"', false, true, 'Enter field name')(
-                                                    data-ignite-unique=items
-                                                    data-ignite-unique-property='name'
-                                                    ignite-auto-focus
-                                                )
-                                                    +unique-feedback('"name"', 'Property with such name already exists!')
-                                            .pc-form-grid-col-30
-                                                +java-class-typeahead('Field full class name:', `$item.className`, '"className"', '$ctrl.queryFieldTypes', true, true, 'Enter field full class name')(
-                                                    ng-model-options='{allowInvalid: true}'
-                                                    extra-valid-java-identifiers='$ctrl.queryFieldTypes'
-                                                )
-
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${items} = ${items} || []).push({}))`
-                                            label-single='field to query'
-                                            label-multiple='fields'
-                                        )
-
-                    +domains-query-fields
-
-                .pc-form-grid-col-60
-                    +sane-ignite-form-field-dropdown({
-                        label: 'Key fields:',
-                        model: queryKeyFields,
-                        name: '"queryKeyFields"',
-                        multiple: true,
-                        placeholder: 'Select key fields',
-                        placeholderEmpty: 'Configure available fields',
-                        options: `$ctrl.fields('cur', ${queryKeyFields})`,
-                        tip: 'Query fields that belongs to the key.<br/>\
-                         Used to build / modify keys and values during SQL DML operations when no key - value classes are present on cluster nodes.'
-                    })
-                .pc-form-grid-col-60
-                    mixin domains-query-aliases
-                        .ignite-form-field
-                            +ignite-form-field__label('Aliases:', '"aliases"')
-                                +tooltip(`Mapping from full property name in dot notation to an alias that will be used as SQL column name<br />
-                                    For example: "parent.name" as "parentName"`)
-                            .ignite-form-field__control
-                                -let items = queryAliases
-
-                                list-editable(ng-model=items name='queryAliases')
-                                    list-editable-item-view
-                                        | {{ $item.field }} &rarr; {{ $item.alias }}
-
-                                    list-editable-item-edit
-                                        - form = '$parent.form'
-                                        .pc-form-grid-row
-                                            .pc-form-grid-col-30(divider='/')
-                                                +ignite-form-field-text('Field name', '$item.field', '"field"', false, true, 'Enter field name')(
-                                                    data-ignite-unique=items
-                                                    data-ignite-unique-property='field'
-                                                    ignite-auto-focus
-                                                )
-                                                    +unique-feedback('"field"', 'Such field already exists!')
-                                            .pc-form-grid-col-30
-                                                +ignite-form-field-text('Field alias', '$item.alias', '"alias"', false, true, 'Enter field alias')
-
-                                    list-editable-no-items
-                                        list-editable-add-item-button(
-                                            add-item=`$editLast((${items} = ${items} || []).push({}))`
-                                            label-single='alias to query'
-                                            label-multiple='aliases'
-                                        )
-
-                    +domains-query-aliases
-
-                .pc-form-grid-col-60(ng-if-end)
+panel-collapsible(ng-form=form opened=`!!${model}.queryMetadata`)
+    panel-title#query-title Domain model for SQL query
+    panel-description
+        | Domain model properties for fields queries. 
+        a.link-success(href='https://apacheignite.readme.io/docs/cache-queries' target='_blank') More info
+    panel-content.pca-form-row
+        .pca-form-column-6.pc-form-grid-row
+            .content-not-available(
+                ng-if=`${model}.queryMetadata === 'Annotations'`
+                style='margin-top: 10px'
+            )
+                label Not available for annotated types
+
+            .pc-form-grid-col-60(ng-if-start=`${model}.queryMetadata === 'Configuration'`)
+                +text('Table name:', `${model}.tableName`, '"tableName"', 'false', 'Enter table name')
+
+            .pc-form-grid-col-30(ng-if-start='$ctrl.available("2.0.0")')
+                +text('Key field name:', `${model}.keyFieldName`, '"keyFieldName"', 'false', 'Enter key field name',
+                    'Key name.<br/>' +
+                    'Can be used in field list to denote the key as a whole')
+            .pc-form-grid-col-30(ng-if-end)
+                +text('Value field name:', `${model}.valueFieldName`, '"valueFieldName"', 'false', 'Enter value field name',
+                    'Value name.<br/>' +
+                    'Can be used in field list to denote the entire value')
+
+            .pc-form-grid-col-60
+                mixin domains-query-fields
                     .ignite-form-field
-                        +ignite-form-field__label('Indexes:', '"indexes"')
+                        +ignite-form-field__label('Fields:', '"fields"')
+                            +tooltip(`Collection of name-to-type mappings to be queried, in addition to indexed fields`)
                         .ignite-form-field__control
+                            -let items = queryFields
                             list-editable(
-                                ng-model=queryIndexes
-                                ng-model-options='{allowInvalid: true}'
-                                name='queryIndexes'
-                                ui-validate=`{
-                                    complete: '$ctrl.Models.queryIndexes.complete($value)',
-                                    fieldsExist: '$ctrl.Models.queryIndexes.fieldsExist($value, ${queryFields})',
-                                    indexFieldsHaveUniqueNames: '$ctrl.Models.queryIndexes.indexFieldsHaveUniqueNames($value)'
-                                }`
-                                ui-validate-watch=`"[${queryIndexes}, ${queryFields}]"`
-                                ui-validate-watch-object-equality='true'
+                                ng-model=items
+                                name='queryFields'
+                                ng-change=`$ctrl.onQueryFieldsChange(${model})`
                             )
-                                list-editable-item-view(item-name='queryIndex')
-                                    div {{ queryIndex.name }} [{{ queryIndex.indexType }}]
-                                    div(ng-repeat='field in queryIndex.fields track by field._id')
-                                        span {{ field.name }}
-                                        span(ng-if='queryIndex.indexType == "SORTED"')
-                                            |  / {{ field.direction ? 'ASC' : 'DESC'}}
+                                list-editable-item-view
+                                    | {{ $item.name}} / {{ $item.className}}
 
-                                list-editable-item-edit(item-name='queryIndex')
+                                list-editable-item-edit
+                                    - form = '$parent.form'
                                     .pc-form-grid-row
                                         .pc-form-grid-col-30(divider='/')
-                                            +sane-ignite-form-field-text({
-                                                label: 'Index name:',
-                                                model: 'queryIndex.name',
-                                                name: '"name"',
-                                                required: true,
-                                                placeholder: 'Enter index name'
-                                            })(
-                                                ignite-unique=queryIndexes
-                                                ignite-unique-property='name'
-                                                ignite-form-field-input-autofocus='true'
+                                            +ignite-form-field-text('Field name:', '$item.name', '"name"', false, true, 'Enter field name')(
+                                                data-ignite-unique=items
+                                                data-ignite-unique-property='name'
+                                                ignite-auto-focus
                                             )
-                                                +unique-feedback(_, 'Such index already exists!')
+                                                +unique-feedback('"name"', 'Property with such name already exists!')
                                         .pc-form-grid-col-30
-                                            +sane-ignite-form-field-dropdown({
-                                                label: 'Index type:',
-                                                model: `queryIndex.indexType`,
-                                                name: '"indexType"',
-                                                required: true,
-                                                placeholder: 'Select index type',
-                                                options: '::$ctrl.Models.indexType.values'
-                                            })
-                                        .pc-form-grid-col-60
-                                            .ignite-form-field
-                                                +ignite-form-field__label('Index fields:', '"indexFields"', true)
-                                                .ignite-form-field__control
-                                                    list-editable(
-                                                        ng-model='queryIndex.fields'
-                                                        ng-model-options='{allowInvalid: true}'
-                                                        name='indexFields'
-                                                        ng-required='true'
-                                                    )
-                                                        list-editable-item-view(item-name='indexField')
-                                                            | {{ indexField.name }} 
-                                                            span(ng-if='queryIndex.indexType === "SORTED"')
-                                                                |  / {{ indexField.direction ? "ASC" : "DESC" }}
-
-                                                        list-editable-item-edit(item-name='indexField')
-                                                            .pc-form-grid-row
-                                                                .pc-form-grid-col-60
-                                                                    +sane-ignite-form-field-dropdown({
-                                                                        label: 'Index field:',
-                                                                        model: 'indexField.name',
-                                                                        name: '"indexName"',
-                                                                        placeholder: `{{ ${queryFields}.length > 0 ? 'Choose index field' : 'No fields configured' }}`,
-                                                                        options: queryFields
-                                                                    })(
-                                                                        bs-options=`queryField.name as queryField.name for queryField in ${queryFields}`
-                                                                        ng-disabled=`${queryFields}.length === 0`
-                                                                        ng-model-options='{allowInvalid: true}'
-                                                                        ignite-unique='queryIndex.fields'
-                                                                        ignite-unique-property='name'
-                                                                        ignite-auto-focus
-                                                                    )
-                                                                        +unique-feedback(_, 'Such field already exists!')
-                                                                .pc-form-grid-col-60(
-                                                                    ng-if='queryIndex.indexType === "SORTED"'
-                                                                )
-                                                                    +sane-ignite-form-field-dropdown({
-                                                                        label: 'Sort direction:',
-                                                                        model: 'indexField.direction',
-                                                                        name: '"indexDirection"',
-                                                                        required: true,
-                                                                        options: '::$ctrl.Models.indexSortDirection.values'
-                                                                    })
-                                                        list-editable-no-items
-                                                            list-editable-add-item-button(
-                                                                add-item=`$edit($ctrl.Models.addIndexField(queryIndex.fields))`
-                                                                label-single='field to index'
-                                                                label-multiple='fields in index'
-                                                            )
-                                                .ignite-form-field__errors(
-                                                    ng-messages=`$form.indexFields.$error`
-                                                    ng-show=`$form.indexFields.$invalid`
-                                                )
-                                                    +form-field-feedback(_, 'required', 'Index fields should be configured')
+                                            +java-class-typeahead('Field full class name:', `$item.className`, '"className"', '$ctrl.queryFieldTypes', true, true, 'Enter field full class name')(
+                                                ng-model-options='{allowInvalid: true}'
+                                                extra-valid-java-identifiers='$ctrl.queryFieldTypes'
+                                            )
 
                                 list-editable-no-items
                                     list-editable-add-item-button(
-                                        add-item=`$edit($ctrl.Models.addIndex(${model}))`
-                                        label-single='index'
+                                        add-item=`$editLast((${items} = ${items} || []).push({}))`
+                                        label-single='field to query'
                                         label-multiple='fields'
                                     )
-                        .ignite-form-field__errors(
-                            ng-messages=`query.queryIndexes.$error`
-                            ng-show=`query.queryIndexes.$invalid`
+
+                +domains-query-fields
+
+            .pc-form-grid-col-60
+                +sane-ignite-form-field-dropdown({
+                    label: 'Key fields:',
+                    model: queryKeyFields,
+                    name: '"queryKeyFields"',
+                    multiple: true,
+                    placeholder: 'Select key fields',
+                    placeholderEmpty: 'Configure available fields',
+                    options: `$ctrl.fields('cur', ${queryKeyFields})`,
+                    tip: 'Query fields that belongs to the key.<br/>\
+                     Used to build / modify keys and values during SQL DML operations when no key - value classes are present on cluster nodes.'
+                })
+            .pc-form-grid-col-60
+                mixin domains-query-aliases
+                    .ignite-form-field
+                        +ignite-form-field__label('Aliases:', '"aliases"')
+                            +tooltip(`Mapping from full property name in dot notation to an alias that will be used as SQL column name<br />
+                                For example: "parent.name" as "parentName"`)
+                        .ignite-form-field__control
+                            -let items = queryAliases
+
+                            list-editable(ng-model=items name='queryAliases')
+                                list-editable-item-view
+                                    | {{ $item.field }} &rarr; {{ $item.alias }}
+
+                                list-editable-item-edit
+                                    - form = '$parent.form'
+                                    .pc-form-grid-row
+                                        .pc-form-grid-col-30(divider='/')
+                                            +ignite-form-field-text('Field name', '$item.field', '"field"', false, true, 'Enter field name')(
+                                                data-ignite-unique=items
+                                                data-ignite-unique-property='field'
+                                                ignite-auto-focus
+                                            )
+                                                +unique-feedback('"field"', 'Such field already exists!')
+                                        .pc-form-grid-col-30
+                                            +ignite-form-field-text('Field alias', '$item.alias', '"alias"', false, true, 'Enter field alias')
+
+                                list-editable-no-items
+                                    list-editable-add-item-button(
+                                        add-item=`$editLast((${items} = ${items} || []).push({}))`
+                                        label-single='alias to query'
+                                        label-multiple='aliases'
+                                    )
+
+                +domains-query-aliases
+
+            .pc-form-grid-col-60(ng-if-end)
+                .ignite-form-field
+                    +ignite-form-field__label('Indexes:', '"indexes"')
+                    .ignite-form-field__control
+                        list-editable(
+                            ng-model=queryIndexes
+                            ng-model-options='{allowInvalid: true}'
+                            name='queryIndexes'
+                            ui-validate=`{
+                                complete: '$ctrl.Models.queryIndexes.complete($value)',
+                                fieldsExist: '$ctrl.Models.queryIndexes.fieldsExist($value, ${queryFields})',
+                                indexFieldsHaveUniqueNames: '$ctrl.Models.queryIndexes.indexFieldsHaveUniqueNames($value)'
+                            }`
+                            ui-validate-watch=`"[${queryIndexes}, ${queryFields}]"`
+                            ui-validate-watch-object-equality='true'
                         )
-                            +form-field-feedback(_, 'complete', 'Some indexes are incomplete')
-                            +form-field-feedback(_, 'fieldsExist', 'Some indexes use unknown fields')
-                            +form-field-feedback(_, 'indexFieldsHaveUniqueNames', 'Each query index field name should be unique')
+                            list-editable-item-view(item-name='queryIndex')
+                                div {{ queryIndex.name }} [{{ queryIndex.indexType }}]
+                                div(ng-repeat='field in queryIndex.fields track by field._id')
+                                    span {{ field.name }}
+                                    span(ng-if='queryIndex.indexType == "SORTED"')
+                                        |  / {{ field.direction ? 'ASC' : 'DESC'}}
+
+                            list-editable-item-edit(item-name='queryIndex')
+                                .pc-form-grid-row
+                                    .pc-form-grid-col-30(divider='/')
+                                        +sane-ignite-form-field-text({
+                                            label: 'Index name:',
+                                            model: 'queryIndex.name',
+                                            name: '"name"',
+                                            required: true,
+                                            placeholder: 'Enter index name'
+                                        })(
+                                            ignite-unique=queryIndexes
+                                            ignite-unique-property='name'
+                                            ignite-form-field-input-autofocus='true'
+                                        )
+                                            +unique-feedback(_, 'Such index already exists!')
+                                    .pc-form-grid-col-30
+                                        +sane-ignite-form-field-dropdown({
+                                            label: 'Index type:',
+                                            model: `queryIndex.indexType`,
+                                            name: '"indexType"',
+                                            required: true,
+                                            placeholder: 'Select index type',
+                                            options: '::$ctrl.Models.indexType.values'
+                                        })
+                                    .pc-form-grid-col-60
+                                        .ignite-form-field
+                                            +ignite-form-field__label('Index fields:', '"indexFields"', true)
+                                            .ignite-form-field__control
+                                                list-editable(
+                                                    ng-model='queryIndex.fields'
+                                                    ng-model-options='{allowInvalid: true}'
+                                                    name='indexFields'
+                                                    ng-required='true'
+                                                )
+                                                    list-editable-item-view(item-name='indexField')
+                                                        | {{ indexField.name }} 
+                                                        span(ng-if='queryIndex.indexType === "SORTED"')
+                                                            |  / {{ indexField.direction ? "ASC" : "DESC" }}
+
+                                                    list-editable-item-edit(item-name='indexField')
+                                                        .pc-form-grid-row
+                                                            .pc-form-grid-col-60
+                                                                +sane-ignite-form-field-dropdown({
+                                                                    label: 'Index field:',
+                                                                    model: 'indexField.name',
+                                                                    name: '"indexName"',
+                                                                    placeholder: `{{ ${queryFields}.length > 0 ? 'Choose index field' : 'No fields configured' }}`,
+                                                                    options: queryFields
+                                                                })(
+                                                                    bs-options=`queryField.name as queryField.name for queryField in ${queryFields}`
+                                                                    ng-disabled=`${queryFields}.length === 0`
+                                                                    ng-model-options='{allowInvalid: true}'
+                                                                    ignite-unique='queryIndex.fields'
+                                                                    ignite-unique-property='name'
+                                                                    ignite-auto-focus
+                                                                )
+                                                                    +unique-feedback(_, 'Such field already exists!')
+                                                            .pc-form-grid-col-60(
+                                                                ng-if='queryIndex.indexType === "SORTED"'
+                                                            )
+                                                                +sane-ignite-form-field-dropdown({
+                                                                    label: 'Sort direction:',
+                                                                    model: 'indexField.direction',
+                                                                    name: '"indexDirection"',
+                                                                    required: true,
+                                                                    options: '::$ctrl.Models.indexSortDirection.values'
+                                                                })
+                                                    list-editable-no-items
+                                                        list-editable-add-item-button(
+                                                            add-item=`$edit($ctrl.Models.addIndexField(queryIndex.fields))`
+                                                            label-single='field to index'
+                                                            label-multiple='fields in index'
+                                                        )
+                                            .ignite-form-field__errors(
+                                                ng-messages=`$form.indexFields.$error`
+                                                ng-show=`$form.indexFields.$invalid`
+                                            )
+                                                +form-field-feedback(_, 'required', 'Index fields should be configured')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'domainModelQuery')
+                            list-editable-no-items
+                                list-editable-add-item-button(
+                                    add-item=`$edit($ctrl.Models.addIndex(${model}))`
+                                    label-single='index'
+                                    label-multiple='fields'
+                                )
+                    .ignite-form-field__errors(
+                        ng-messages=`query.queryIndexes.$error`
+                        ng-show=`query.queryIndexes.$invalid`
+                    )
+                        +form-field-feedback(_, 'complete', 'Some indexes are incomplete')
+                        +form-field-feedback(_, 'fieldsExist', 'Some indexes use unknown fields')
+                        +form-field-feedback(_, 'indexFieldsHaveUniqueNames', 'Each query index field name should be unique')
+
+        .pca-form-column-6
+            +preview-xml-java(model, 'domainModelQuery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/domains/store.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/store.pug b/modules/web-console/frontend/app/modules/states/configuration/domains/store.pug
index eb0f9b7..811c0d7 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/domains/store.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/store.pug
@@ -75,52 +75,49 @@ mixin list-db-field-edit({ items, itemName, itemsName })
                 label-multiple=itemsName
             )
 
-.pca-panel.pca-panel-default(ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title(id='store-title') Domain model for cache store
-        .pca-panel-heading-description
-            | Domain model properties for binding database with cache via POJO cache store. 
-            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
-                .pc-form-grid-col-30
-                    +text('Database schema:', model + '.databaseSchema', '"databaseSchema"', 'false', 'Input DB schema name', 'Schema name in database')
-                .pc-form-grid-col-30
-                    +text('Database table:', model + '.databaseTable', '"databaseTable"', 'false', 'Input DB table name', 'Table name in database')
-                .pc-form-grid-col-60
-                    .ignite-form-field
-                        +ignite-form-field__label('Key fields:', '"keyFields"')
-                            +tooltip(`Collection of key fields descriptions for CacheJdbcPojoStore`)
-                        .ignite-form-field__control
-                            +list-db-field-edit({
-                                items: keyFields,
-                                itemName: 'key field',
-                                itemsName: 'key fields'
-                            })(name='keyFields')
-                        .ignite-form-field__errors(
-                            ng-messages=`store.keyFields.$error`
-                            ng-show=`store.keyFields.$invalid`
-                        )
-                            +form-field-feedback(_, 'dbFieldUnique', 'Each key field DB name and Java name should be unique')
+panel-collapsible(ng-form=form on-open=`ui.loadPanel('${form}')`)
+    panel-title#store-title Domain model for cache store
+    panel-description
+        | Domain model properties for binding database with cache via POJO cache store. 
+        a.link-success(href="https://apacheignite.readme.io/docs/3rd-party-store" target="_blank") More info
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6.pc-form-grid-row
+            .pc-form-grid-col-30
+                +text('Database schema:', model + '.databaseSchema', '"databaseSchema"', 'false', 'Input DB schema name', 'Schema name in database')
+            .pc-form-grid-col-30
+                +text('Database table:', model + '.databaseTable', '"databaseTable"', 'false', 'Input DB table name', 'Table name in database')
+            .pc-form-grid-col-60
+                .ignite-form-field
+                    +ignite-form-field__label('Key fields:', '"keyFields"')
+                        +tooltip(`Collection of key fields descriptions for CacheJdbcPojoStore`)
+                    .ignite-form-field__control
+                        +list-db-field-edit({
+                            items: keyFields,
+                            itemName: 'key field',
+                            itemsName: 'key fields'
+                        })(name='keyFields')
+                    .ignite-form-field__errors(
+                        ng-messages=`store.keyFields.$error`
+                        ng-show=`store.keyFields.$invalid`
+                    )
+                        +form-field-feedback(_, 'dbFieldUnique', 'Each key field DB name and Java name should be unique')
 
-                .pc-form-grid-col-60
-                    .ignite-form-field
-                        +ignite-form-field__label('Value fields:', '"valueFields"')
-                            +tooltip(`Collection of value fields descriptions for CacheJdbcPojoStore`)
-                        .ignite-form-field__control
-                            +list-db-field-edit({
-                                items: valueFields,
-                                itemName: 'value field',
-                                itemsName: 'value fields'
-                            })(name='valueFields')
-                        .ignite-form-field__errors(
-                            ng-messages=`store.valueFields.$error`
-                            ng-show=`store.valueFields.$invalid`
-                        )
-                            +form-field-feedback(_, 'dbFieldUnique', 'Each value field DB name and Java name should be unique')
+            .pc-form-grid-col-60
+                .ignite-form-field
+                    +ignite-form-field__label('Value fields:', '"valueFields"')
+                        +tooltip(`Collection of value fields descriptions for CacheJdbcPojoStore`)
+                    .ignite-form-field__control
+                        +list-db-field-edit({
+                            items: valueFields,
+                            itemName: 'value field',
+                            itemsName: 'value fields'
+                        })(name='valueFields')
+                    .ignite-form-field__errors(
+                        ng-messages=`store.valueFields.$error`
+                        ng-show=`store.valueFields.$invalid`
+                    )
+                        +form-field-feedback(_, 'dbFieldUnique', 'Each value field DB name and Java name should be unique')
 
-            .pca-form-column-6
-                +preview-xml-java(model, 'domainStore')
+        .pca-form-column-6
+            +preview-xml-java(model, 'domainStore')
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/d24dab81/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.pug b/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.pug
index b05caab..67a37ad 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.pug
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.pug
@@ -19,23 +19,24 @@ include /app/helpers/jade/mixins
 -var form = 'dualMode'
 -var model = 'backupItem'
 
-.pca-panel.pca-panel-default(ng-show='$ctrl.available(["1.0.0", "2.0.0"])' ng-form=form novalidate)
-    .pca-panel-heading(bs-collapse-toggle='' ng-click=`ui.loadPanel('${form}')`)
-        ignite-form-panel-chevron
-        .pca-panel-heading-title Dual mode
-        .pca-panel-heading-description
-            | IGFS supports dual-mode that allows it to work as either a standalone file system in Hadoop cluster, or work in tandem with HDFS, providing a primary caching layer for the secondary HDFS.
-            | As a caching layer it provides highly configurable read-through and write-through behaviour.
-    .pca-panel-collapse(role='tabpanel' bs-collapse-target id=`${form}`)
-        .pca-panel-body.pca-form-row(ng-if=`$ctrl.available(["1.0.0", "2.0.0"]) && ui.isPanelLoaded('${form}')`)
-            .pca-form-column-6
-                .settings-row
-                    +number('Maximum pending puts size:', `${model}.dualModeMaxPendingPutsSize`, '"dualModeMaxPendingPutsSize"', 'true', '0', 'Number.MIN_SAFE_INTEGER',
-                        'Maximum amount of pending data read from the secondary file system and waiting to be written to data cache<br/>\
-                        Zero or negative value stands for unlimited size')
-                .settings-row
-                    +java-class('Put executor service:', `${model}.dualModePutExecutorService`, '"dualModePutExecutorService"', 'true', 'false', 'DUAL mode put operation executor service')
-                .settings-row
-                    +checkbox('Put executor service shutdown', `${model}.dualModePutExecutorServiceShutdown`, '"dualModePutExecutorServiceShutdown"', 'DUAL mode put operation executor service shutdown flag')
-            .pca-form-column-6
-                +preview-xml-java(model, 'igfsDualMode')
+panel-collapsible(
+    ng-form=form
+    on-open=`ui.loadPanel('${form}')`
+    ng-if='$ctrl.available(["1.0.0", "2.0.0"])'
+)
+    panel-title Dual mode
+    panel-description
+        | IGFS supports dual-mode that allows it to work as either a standalone file system in Hadoop cluster, or work in tandem with HDFS, providing a primary caching layer for the secondary HDFS.
+        | As a caching layer it provides highly configurable read-through and write-through behaviour.
+    panel-content.pca-form-row(ng-if=`ui.isPanelLoaded('${form}')`)
+        .pca-form-column-6
+            .settings-row
+                +number('Maximum pending puts size:', `${model}.dualModeMaxPendingPutsSize`, '"dualModeMaxPendingPutsSize"', 'true', '0', 'Number.MIN_SAFE_INTEGER',
+                    'Maximum amount of pending data read from the secondary file system and waiting to be written to data cache<br/>\
+                    Zero or negative value stands for unlimited size')
+            .settings-row
+                +java-class('Put executor service:', `${model}.dualModePutExecutorService`, '"dualModePutExecutorService"', 'true', 'false', 'DUAL mode put operation executor service')
+            .settings-row
+                +checkbox('Put executor service shutdown', `${model}.dualModePutExecutorServiceShutdown`, '"dualModePutExecutorServiceShutdown"', 'DUAL mode put operation executor service shutdown flag')
+        .pca-form-column-6
+            +preview-xml-java(model, 'igfsDualMode')