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

[04/50] ignite git commit: IGNITE-843 Fixed clusters validation.

IGNITE-843 Fixed clusters validation.


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

Branch: refs/heads/ignite-843-rc3
Commit: 250a24224a76d6b8455a1ea203c5c67aa6c3861f
Parents: 959a0c9
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Fri Jan 29 16:47:44 2016 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Fri Jan 29 16:47:44 2016 +0700

----------------------------------------------------------------------
 .../js/app/modules/Form/field/input/number.jade |   6 +-
 .../states/configuration/clusters/atomic.jade   |   2 +-
 .../configuration/clusters/connector.jade       |   4 +-
 .../clusters/general/discovery/vm.jade          |   2 +-
 .../states/configuration/clusters/ssl.jade      |   2 +-
 .../main/js/controllers/caches-controller.js    |  39 ++---
 .../main/js/controllers/clusters-controller.js  | 147 +++++++------------
 .../src/main/js/controllers/common-module.js    |  23 +--
 .../main/js/controllers/domains-controller.js   |  40 ++---
 .../src/main/js/controllers/igfs-controller.js  |  33 ++---
 .../src/main/js/views/configuration/caches.jade |   2 +-
 .../main/js/views/configuration/clusters.jade   |  14 +-
 .../main/js/views/configuration/domains.jade    |   2 +-
 .../src/main/js/views/configuration/igfs.jade   |   2 +-
 .../main/js/views/configuration/summary.jade    |   2 +-
 .../src/main/js/views/includes/controls.jade    |  16 +-
 16 files changed, 143 insertions(+), 193 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/app/modules/Form/field/input/number.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/modules/Form/field/input/number.jade b/modules/control-center-web/src/main/js/app/modules/Form/field/input/number.jade
index 2738309..58a2f16 100644
--- a/modules/control-center-web/src/main/js/app/modules/Form/field/input/number.jade
+++ b/modules/control-center-web/src/main/js/app/modules/Form/field/input/number.jade
@@ -30,15 +30,15 @@
 
     i.fa.fa-exclamation-triangle.form-control-feedback(
         ng-show='field.$error.min'
-        bs-tooltip='"Value is less than allowable minimum."'
+        bs-tooltip='"Value is less than allowable minimum"'
     )
     i.fa.fa-exclamation-triangle.form-control-feedback(
         ng-show='field.$error.max' 
-        bs-tooltip='"Value is more than allowable maximum."'
+        bs-tooltip='"Value is more than allowable maximum"'
     )
 
     i.fa.fa-exclamation-triangle.form-control-feedback(
         ng-show='field.$error.number' 
-        bs-tooltip='"Invalid value. Only numbers allowed."'
+        bs-tooltip='"Invalid value. Only numbers allowed"'
     )
     span(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/atomic.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/atomic.jade b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/atomic.jade
index 513a037..e2c1b81 100644
--- a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/atomic.jade
+++ b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/atomic.jade
@@ -16,7 +16,7 @@
 
 - var model = 'backupItem.atomicConfiguration'
 
-form.panel.panel-default(name='atomic' novalidate)
+form.panel.panel-default(name='atomics' novalidate)
     .panel-heading(bs-collapse-toggle='' ng-click='__show__ = true')
         ignite-form-panel-chevron
         label Atomic configuration

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/connector.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/connector.jade b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/connector.jade
index 5353d54..0803a74 100644
--- a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/connector.jade
+++ b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/connector.jade
@@ -99,7 +99,7 @@ form.panel.panel-default(name='connector' novalidate)
                         ignite-form-field-label
                             | Idle query cursor timeout:
                         ignite-form-field-tooltip
-                            | Reject open query cursors that is not used timeout
+                            | 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
                         ignite-form-field-input-number(
                         data-id='connectorIdleQueryCursorTimeout'
@@ -113,7 +113,7 @@ form.panel.panel-default(name='connector' novalidate)
                         ignite-form-field-label
                             | Idle query cursor check frequency:
                         ignite-form-field-tooltip
-                            | Idle query cursors check frequency.
+                            | Idle query cursors check frequency#[br]
                             | This setting is used to reject open query cursors that is not used
                         ignite-form-field-input-number(
                         data-id='connectorIdleQueryCursorCheckFrequency'

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
index 49335fa..766bc77 100644
--- a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
+++ b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
@@ -111,5 +111,5 @@ div
                         data-title='Such IP address already exists!'
                     )
         
-        .group-content-empty(ng-if='!(#{addresses}.length) && !__.add.length')
+        .group-content-empty(id='addresses' ng-if='!(#{addresses}.length) && !__.add.length')
                 | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/ssl.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/ssl.jade b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/ssl.jade
index 7063a1d..00b23f6 100644
--- a/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/ssl.jade
+++ b/modules/control-center-web/src/main/js/app/modules/states/configuration/clusters/ssl.jade
@@ -30,7 +30,7 @@ mixin feedback(field, error, message)
 form.panel.panel-default(name='#{form}' novalidate)
     .panel-heading(bs-collapse-toggle ng-click='__show__ = true')
         ignite-form-panel-chevron
-        label SSL configuration
+        label(id='sslConfiguration-title') SSL configuration
         ignite-form-field-tooltip.tipLabel
             | Settings for SSL configuration
         ignite-form-revert

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/caches-controller.js b/modules/control-center-web/src/main/js/controllers/caches-controller.js
index 3eb0809..eadceac 100644
--- a/modules/control-center-web/src/main/js/controllers/caches-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/caches-controller.js
@@ -25,6 +25,9 @@ consoleModule.controller('cachesController', [
         angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
         $scope.ui = $common.formUI();
+        $scope.ui.activePanels = [0];
+        $scope.ui.topPanels = [0, 1, 2, 3];
+
         $scope.selectedItemWatchGuard = false;
 
         $scope.joinTip = $common.joinTip;
@@ -153,8 +156,6 @@ consoleModule.controller('cachesController', [
             $common.hidePopover();
         };
 
-        $scope.panels = {activePanels: [0]};
-
         $scope.general = [];
         $scope.advanced = [];
         $scope.caches = [];
@@ -443,7 +444,7 @@ consoleModule.controller('cachesController', [
         $scope.createItem = function (id) {
             if ($scope.tableReset(true)) {
                 $timeout(function () {
-                    $common.ensureActivePanel($scope.panels, 'general', 'cacheName');
+                    $common.ensureActivePanel($scope.ui, 'general', 'cacheName');
                 });
 
                 $scope.selectItem(undefined, prepareNewItem(id));
@@ -472,7 +473,7 @@ consoleModule.controller('cachesController', [
             });
 
             if (!checkRes.checked) {
-                return showPopoverMessage($scope.panels, 'store', checkRes.firstCache.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
+                return showPopoverMessage($scope.ui, 'store', checkRes.firstCache.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
                     'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
                     'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean +
                     '" and different database: "' + $common.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
@@ -485,14 +486,14 @@ consoleModule.controller('cachesController', [
         // Check cache logical consistency.
         function validate(item) {
             if ($common.isEmptyString(item.name))
-                return showPopoverMessage($scope.panels, 'general', 'cacheName', 'Name should not be empty');
+                return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Name should not be empty');
 
             if (item.memoryMode === 'OFFHEAP_TIERED' && !$common.isDefined(item.offHeapMaxMemory))
-                return showPopoverMessage($scope.panels, 'memory', 'offHeapMaxMemory',
+                return showPopoverMessage($scope.ui, 'memory', 'offHeapMaxMemory',
                     'Off-heap max memory should be specified');
 
             if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !$common.isDefined(item.evictionPolicy.kind))
-                return showPopoverMessage($scope.panels, 'memory', 'evictionPolicy', 'Eviction policy should not be configured');
+                return showPopoverMessage($scope.ui, 'memory', 'evictionPolicy', 'Eviction policy should not be configured');
 
             var cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
 
@@ -501,14 +502,14 @@ consoleModule.controller('cachesController', [
 
                 if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory') {
                     if ($common.isEmptyString(storeFactory.dataSourceBean))
-                        return showPopoverMessage($scope.panels, 'store', 'dataSourceBean',
+                        return showPopoverMessage($scope.ui, 'store', 'dataSourceBean',
                             'Data source bean name should not be empty');
 
-                    if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.panels, 'store'))
+                    if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.ui, 'store'))
                         return false;
 
                     if (!storeFactory.dialect)
-                        return showPopoverMessage($scope.panels, 'store', 'pojoDialect',
+                        return showPopoverMessage($scope.ui, 'store', 'pojoDialect',
                             'Dialect should not be empty');
 
                     if (!checkDataSources())
@@ -518,23 +519,23 @@ consoleModule.controller('cachesController', [
                 if (item.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory') {
                     if (storeFactory.connectVia === 'URL') {
                         if ($common.isEmptyString(storeFactory.connectionUrl))
-                            return showPopoverMessage($scope.panels, 'store', 'connectionUrl',
+                            return showPopoverMessage($scope.ui, 'store', 'connectionUrl',
                                 'Connection URL should not be empty');
 
                         if ($common.isEmptyString(storeFactory.user))
-                            return showPopoverMessage($scope.panels, 'store', 'user',
+                            return showPopoverMessage($scope.ui, 'store', 'user',
                                 'User should not be empty');
                     }
                     else {
                         if ($common.isEmptyString(storeFactory.dataSourceBean))
-                            return showPopoverMessage($scope.panels, 'store', 'dataSourceBean',
+                            return showPopoverMessage($scope.ui, 'store', 'dataSourceBean',
                                 'Data source bean name should not be empty');
 
-                        if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.panels, 'store'))
+                        if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.ui, 'store'))
                             return false;
 
                         if (!storeFactory.dialect)
-                            return showPopoverMessage($scope.panels, 'store', 'blobDialect',
+                            return showPopoverMessage($scope.ui, 'store', 'blobDialect',
                                 'Database should not be empty');
 
                         if (!checkDataSources())
@@ -544,16 +545,16 @@ consoleModule.controller('cachesController', [
             }
 
             if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.panels, 'store', 'cacheStoreFactory',
+                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory',
                     (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!');
 
             if (item.writeBehindEnabled && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.panels, 'store', 'cacheStoreFactory',
+                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory',
                     'Write behind enabled but store is not configured!');
 
             if (cacheStoreFactorySelected) {
                 if (!item.readThrough && !item.writeThrough)
-                    return showPopoverMessage($scope.panels, 'store', 'readThrough',
+                    return showPopoverMessage($scope.ui, 'store', 'readThrough',
                         'Store is configured but read/write through are not enabled!');
 
                 if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory') {
@@ -561,7 +562,7 @@ consoleModule.controller('cachesController', [
                         var domains = cacheDomains($scope.backupItem);
 
                         if (_.findIndex(domains, $common.domainForStoreConfigured) < 0)
-                            return showPopoverMessage($scope.panels, 'general', 'domains',
+                            return showPopoverMessage($scope.ui, 'general', 'domains',
                                 'Cache with configured JDBC POJO store factory should be associated with at least one domain model for cache store');
                     }
                 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/clusters-controller.js b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
index e5aa9ee..3344a26 100644
--- a/modules/control-center-web/src/main/js/controllers/clusters-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/clusters-controller.js
@@ -39,6 +39,8 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
 
         $scope.ui = $common.formUI();
         $scope.ui.angularWay = true; // TODO We need to distinguish refactored UI from legacy UI.
+        $scope.ui.activePanels = [0];
+        $scope.ui.topPanels = [0];
 
         $scope.joinTip = $common.joinTip;
         $scope.getModel = $common.getModel;
@@ -126,8 +128,6 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
             $common.hidePopover();
         };
 
-        $scope.panels = {activePanels: [0]};
-
         $scope.clusters = [];
 
         function _clusterLbl (cluster) {
@@ -336,7 +336,7 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
         // Add new cluster.
         $scope.createItem = function(id) {
             $timeout(function () {
-                $common.ensureActivePanel($scope.panels, "general", 'clusterName');
+                $common.ensureActivePanel($scope.ui, "general", 'clusterName');
             });
 
             $scope.selectItem(undefined, prepareNewItem(id));
@@ -351,7 +351,19 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
         // Check cluster logical consistency.
         function validate(item) {
             if ($common.isEmptyString(item.name))
-                return showPopoverMessage($scope.panels, 'general', 'clusterName', 'Name should not be empty');
+                return showPopoverMessage($scope.ui, 'general', 'clusterName', 'Name should not be empty');
+
+            var errors = $scope.ui.inputForm.$error;
+            var errKeys = Object.keys(errors);
+
+            if (errKeys && errKeys.length > 0) {
+                var firstErrorKey = errKeys[0];
+
+                var firstError = errors[firstErrorKey][0];
+                var actualError = firstError.$error[firstErrorKey][0];
+
+                return showPopoverMessage($scope.ui, firstError.$name, actualError.$name, 'Invalid value');
+            }
 
             var caches = _.filter(_.map($scope.caches, function (scopeCache) {
                 return scopeCache.cache;
@@ -362,7 +374,7 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
             var checkRes = $common.checkCachesDataSources(caches);
 
             if (!checkRes.checked) {
-                return showPopoverMessage($scope.panels, 'general', 'caches',
+                return showPopoverMessage($scope.ui, 'general', 'caches',
                     'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' +
                     'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean +
                     '" and different databases: "' + $common.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstCache.name + '" and "' +
@@ -372,18 +384,6 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
             var b = item.binaryConfiguration;
 
             if ($common.isDefined(b)) {
-                if (!$common.isEmptyString(b.idMapper) && !$common.isValidJavaClass('ID mapper', b.idMapper, false, 'idMapper', false, $scope.panels, 'binary')) {
-                    $scope.ui.expanded = true;
-
-                    return false;
-                }
-
-                if (!$common.isEmptyString(b.serializer) && !$common.isValidJavaClass('Serializer', b.serializer, false, 'serializer', false, $scope.panels, 'binary')) {
-                    $scope.ui.expanded = true;
-
-                    return false;
-                }
-
                 if (!$common.isEmptyArray(b.typeConfigurations)) {
                     var sameName = function (t, ix) {
                         return ix < typeIx && t.typeName === type.typeName;
@@ -392,39 +392,20 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
                     for (var typeIx = 0; typeIx < b.typeConfigurations.length; typeIx++) {
                         var type = b.typeConfigurations[typeIx];
 
-                        if ($common.isEmptyString(type.typeName)) {
-                            $scope.ui.expanded = true;
-
-                            showPopoverMessage($scope.panels, 'binary', 'typeName' + typeIx, 'Type name should be specified');
+                        if ($common.isEmptyString(type.typeName))
+                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type name should be specified');
 
+                        if (!$common.isEmptyString(type.typeName) && !$common.isValidJavaClass('Type name', type.typeName, false, 'typeName' + typeIx, false, $scope.ui, 'binary'))
                             return false;
-                        }
-
-                        if (!$common.isEmptyString(type.typeName) && !$common.isValidJavaClass('Type name', type.typeName, false, 'typeName' + typeIx, false, $scope.panels, 'binary')) {
-                            $scope.ui.expanded = true;
 
+                        if (!$common.isEmptyString(type.idMapper) && !$common.isValidJavaClass('ID mapper', type.idMapper, false, 'idMapper' + typeIx, false, $scope.ui, 'binary'))
                             return false;
-                        }
-
-                        if (!$common.isEmptyString(type.idMapper) && !$common.isValidJavaClass('ID mapper', type.idMapper, false, 'idMapper' + typeIx, false, $scope.panels, 'binary')) {
-                            $scope.ui.expanded = true;
-
-                            return false;
-                        }
-
-                        if (!$common.isEmptyString(type.serializer) && !$common.isValidJavaClass('Serializer', type.serializer, false, 'serializer' + typeIx, false, $scope.panels, 'binary')) {
-                            $scope.ui.expanded = true;
 
+                        if (!$common.isEmptyString(type.serializer) && !$common.isValidJavaClass('Serializer', type.serializer, false, 'serializer' + typeIx, false, $scope.ui, 'binary'))
                             return false;
-                        }
-
-                        if (_.find(b.typeConfigurations, sameName)) {
-                            $scope.ui.expanded = true;
 
-                            showPopoverMessage($scope.panels, 'binary', 'typeName' + typeIx, 'Type with such name is already specified');
-
-                            return false;
-                        }
+                        if (_.find(b.typeConfigurations, sameName))
+                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type with such name is already specified');
                     }
                 }
             }
@@ -432,96 +413,80 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
             var c = item.communication;
 
             if ($common.isDefined(c)) {
-                if (!$common.isEmptyString(c.listener) && !$common.isValidJavaClass('Communication listener', c.listener, false, 'comListener', false, $scope.panels, 'communication')) {
-                    $scope.ui.expanded = true;
-
+                if (!$common.isEmptyString(c.listener) && !$common.isValidJavaClass('Communication listener', c.listener, false, 'comListener', false, $scope.ui, 'communication'))
                     return false;
-                }
-
-                if (!$common.isEmptyString(c.addressResolver) && !$common.isValidJavaClass('Address resolver', c.addressResolver, false, 'comAddressResolver', false, $scope.panels, 'communication')) {
-                    $scope.ui.expanded = true;
 
+                if (!$common.isEmptyString(c.addressResolver) && !$common.isValidJavaClass('Address resolver', c.addressResolver, false, 'comAddressResolver', false, $scope.ui, 'communication'))
                     return false;
-                }
 
                 if ($common.isDefined(c.unacknowledgedMessagesBufferSize)) {
                     if ($common.isDefined(c.messageQueueLimit))
-                        if (c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit) {
-                            $scope.ui.expanded = true;
-
-                            showPopoverMessage($scope.panels, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit');
-
-                            return false;
-                        }
+                        if (c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit)
+                            return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit');
 
                     if ($common.isDefined(c.ackSendThreshold))
-                        if (c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold) {
-                            $scope.ui.expanded = true;
-
-                            showPopoverMessage($scope.panels, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold');
-
-                            return false;
-                        }
+                        if (c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold)
+                            return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold');
                 }
             }
 
             var r = item.connector;
 
             if ($common.isDefined(r)) {
-                if (!$common.isEmptyString(r.messageInterceptor) && !$common.isValidJavaClass('Message interceptor', r.messageInterceptor, false, 'connectorMessageInterceptor', false, $scope.panels, 'connector'))
+                if (!$common.isEmptyString(r.messageInterceptor) && !$common.isValidJavaClass('Message interceptor', r.messageInterceptor, false, 'connectorMessageInterceptor', false, $scope.ui, 'connector'))
                     return false;
 
                 if (r.sslEnabled && $common.isEmptyString(r.sslFactory))
-                    return showPopoverMessage($scope.panels, 'connector', 'connectorSslFactory', 'SSL factory should not be empty');
+                    return showPopoverMessage($scope.ui, 'connector', 'connectorSslFactory', 'SSL factory should not be empty');
 
-                if (r.sslEnabled && !$common.isEmptyString(r.sslFactory) && !$common.isValidJavaClass('SSL factory', r.sslFactory, false, 'connectorSslFactory', false, $scope.panels, 'connector'))
+                if (r.sslEnabled && !$common.isEmptyString(r.sslFactory) && !$common.isValidJavaClass('SSL factory', r.sslFactory, false, 'connectorSslFactory', false, $scope.ui, 'connector'))
                     return false;
             }
 
             var d = item.discovery;
 
             if (d) {
-                if (!$common.isEmptyString(d.addressResolver) && !$common.isValidJavaClass('Address resolver', d.addressResolver, false, 'discoAddressResolver', false, $scope.panels, 'discovery'))
+                if (!$common.isEmptyString(d.addressResolver) && !$common.isValidJavaClass('Address resolver', d.addressResolver, false, 'discoAddressResolver', false, $scope.ui, 'discovery'))
                     return false;
 
-                if (!$common.isEmptyString(d.listener) && !$common.isValidJavaClass('Discovery listener', d.listener, false, 'discoListener', false, $scope.panels, 'discovery'))
+                if (!$common.isEmptyString(d.listener) && !$common.isValidJavaClass('Discovery listener', d.listener, false, 'discoListener', false, $scope.ui, 'discovery'))
                     return false;
 
-                if (!$common.isEmptyString(d.dataExchange) && !$common.isValidJavaClass('Data exchange', d.dataExchange, false, 'dataExchange', false, $scope.panels, 'discovery'))
+                if (!$common.isEmptyString(d.dataExchange) && !$common.isValidJavaClass('Data exchange', d.dataExchange, false, 'dataExchange', false, $scope.ui, 'discovery'))
                     return false;
 
-                if (!$common.isEmptyString(d.metricsProvider) && !$common.isValidJavaClass('Metrics provider', d.metricsProvider, false, 'metricsProvider', false, $scope.panels, 'discovery'))
+                if (!$common.isEmptyString(d.metricsProvider) && !$common.isValidJavaClass('Metrics provider', d.metricsProvider, false, 'metricsProvider', false, $scope.ui, 'discovery'))
                     return false;
 
-                if (!$common.isEmptyString(d.authenticator) && !$common.isValidJavaClass('Node authenticator', d.authenticator, false, 'authenticator', false, $scope.panels, 'discovery'))
+                if (!$common.isEmptyString(d.authenticator) && !$common.isValidJavaClass('Node authenticator', d.authenticator, false, 'authenticator', false, $scope.ui, 'discovery'))
                     return false;
 
                 if (d.kind === 'Vm' && d.Vm && d.Vm.addresses.length === 0)
-                    return showPopoverMessage($scope.panels, 'general', 'addresses', 'Addresses are not specified');
+                    return showPopoverMessage($scope.ui, 'general', 'addresses', 'Addresses are not specified');
 
                 if (d.kind === 'S3' && d.S3 && $common.isEmptyString(d.S3.bucketName))
-                    return showPopoverMessage($scope.panels, 'general', 'bucketName', 'Bucket name should not be empty');
+                    return showPopoverMessage($scope.ui, 'general', 'bucketName', 'Bucket name should not be empty');
 
                 if (d.kind === 'Cloud' && d.Cloud) {
                     if ($common.isEmptyString(d.Cloud.identity))
-                        return showPopoverMessage($scope.panels, 'general', 'identity', 'Identity should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'identity', 'Identity should not be empty');
 
                     if ($common.isEmptyString(d.Cloud.provider))
-                        return showPopoverMessage($scope.panels, 'general', 'provider', 'Provider should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'provider', 'Provider should not be empty');
                 }
 
                 if (d.kind === 'GoogleStorage' && d.GoogleStorage) {
                     if ($common.isEmptyString(d.GoogleStorage.projectName))
-                        return showPopoverMessage($scope.panels, 'general', 'projectName', 'Project name should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'projectName', 'Project name should not be empty');
 
                     if ($common.isEmptyString(d.GoogleStorage.bucketName))
-                        return showPopoverMessage($scope.panels, 'general', 'bucketName', 'Bucket name should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'bucketName', 'Bucket name should not be empty');
 
                     if ($common.isEmptyString(d.GoogleStorage.serviceAccountP12FilePath))
-                        return showPopoverMessage($scope.panels, 'general', 'serviceAccountP12FilePath', 'Private key path should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'serviceAccountP12FilePath', 'Private key path should not be empty');
 
                     if ($common.isEmptyString(d.GoogleStorage.serviceAccountId))
-                        return showPopoverMessage($scope.panels, 'general', 'serviceAccountId', 'Account ID should not be empty');
+                        return showPopoverMessage($scope.ui, 'general', 'serviceAccountId', 'Account ID should not be empty');
                 }
             }
 
@@ -531,15 +496,15 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
                 var sparsity = item.swapSpaceSpi[swapKind].maximumSparsity;
 
                 if (sparsity < 0 || sparsity >= 1)
-                    return showPopoverMessage($scope.panels, 'swap', 'maximumSparsity', 'Maximum sparsity should be more or equal 0 and less than 1');
+                    return showPopoverMessage($scope.ui, 'swap', 'maximumSparsity', 'Maximum sparsity should be more or equal 0 and less than 1');
             }
 
             if (item.sslEnabled) {
                 if (!$common.isDefined(item.sslContextFactory) || $common.isEmptyString(item.sslContextFactory.keyStoreFilePath))
-                    return showPopoverMessage($scope.panels, 'sslConfiguration', 'keyStoreFilePath', 'Key store file should not be empty');
+                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'keyStoreFilePath', 'Key store file should not be empty');
 
                 if ($common.isEmptyString(item.sslContextFactory.trustStoreFilePath) && $common.isEmptyArray(item.sslContextFactory.trustManagers))
-                    return showPopoverMessage($scope.panels, 'sslConfiguration', 'sslConfiguration-title', 'Trust storage file or managers should be configured');
+                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'sslConfiguration-title', 'Trust storage file or managers should be configured');
             }
 
             if (!item.swapSpaceSpi || !item.swapSpaceSpi.kind && item.caches) {
@@ -549,22 +514,16 @@ consoleModule.controller('clustersController', function ($http, $timeout, $scope
                     if (idx >= 0) {
                         var cache = $scope.caches[idx];
 
-                        if (cache.cache.swapEnabled) {
-                            $scope.ui.expanded = true;
-
-                            return showPopoverMessage($scope.panels, 'swap', 'swapSpaceSpi',
+                        if (cache.cache.swapEnabled)
+                            return showPopoverMessage($scope.ui, 'swap', 'swapSpaceSpi',
                                 'Swap space SPI is not configured, but cache "' + cache.label + '" configured to use swap!');
-                        }
                     }
                 }
             }
 
-            if (item.rebalanceThreadPoolSize && item.systemThreadPoolSize && item.systemThreadPoolSize <= item.rebalanceThreadPoolSize) {
-                $scope.ui.expanded = true;
-
-                return showPopoverMessage($scope.panels, 'pools', 'rebalanceThreadPoolSize',
+            if (item.rebalanceThreadPoolSize && item.systemThreadPoolSize && item.systemThreadPoolSize <= item.rebalanceThreadPoolSize)
+                return showPopoverMessage($scope.ui, 'pools', 'rebalanceThreadPoolSize',
                     'Rebalance thread pool size exceed or equals System thread pool size');
-            }
 
             return true;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/controllers/common-module.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/common-module.js b/modules/control-center-web/src/main/js/controllers/common-module.js
index 67a9c2c..16036ac 100644
--- a/modules/control-center-web/src/main/js/controllers/common-module.js
+++ b/modules/control-center-web/src/main/js/controllers/common-module.js
@@ -563,23 +563,26 @@ consoleModule.service('$common', [
 
         var popover = null;
 
-        function ensureActivePanel(panels, id, focusId) {
-            if (panels) {
+        function ensureActivePanel(ui, id, focusId) {
+            if (ui) {
                 var idx = _.findIndex($('div.panel-collapse'), function(pnl) {
                     return pnl.id === id;
                 });
 
                 if (idx >= 0) {
-                    var activePanels = panels.activePanels;
+                    var activePanels = ui.activePanels;
+
+                    if (!_.includes(ui.topPanels))
+                        ui.expanded = true;
 
                     if (!activePanels || activePanels.length < 1)
-                        panels.activePanels = [idx];
+                        ui.activePanels = [idx];
                     else if (!_.contains(activePanels, idx)) {
                         var newActivePanels = angular.copy(activePanels);
 
                         newActivePanels.push(idx);
 
-                        panels.activePanels = newActivePanels;
+                        ui.activePanels = newActivePanels;
                     }
                 }
 
@@ -588,8 +591,8 @@ consoleModule.service('$common', [
             }
         }
 
-        function showPopoverMessage(panels, panelId, id, message, showTime) {
-            ensureActivePanel(panels, panelId, id);
+        function showPopoverMessage(ui, panelId, id, message, showTime) {
+            ensureActivePanel(ui, panelId, id);
 
             var el = $('body').find('#' + id);
 
@@ -900,13 +903,13 @@ consoleModule.service('$common', [
             ensureActivePanel: function (panels, id, focusId) {
                 ensureActivePanel(panels, id, focusId);
             },
-            panelExpanded: function (panels, id) {
-                if (panels && panels.activePanels && panels.activePanels.length > 0) {
+            panelExpanded: function (ui, id) {
+                if (ui && ui.activePanels && ui.activePanels.length > 0) {
                     var idx = _.findIndex($('div.panel-collapse'), function(pnl) {
                         return pnl.id === id;
                     });
 
-                    return idx >= 0 && _.includes(panels.activePanels, idx);
+                    return idx >= 0 && _.includes(ui.activePanels, idx);
                 }
 
                 return false;

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/domains-controller.js b/modules/control-center-web/src/main/js/controllers/domains-controller.js
index 451d6d1..c78cbd4 100644
--- a/modules/control-center-web/src/main/js/controllers/domains-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/domains-controller.js
@@ -24,6 +24,8 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
         angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
         $scope.ui = $common.formUI();
+        $scope.ui.activePanels = [0, 1];
+        $scope.ui.topPanels = [];
 
         var IMPORT_DM_NEW_CACHE = 1;
         var IMPORT_DM_ASSOCIATE_CACHE = 2;
@@ -370,8 +372,6 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
             {value: false, label: 'DESC'}
         ];
 
-        $scope.panels = {activePanels: [0, 1]};
-
         $scope.domains = [];
 
         $scope.isJavaBuiltInClass = function () {
@@ -757,7 +757,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                         $common.showInfo('Domain models imported from database.');
 
-                        $scope.panels.activePanels = [0, 1, 2];
+                        $scope.ui.activePanels = [0, 1, 2];
 
                         $scope.ui.showValid = true;
                     })
@@ -1251,8 +1251,8 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
         $scope.createItem = function (cacheId) {
             if ($scope.tableReset(true)) {
                 $timeout(function () {
-                    $common.ensureActivePanel($scope.panels, 'query');
-                    $common.ensureActivePanel($scope.panels, 'general', 'keyType');
+                    $common.ensureActivePanel($scope.ui, 'query');
+                    $common.ensureActivePanel($scope.ui, 'general', 'keyType');
                 });
 
                 $scope.selectItem(undefined, prepareNewItem(cacheId));
@@ -1262,12 +1262,12 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
         // Check domain model logical consistency.
         function validate(item) {
             if ($common.isEmptyString(item.keyType))
-                return showPopoverMessage($scope.panels, 'general', 'keyType', 'Key type should not be empty');
+                return showPopoverMessage($scope.ui, 'general', 'keyType', 'Key type should not be empty');
             else if (!$common.isValidJavaClass('Key type', item.keyType, true, 'keyType'))
                 return false;
 
             if ($common.isEmptyString(item.valueType))
-                return showPopoverMessage($scope.panels, 'general', 'valueType', 'Value type should not be empty');
+                return showPopoverMessage($scope.ui, 'general', 'valueType', 'Value type should not be empty');
             else if (!$common.isValidJavaClass('Value type', item.valueType, false, 'valueType'))
                 return false;
 
@@ -1276,14 +1276,14 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
             if (item.queryMetadata === 'Configuration' && qry) {
                 if ($common.isEmptyArray(item.fields))
-                    return showPopoverMessage($scope.panels, 'query', 'fields-legend', 'Query fields should not be empty');
+                    return showPopoverMessage($scope.ui, 'query', 'fields-legend', 'Query fields should not be empty');
 
                 var indexes = item.indexes;
 
                 if (indexes && indexes.length > 0) {
                     if (_.find(indexes, function (index, i) {
                             if ($common.isEmptyArray(index.fields))
-                                return !showPopoverMessage($scope.panels, 'query', 'indexes' + i, 'Index fields are not specified');
+                                return !showPopoverMessage($scope.ui, 'query', 'indexes' + i, 'Index fields are not specified');
                         }))
                         return false;
                 }
@@ -1291,22 +1291,22 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
             if (str) {
                 if ($common.isEmptyString(item.databaseSchema))
-                    return showPopoverMessage($scope.panels, 'store', 'databaseSchema', 'Database schema should not be empty');
+                    return showPopoverMessage($scope.ui, 'store', 'databaseSchema', 'Database schema should not be empty');
 
                 if ($common.isEmptyString(item.databaseTable))
-                    return showPopoverMessage($scope.panels, 'store', 'databaseTable', 'Database table should not be empty');
+                    return showPopoverMessage($scope.ui, 'store', 'databaseTable', 'Database table should not be empty');
 
                 if ($common.isEmptyArray(item.keyFields))
-                    return showPopoverMessage($scope.panels, 'store', 'keyFields-add', 'Key fields are not specified');
+                    return showPopoverMessage($scope.ui, 'store', 'keyFields-add', 'Key fields are not specified');
 
                 if ($common.isJavaBuiltInClass(item.keyType) && item.keyFields.length !== 1)
-                    return showPopoverMessage($scope.panels, 'store', 'keyFields-add', 'Only one field should be specified in case when key type is a Java built-in type');
+                    return showPopoverMessage($scope.ui, 'store', 'keyFields-add', 'Only one field should be specified in case when key type is a Java built-in type');
 
                 if ($common.isEmptyArray(item.valueFields))
-                    return showPopoverMessage($scope.panels, 'store', 'valueFields-add', 'Value fields are not specified');
+                    return showPopoverMessage($scope.ui, 'store', 'valueFields-add', 'Value fields are not specified');
             }
             else if (!qry && item.queryMetadata === 'Configuration') {
-                return showPopoverMessage($scope.panels, 'query', 'query-title', 'SQL query domain model should be configured');
+                return showPopoverMessage($scope.ui, 'query', 'query-title', 'SQL query domain model should be configured');
             }
 
             return true;
@@ -1505,7 +1505,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                     // Found duplicate by key.
                     if (idx >= 0 && idx !== index)
-                        return showPopoverMessage($scope.panels, 'query', $table.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!');
+                        return showPopoverMessage($scope.ui, 'query', $table.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!');
                 }
 
                 if (pairField.classValidation && !$common.isValidJavaClass(pairField.msg, pairValue.value, true, $table.tableFieldId(index, 'Value' + pairField.id)))
@@ -1563,7 +1563,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                     // Found duplicate.
                     if (idx >= 0 && index !== idx)
-                        return showPopoverMessage($scope.panels, 'store', $table.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!');
+                        return showPopoverMessage($scope.ui, 'store', $table.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!');
 
                     idx = _.findIndex(model, function (dbMeta) {
                         return dbMeta.javaFieldName === dbFieldValue.javaFieldName;
@@ -1571,7 +1571,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                     // Found duplicate.
                     if (idx >= 0 && index !== idx)
-                        return showPopoverMessage($scope.panels, 'store', $table.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!');
+                        return showPopoverMessage($scope.ui, 'store', $table.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!');
 
                     if (index < 0) {
                         model.push(dbFieldValue);
@@ -1633,7 +1633,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                 // Found duplicate.
                 if (idx >= 0 && idx !== curIdx)
-                    return showPopoverMessage($scope.panels, 'query', $table.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!');
+                    return showPopoverMessage($scope.ui, 'query', $table.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!');
             }
 
             $table.tableReset();
@@ -1750,7 +1750,7 @@ consoleModule.controller('domainsController', function ($filter, $http, $timeout
 
                 // Found duplicate.
                 if (idx >= 0 && idx !== curIdx)
-                    return showPopoverMessage($scope.panels, 'query', $table.tableFieldId(curIdx, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx + (curIdx >= 0 ? '-' : '')), 'Field with such name already exists in index!');
+                    return showPopoverMessage($scope.ui, 'query', $table.tableFieldId(curIdx, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx + (curIdx >= 0 ? '-' : '')), 'Field with such name already exists in index!');
             }
 
             $table.tableReset();

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/controllers/igfs-controller.js
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/controllers/igfs-controller.js b/modules/control-center-web/src/main/js/controllers/igfs-controller.js
index d5565d1..83da23a 100644
--- a/modules/control-center-web/src/main/js/controllers/igfs-controller.js
+++ b/modules/control-center-web/src/main/js/controllers/igfs-controller.js
@@ -25,6 +25,8 @@ consoleModule.controller('igfsController', [
             angular.extend(this, $controller('save-remove', {$scope: $scope}));
 
             $scope.ui = $common.formUI();
+            $scope.ui.activePanels = [0];
+            $scope.ui.topPanels = [0];
 
             $scope.joinTip = $common.joinTip;
             $scope.getModel = $common.getModel;
@@ -121,8 +123,6 @@ consoleModule.controller('igfsController', [
                 $common.hidePopover();
             };
 
-            $scope.panels = {activePanels: [0]};
-
             $scope.general = [];
             $scope.advanced = [];
             $scope.igfss = [];
@@ -149,7 +149,7 @@ consoleModule.controller('igfsController', [
 
                     // Found duplicate.
                     if (idx >= 0 && idx !== index)
-                        return showPopoverMessage($scope.panels, 'misc', $table.tableFieldId(index, 'KeyPathMode'), 'Such path already exists!');
+                        return showPopoverMessage($scope.ui, 'misc', $table.tableFieldId(index, 'KeyPathMode'), 'Such path already exists!');
                 }
 
                 return true;
@@ -292,7 +292,7 @@ consoleModule.controller('igfsController', [
             $scope.createItem = function (id) {
                 if ($scope.tableReset(true)) {
                     $timeout(function () {
-                        $common.ensureActivePanel($scope.panels, 'general', 'igfsName');
+                        $common.ensureActivePanel($scope.ui, 'general', 'igfsName');
                     });
 
                     $scope.selectItem(undefined, prepareNewItem(id));
@@ -302,32 +302,19 @@ consoleModule.controller('igfsController', [
             // Check IGFS logical consistency.
             function validate(item) {
                 if ($common.isEmptyString(item.name))
-                    return showPopoverMessage($scope.panels, 'general', 'igfsName', 'Name should not be empty');
+                    return showPopoverMessage($scope.ui, 'general', 'igfsName', 'Name should not be empty');
 
                 if (!$common.isEmptyString(item.dualModePutExecutorService) &&
-                    !$common.isValidJavaClass('Put executor service', item.dualModePutExecutorService, false, 'dualModePutExecutorService', false, $scope.panels, 'dualMode')) {
-                    $scope.ui.expanded = true;
-
+                    !$common.isValidJavaClass('Put executor service', item.dualModePutExecutorService, false, 'dualModePutExecutorService', false, $scope.ui, 'dualMode'))
                     return false;
-                }
-
-                if (!item.secondaryFileSystemEnabled && (item.defaultMode === 'PROXY')) {
-                    $scope.ui.expanded = true;
-
-                    showPopoverMessage($scope.panels, 'secondaryFileSystem', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" IGFS mode');
 
-                    return false;
-                }
+                if (!item.secondaryFileSystemEnabled && (item.defaultMode === 'PROXY'))
+                    return showPopoverMessage($scope.ui, 'secondaryFileSystem', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" IGFS mode');
 
                 if (item.pathModes) {
                     for (var pathIx = 0; pathIx < item.pathModes.length; pathIx ++) {
-                        if (!item.secondaryFileSystemEnabled && item.pathModes[pathIx].mode === 'PROXY') {
-                            $scope.ui.expanded = true;
-
-                            showPopoverMessage($scope.panels, 'misc', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" path mode');
-
-                            return false;
-                        }
+                        if (!item.secondaryFileSystemEnabled && item.pathModes[pathIx].mode === 'PROXY')
+                            return showPopoverMessage($scope.ui, 'misc', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" path mode');
                     }
                 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/caches.jade b/modules/control-center-web/src/main/js/views/configuration/caches.jade
index 97a2494..290a625 100644
--- a/modules/control-center-web/src/main/js/views/configuration/caches.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/caches.jade
@@ -34,7 +34,7 @@ include ../includes/controls
                 +save-remove-buttons('cache')
                 hr
             form.form-horizontal(name='ui.inputForm' ng-show='backupItem && tableVisibleRow(displayedRows, selectedItem)' novalidate)
-                .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true')
+                .panel-group(bs-collapse ng-model='ui.activePanels' data-allow-multiple='true')
                     +groups('general', 'backupItem')
                     div(ng-show='ui.expanded')
                         +advanced-options

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/clusters.jade b/modules/control-center-web/src/main/js/views/configuration/clusters.jade
index 28fc273..c30e6d7 100644
--- a/modules/control-center-web/src/main/js/views/configuration/clusters.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/clusters.jade
@@ -51,16 +51,16 @@ include ../includes/controls
                     .panel-tip-container(ng-show='backupItem')
                         i.btn.btn-primary.fa.fa-undo(id='undo-item' ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && resetAll()' bs-tooltip=undoTip data-placement='bottom' data-trigger='hover')
             hr
-            div(bs-collapse='' data-allow-multiple='true' ng-model='__.groups')
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
                 form.form-horizontal(name='ui.inputForm' ng-show='backupItem' novalidate)
                     .panel-group(ng-click='triggerDigest = true')
                         ignite-configuration-clusters-general
                         .advanced-options
                             i.fa(
-                                ng-click='__.advanced = !__.advanced'
-                                ng-class='__.advanced ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-                            a(ng-click='__.advanced = !__.advanced') {{__.advanced ? 'Hide advanced settings...' : 'Show advanced settings...'}}
-                        div(ng-show='__.advanced')
+                                ng-click='toggleExpanded()'
+                                ng-class='ui.expanded ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+                            a(ng-click='toggleExpanded()') {{ui.expanded ? 'Hide advanced settings...' : 'Show advanced settings...'}}
+                        div(ng-show='ui.expanded')
                             ignite-configuration-clusters-atomic
                             ignite-configuration-clusters-binary
                             ignite-configuration-clusters-communication
@@ -78,5 +78,5 @@ include ../includes/controls
                             ignite-configuration-clusters-transactions
 
                             .advanced-options
-                                i.fa.fa-chevron-circle-down(ng-click='__.advanced = !__.advanced')
-                                a(ng-click='__.advanced = !__.advanced') Hide advanced settings...
+                                i.fa.fa-chevron-circle-down(ng-click='ui.expanded = !ui.expanded')
+                                a(ng-click='ui.expanded = !ui.expanded') Hide advanced settings...

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/configuration/domains.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/domains.jade b/modules/control-center-web/src/main/js/views/configuration/domains.jade
index eb79b5a..c817ca5 100644
--- a/modules/control-center-web/src/main/js/views/configuration/domains.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/domains.jade
@@ -64,5 +64,5 @@ include ../includes/controls
                             span.caret
                 hr
             form.form-horizontal(name='ui.inputForm' ng-show='backupItem && tableVisibleRow((displayedRows | domainsValidation:ui.showValid:true), selectedItem)' novalidate)
-                .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true')
+                .panel-group(bs-collapse ng-model='ui.activePanels' data-allow-multiple='true')
                     +groups('domainModel', 'backupItem')

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/configuration/igfs.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/igfs.jade b/modules/control-center-web/src/main/js/views/configuration/igfs.jade
index eec1cbd..c6eaa89 100644
--- a/modules/control-center-web/src/main/js/views/configuration/igfs.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/igfs.jade
@@ -33,7 +33,7 @@ include ../includes/controls
                 +save-remove-buttons('IGFS')
                 hr
             form.form-horizontal(name='ui.inputForm' ng-show='backupItem && tableVisibleRow(displayedRows, selectedItem)' novalidate)
-                .panel-group(bs-collapse ng-model='panels.activePanels' data-allow-multiple='true' ng-click='triggerDigest = true')
+                .panel-group(bs-collapse ng-model='ui.activePanels' data-allow-multiple='true' ng-click='triggerDigest = true')
                     +groups('general', 'backupItem')
                     div(ng-show='ui.expanded')
                         +advanced-options

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/configuration/summary.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/configuration/summary.jade b/modules/control-center-web/src/main/js/views/configuration/summary.jade
index 1e19560..6258900 100644
--- a/modules/control-center-web/src/main/js/views/configuration/summary.jade
+++ b/modules/control-center-web/src/main/js/views/configuration/summary.jade
@@ -49,7 +49,7 @@ mixin ignite-form-field-tooltip(message)
                             label.tipLabel Project structure
                     button.btn.btn-primary(id='proprietary-jdbc-drivers' ng-if='downloadJdbcDriversVisible()' ng-click='downloadJdbcDrivers()' bs-tooltip='' data-title='Open proprietary JDBC drivers download pages' data-placement='bottom') Download JDBC drivers
                     hr
-                .panel-group(bs-collapse ng-init='panels.activePanels=[0,1]' ng-model='panels.activePanels' data-allow-multiple='true')
+                .panel-group(bs-collapse ng-init='ui.activePanels=[0,1]' ng-model='ui.activePanels' data-allow-multiple='true')
                     .panel.panel-default
                         .panel-heading(role='tab' bs-collapse-toggle)
                             i.fa(ng-class='panelExpanded(panels, "server") ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')

http://git-wip-us.apache.org/repos/asf/ignite/blob/250a2422/modules/control-center-web/src/main/js/views/includes/controls.jade
----------------------------------------------------------------------
diff --git a/modules/control-center-web/src/main/js/views/includes/controls.jade b/modules/control-center-web/src/main/js/views/includes/controls.jade
index f96399c..0c5cd51 100644
--- a/modules/control-center-web/src/main/js/views/includes/controls.jade
+++ b/modules/control-center-web/src/main/js/views/includes/controls.jade
@@ -172,9 +172,9 @@ mixin details-row(lblClasses, fieldClasses)
                 +tipField('detail.tip')
                 .input-tip
                     input.form-control(id='{{::detail.id}}' name='{{detail.model}}' type='number' placeholder='{{::detail.placeholder}}' min='{{detail.min ? detail.min : 0}}' max='{{detail.max ? detail.max : Number.MAX_VALUE}}' step='{{detail.step ? detail.step : 1}}')&attributes(detailCommon)
-                    +ico-exclamation('{{detail.model}}', 'min', 'Value is less than allowable minimum.')
-                    +ico-exclamation('{{detail.model}}', 'max', 'Value is more than allowable maximum.')
-                    +ico-exclamation('{{detail.model}}', 'number', 'Invalid value. Only numbers allowed.')
+                    +ico-exclamation('{{detail.model}}', 'min', 'Value is less than allowable minimum')
+                    +ico-exclamation('{{detail.model}}', 'max', 'Value is more than allowable maximum')
+                    +ico-exclamation('{{detail.model}}', 'number', 'Invalid value. Only numbers allowed')
         div(ng-switch-when='dropdown' ng-hide=detailHide)
             label(class=lblDetailClasses ng-class='{required: detail.required}') {{::detail.label}}:
             .div(class=fieldClasses)
@@ -209,7 +209,7 @@ mixin details-row(lblClasses, fieldClasses)
                                         +btn-save('tableSimpleSaveVisible(detail, index)', 'tableSimpleSave(tableSimpleValid, backupItem, detail, $index)')
                                         .input-tip.form-group.has-feedback
                                             input.form-control(id='cur{{::detail.focusId + $index}}' name='{{detail.model}}.edit' type='text' ng-model='detail.curValue' placeholder='{{::detail.placeholder}}' on-enter='tableSimpleSaveVisible(detail, index) && tableSimpleSave(tableSimpleValid, backupItem, detail, $index)' on-escape='tableReset()')&attributes(customValidators)
-                                            +ico-exclamation('{{detail.model}}.edit', 'ipaddress', 'Invalid address, see help for format description.')
+                                            +ico-exclamation('{{detail.model}}.edit', 'ipaddress', 'Invalid address, see help for format description')
                         tfoot(ng-show='tableNewItemActive(detail)')
                             tr
                                 td
@@ -217,7 +217,7 @@ mixin details-row(lblClasses, fieldClasses)
                                     +btn-save('tableSimpleSaveVisible(detail, -1)', 'tableSimpleSave(tableSimpleValid, backupItem, detail, -1)')
                                     .input-tip.form-group.has-feedback
                                         input.form-control(id='new{{::detail.focusId}}' name='{{detail.model}}' type='text' ng-model='detail.newValue' placeholder='{{::detail.placeholder}}' on-enter='tableSimpleSaveVisible(detail, -1) && tableSimpleSave(tableSimpleValid, backupItem, detail, -1)' on-escape='tableReset()')&attributes(customValidators)
-                                        +ico-exclamation('{{detail.model}}', 'ipaddress', 'Invalid address, see help for format description.')
+                                        +ico-exclamation('{{detail.model}}', 'ipaddress', 'Invalid address, see help for format description')
 
 mixin table-db-field-edit(prefix, focusId, index)
     -var databaseName = prefix + 'DatabaseFieldName'
@@ -368,9 +368,9 @@ mixin form-row-custom(lblClasses, fieldClasses, dataSource)
                 +tipField('field.tip')
                 .input-tip
                     input.form-control(id='{{::field.id}}' name='{{field.model}}' type='number' placeholder='{{::field.placeholder}}' min='{{field.min ? field.min : 0}}' max='{{field.max ? field.max : Number.MAX_VALUE}}' step='{{field.step ? field.step: 1}}')&attributes(fieldCommon)&attributes(fieldDisabled)
-                    +ico-exclamation('{{field.model}}', 'min', 'Value is less than allowable minimum.')
-                    +ico-exclamation('{{field.model}}', 'max', 'Value is more than allowable maximum.')
-                    +ico-exclamation('{{field.model}}', 'number', 'Invalid value. Only numbers allowed.')
+                    +ico-exclamation('{{field.model}}', 'min', 'Value is less than allowable minimum')
+                    +ico-exclamation('{{field.model}}', 'max', 'Value is more than allowable maximum')
+                    +ico-exclamation('{{field.model}}', 'number', 'Invalid value. Only numbers allowed')
         div(ng-switch-when='dropdown' ng-hide=fieldHide)
             label(class=lblClasses ng-class=fieldRequiredClass) {{::field.label}}:
             div(class=fieldClasses)