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 2016/06/27 03:23:02 UTC

[18/22] ignite git commit: Ignite Web Console beta2.

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
new file mode 100644
index 0000000..3406ff5
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
@@ -0,0 +1,65 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.logger'
+-var form = 'logger'
+-var kind = model + '.kind'
+
+form.panel.panel-default(name=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Logger configuration
+        ignite-form-field-tooltip.tipLabel
+            | Logging functionality used throughout the system
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +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: undefined, 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>')
+                .settings-row(ng-show='#{kind} && (#{kind} === "Log4j2" || #{kind} === "Log4j" || #{kind} === "Custom")')
+                    .panel-details
+                        ignite-configuration-clusters-logger-log4j2(
+                            ng-show='#{kind} === "Log4j2"')
+                        ignite-configuration-clusters-logger-log4j(
+                            ng-show='#{kind} === "Log4j"')
+                        ignite-configuration-clusters-logger-custom(
+                            ng-show='#{kind} === "Custom"')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterLogger')

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
new file mode 100644
index 0000000..5bd586b
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './custom.jade!';
+
+export default ['igniteConfigurationClustersLoggerCustom', [() => {
+    return {
+        scope: true,
+        restrict: 'E',
+        template,
+        replace: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
new file mode 100644
index 0000000..58dba15
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
@@ -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.
+
+include ../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.logger.Custom'
+-var required = 'backupItem.logger.kind === "Custom"'
+
+div
+    .details-row
+        +java-class('Class:', model + '.class', 'customLogger', 'true', required, 'Logger implementation class')

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
new file mode 100644
index 0000000..64e4337
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './log4j.jade!';
+
+export default ['igniteConfigurationClustersLoggerLog4j', [() => {
+    return {
+        scope: true,
+        restrict: 'E',
+        template,
+        replace: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
new file mode 100644
index 0000000..97f407d
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
@@ -0,0 +1,49 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include ../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.logger.Log4j'
+-var pathRequired = model + '.mode === "Path" && backupItem.logger.kind === "Log4j"'
+
+div
+    .details-row
+        +dropdown('Level:', model + '.level', 'log4jLevel', 'true', 'Default',
+            '[\
+                {value: "OFF", label: "OFF"},\
+                {value: "FATAL", label: "FATAL"},\
+                {value: "ERROR", label: "ERROR"},\
+                {value: "WARN", label: "WARN"},\
+                {value: "INFO", label: "INFO"},\
+                {value: "DEBUG", label: "DEBUG"},\
+                {value: "TRACE", label: "TRACE"},\
+                {value: "ALL", label: "ALL"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Level for internal log4j implementation')
+    .details-row
+        +dropdown-required('Logger configuration:', model + '.mode', 'log4jMode', 'true', 'true', 'Choose logger mode',
+            '[\
+                {value: "Default", label: "Default"},\
+                {value: "Path", label: "Path"}\
+            ]',
+            'Choose logger configuration\
+            <ul>\
+                <li>Default - default logger</li>\
+                <li>Path - path or URI to XML configuration</li>\
+            </ul>')
+    .details-row(ng-show=pathRequired)
+        +text('Path:', model + '.path', 'log4jPath', pathRequired, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
new file mode 100644
index 0000000..ad891f7
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './log4j2.jade!';
+
+export default ['igniteConfigurationClustersLoggerLog4j2', [() => {
+    return {
+        scope: true,
+        restrict: 'E',
+        template,
+        replace: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
new file mode 100644
index 0000000..b4cea90
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
@@ -0,0 +1,38 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include ../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.logger.Log4j2'
+-var log4j2Required = 'backupItem.logger.kind === "Log4j2"'
+
+div
+    .details-row
+        +dropdown('Level:', model + '.level', 'log4j2Level', 'true', 'Default',
+            '[\
+                {value: "OFF", label: "OFF"},\
+                {value: "FATAL", label: "FATAL"},\
+                {value: "ERROR", label: "ERROR"},\
+                {value: "WARN", label: "WARN"},\
+                {value: "INFO", label: "INFO"},\
+                {value: "DEBUG", label: "DEBUG"},\
+                {value: "TRACE", label: "TRACE"},\
+                {value: "ALL", label: "ALL"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Level for internal log4j2 implementation')
+    .details-row
+        +text('Path:', model + '.path', 'log4j2Path', log4j2Required, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade b/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
index 9974417..f66de92 100644
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
@@ -62,7 +62,7 @@ form.panel.panel-default(name='query' novalidate)
                 .content-not-available(ng-if='#{model}.queryMetadata === "Annotations"')
                     label Not available for annotated types
                 div(ng-if='#{model}.queryMetadata === "Configuration"')
-                    .settings-row(ng-init='queryFieldsTbl={type: "fields", model: "fields", focusId: "QryField", ui: "table-pair", keyName: "name", valueName: "className"}')
+                    .settings-row
                         ignite-form-group(ng-model='#{queryFields}' ng-form='#{queryFieldsForm}')
                             ignite-form-field-label(id='queryFields')
                                 | Fields
@@ -85,7 +85,7 @@ form.panel.panel-default(name='query' novalidate)
                                         tr
                                             td.col-sm-12
                                                 +table-pair-edit('queryFieldsTbl', 'new', 'Field name', 'Field full class name', false, true, '{{::queryFieldsTbl.focusId + $index}}', '-1', '/')
-                    .settings-row(ng-init='aliasesTbl={type: "aliases", model: "aliases", focusId: "Alias", ui: "table-pair", keyName: "field", valueName: "alias"}')
+                    .settings-row
                         ignite-form-group(ng-model='#{queryAliases}' ng-form='#{queryAliasesForm}')
                             ignite-form-field-label
                                 | Aliases

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade b/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
index c6c3351..d2a1dc6 100644
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
@@ -66,7 +66,7 @@ form.panel.panel-default(name=form novalidate)
         ignite-form-panel-chevron
         label Domain model for cache store
         ignite-form-field-tooltip.tipLabel
-            | Domain model properties for fields queries
+            | Domain model properties for binding database with cache via POJO cache store
         ignite-form-revert
     .panel-collapse(role='tabpanel' bs-collapse-target id=form)
         .panel-body(ng-if='ui.isPanelLoaded("#{form}")')

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
index 7cc0354..fd42805 100644
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
+++ b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
@@ -79,7 +79,7 @@ form.panel.panel-default(name=form novalidate)
                         'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks. It is recommended to set\
                         this flag to <b>false</b>b> if your application has conflicting operations, or you do not how exactly users will\
                         use your system.')
-                .settings-row(ng-init='tblPathModes={type: "pathModes", model: "pathModes", focusId: "PathMode", ui: "table-pair", keyName: "path", valueName: "mode"}')
+                .settings-row
                     ignite-form-group(ng-model=pathModes ng-form=pathModesForm)
                         ignite-form-field-label
                             | Path modes

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/modules/user/Auth.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/user/Auth.service.js b/modules/web-console/src/main/js/app/modules/user/Auth.service.js
index 8ed9f33..f0aa397 100644
--- a/modules/web-console/src/main/js/app/modules/user/Auth.service.js
+++ b/modules/web-console/src/main/js/app/modules/user/Auth.service.js
@@ -41,11 +41,15 @@ export default ['Auth', ['$http', '$rootScope', '$state', '$window', '$common',
             set authorized(auth) {
                 _authorized(auth);
             },
+            forgotPassword(userInfo) {
+                return $http.post('/api/v1/password/forgot', userInfo)
+                    .success(() => $state.go('password.send'))
+                    .error((err) => $common.showPopoverMessage(null, null, 'forgot_email', $common.errorMessage(err)));
+            },
             auth(action, userInfo) {
-                $http.post('/api/v1/' + action, userInfo)
-                    .then(User.read)
-                    .then((user) => {
-                        if (action !== 'password/forgot') {
+                return $http.post('/api/v1/' + action, userInfo)
+                    .success(() => {
+                        return User.read().then((user) => {
                             _authorized(true);
 
                             $root.$broadcast('user', user);
@@ -55,13 +59,12 @@ export default ['Auth', ['$http', '$rootScope', '$state', '$window', '$common',
                             $root.gettingStarted.tryShow();
 
                             agentMonitor.init();
-                        } else
-                            $state.go('password.send');
+                        });
                     })
-                    .catch((errMsg) => $common.showPopoverMessage(null, null, action === 'signup' ? 'signup_email' : 'signin_email', errMsg.data));
+                    .error((err) => $common.showPopoverMessage(null, null, action + '_email', $common.errorMessage(err)));
             },
             logout() {
-                $http.post('/api/v1/logout')
+                return $http.post('/api/v1/logout')
                     .then(() => {
                         User.clean();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/services/AgentMonitor.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/AgentMonitor.service.js b/modules/web-console/src/main/js/app/services/AgentMonitor.service.js
deleted file mode 100644
index 88995d5..0000000
--- a/modules/web-console/src/main/js/app/services/AgentMonitor.service.js
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import io from 'socket.io-client'; // eslint-disable-line no-unused-vars
-
-class IgniteAgentMonitor {
-    constructor(socketFactory, $root, $q, $state, $modal, $common) {
-        this._scope = $root.$new();
-
-        $root.$on('$stateChangeStart', () => {
-            this.stopWatch();
-        });
-
-        // Pre-fetch modal dialogs.
-        this._downloadAgentModal = $modal({
-            scope: this._scope,
-            templateUrl: '/templates/agent-download.html',
-            show: false,
-            backdrop: 'static'
-        });
-
-        const _modalHide = this._downloadAgentModal.hide;
-
-        /**
-         * Special dialog hide function.
-         */
-        this._downloadAgentModal.hide = () => {
-            $common.hideAlert();
-
-            _modalHide();
-        };
-
-        /**
-         * Close dialog and go by specified link.
-         */
-        this._scope.back = () => {
-            this.stopWatch();
-
-            if (this._scope.backState)
-                this._scope.$$postDigest(() => $state.go(this._scope.backState));
-        };
-
-        this._scope.downloadAgent = () => {
-            const lnk = document.createElement('a');
-
-            lnk.setAttribute('href', '/api/v1/agent/download/zip');
-            lnk.setAttribute('target', '_self');
-            lnk.setAttribute('download', null);
-            lnk.style.display = 'none';
-
-            document.body.appendChild(lnk);
-
-            lnk.click();
-
-            document.body.removeChild(lnk);
-        };
-
-        this._scope.hasAgents = null;
-        this._scope.showModal = false;
-
-        this._evtOrderKey = $common.randomString(20);
-        this._evtThrottleCntrKey = $common.randomString(20);
-
-        /**
-         * @type {Socket}
-         */
-        this._socket = null;
-
-        this._socketFactory = socketFactory;
-
-        this._$q = $q;
-
-        this._$common = $common;
-    }
-
-    /**
-     * @private
-     */
-    checkModal() {
-        if (this._scope.showModal && !this._scope.hasAgents)
-            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
-        else if ((this._scope.hasAgents || !this._scope.showModal) && this._downloadAgentModal.$isShown)
-            this._downloadAgentModal.hide();
-    }
-
-    /**
-     * @returns {Promise}
-     */
-    awaitAgent() {
-        if (this._scope.hasAgents)
-            return this._$q.when();
-
-        if (this._scope.hasAgents !== null)
-            this.checkModal();
-
-        const latch = this._$q.defer();
-
-        const offConnected = this._scope.$on('agent:connected', (event, success) => {
-            offConnected();
-
-            if (success)
-                return latch.resolve();
-
-            latch.reject();
-        });
-
-        return latch.promise;
-    }
-
-    init() {
-        this._socket = this._socketFactory();
-
-        this._socket.on('connect_error', () => {
-            this._scope.hasAgents = false;
-        });
-
-        this._socket.on('agent:count', ({count}) => {
-            this._scope.hasAgents = count > 0;
-
-            this.checkModal();
-
-            if (this._scope.hasAgents)
-                this._scope.$broadcast('agent:connected', true);
-        });
-
-        this._socket.on('disconnect', () => {
-            this._scope.hasAgents = false;
-
-            this.checkModal();
-        });
-    }
-
-    /**
-     * @param {Object} back
-     * @returns {Promise}
-     */
-    startWatch(back) {
-        this._scope.backState = back.state;
-        this._scope.backText = back.text;
-
-        this._scope.agentGoal = back.goal;
-
-        this._scope.showModal = true;
-
-        return this.awaitAgent();
-    }
-
-    /**
-     *
-     * @param {String} event
-     * @param {Object} [args]
-     * @returns {Promise}
-     * @private
-     */
-    _emit(event, ...args) {
-        if (!this._socket)
-            return this._$q.reject('Failed to connect to agent');
-
-        const latch = this._$q.defer();
-
-        const onDisconnect = () => {
-            this._socket.removeListener('disconnect', onDisconnect);
-
-            latch.reject('Connection to server was closed');
-        };
-
-        this._socket.on('disconnect', onDisconnect);
-
-        args.push((err, res) => {
-            this._socket.removeListener('disconnect', onDisconnect);
-
-            if (err)
-                latch.reject(err);
-
-            latch.resolve(res);
-        });
-
-        this._socket.emit(event, ...args);
-
-        return latch.promise;
-    }
-
-    drivers() {
-        return this._emit('schemaImport:drivers');
-    }
-
-    /**
-     *
-     * @param {Object} preset
-     * @returns {Promise}
-     */
-    schemas(preset) {
-        return this._emit('schemaImport:schemas', preset);
-    }
-
-    /**
-     *
-     * @param {Object} preset
-     * @returns {Promise}
-     */
-    tables(preset) {
-        return this._emit('schemaImport:tables', preset);
-    }
-
-    /**
-     * @param {String} errMsg
-     */
-    showNodeError(errMsg) {
-        this._downloadAgentModal.show();
-
-        this._$common.showError(errMsg);
-    }
-
-    /**
-     *
-     * @param {String} event
-     * @param {Object} [args]
-     * @returns {Promise}
-     * @private
-     */
-    _rest(event, ...args) {
-        return this._downloadAgentModal.$promise
-            .then(() => this._emit(event, ...args));
-    }
-
-    /**
-     * @param {Boolean} [attr]
-     * @param {Boolean} [mtr]
-     * @returns {Promise}
-     */
-    topology(attr, mtr) {
-        return this._rest('node:topology', !!attr, !!mtr);
-    }
-
-    /**
-     * @param {int} [queryId]
-     * @returns {Promise}
-     */
-    queryClose(queryId) {
-        return this._rest('node:query:close', queryId);
-    }
-
-    /**
-     * @param {String} cacheName Cache name.
-     * @param {int} pageSize
-     * @param {String} [query] Query if null then scan query.
-     * @returns {Promise}
-     */
-    query(cacheName, pageSize, query) {
-        return this._rest('node:query', _.isEmpty(cacheName) ? null : cacheName, pageSize, query);
-    }
-
-    /**
-     * @param {String} cacheName Cache name.
-     * @param {String} [query] Query if null then scan query.
-     * @returns {Promise}
-     */
-    queryGetAll(cacheName, query) {
-        return this._rest('node:query:getAll', _.isEmpty(cacheName) ? null : cacheName, query);
-    }
-
-    /**
-     * @param {String} [cacheName] Cache name.
-     * @returns {Promise}
-     */
-    metadata(cacheName) {
-        return this._rest('node:cache:metadata', _.isEmpty(cacheName) ? null : cacheName);
-    }
-
-    /**
-     * @param {int} queryId
-     * @param {int} pageSize
-     * @returns {Promise}
-     */
-    next(queryId, pageSize) {
-        return this._rest('node:query:fetch', queryId, pageSize);
-    }
-
-    collect() {
-        return this._rest('node:visor:collect', this._evtOrderKey, this._evtThrottleCntrKey);
-    }
-
-    /**
-     * Clear specified cache on specified node.
-     * @param {String} nid Node id.
-     * @param {String} cacheName Cache name.
-     * @returns {Promise}
-     */
-    cacheClear(nid, cacheName) {
-        return this._rest('node:cache:clear', nid, cacheName);
-    }
-
-    /**
-     * Stop specified cache on specified node.
-     * @param {String} nid Node id.
-     * @param {String} cacheName Cache name.
-     * @returns {Promise}
-     */
-    cacheStop(nid, cacheName) {
-        return this._rest('node:cache:stop', nid, cacheName);
-    }
-
-    /**
-     * Ping node.
-     * @param {String} nid Node id.
-     * @returns {Promise}
-     */
-    ping(nid) {
-        return this._rest('node:ping', nid);
-    }
-
-    stopWatch() {
-        this._scope.showModal = false;
-
-        this.checkModal();
-
-        this._scope.$broadcast('agent:connected', false);
-    }
-}
-
-IgniteAgentMonitor.$inject = ['igniteSocketFactory', '$rootScope', '$q', '$state', '$modal', '$common'];
-
-export default ['IgniteAgentMonitor', IgniteAgentMonitor];

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/app/services/cleanup.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/cleanup.service.js b/modules/web-console/src/main/js/app/services/cleanup.service.js
index 380beda..bec9ea3 100644
--- a/modules/web-console/src/main/js/app/services/cleanup.service.js
+++ b/modules/web-console/src/main/js/app/services/cleanup.service.js
@@ -32,7 +32,9 @@ export default ['$cleanup', () => {
                     dist[key] = attr;
                 }
             });
-        } else if ((_.isString(original) && original.length) || _.isNumber(original) || _.isBoolean(original))
+        } else if (_.isBoolean(original) && original === true)
+            dist = original;
+        else if ((_.isString(original) && original.length) || _.isNumber(original))
             dist = original;
         else if (_.isArray(original) && original.length)
             dist = _.map(original, (value) => cleanup(value, {}));

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/build/system.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/build/system.config.js b/modules/web-console/src/main/js/build/system.config.js
index edd9e9e..20af865 100644
--- a/modules/web-console/src/main/js/build/system.config.js
+++ b/modules/web-console/src/main/js/build/system.config.js
@@ -18,15 +18,15 @@ System.config({
     "angular": "github:angular/bower-angular@1.5.5",
     "angular-animate": "github:angular/bower-angular-animate@1.5.5",
     "angular-drag-and-drop-lists": "github:marceljuenemann/angular-drag-and-drop-lists@1.4.0",
-    "angular-gridster": "github:ManifestWebDesign/angular-gridster@0.13.5",
+    "angular-gridster": "github:ManifestWebDesign/angular-gridster@0.13.9",
     "angular-motion": "github:mgcrea/angular-motion@0.4.4",
-    "angular-nvd3": "github:krispo/angular-nvd3@1.0.6",
+    "angular-nvd3": "github:krispo/angular-nvd3@1.0.7",
     "angular-retina": "github:jrief/angular-retina@0.3.8",
     "angular-sanitize": "github:angular/bower-angular-sanitize@1.5.5",
     "angular-smart-table": "github:lorenzofox3/Smart-Table@2.1.8",
     "angular-socket-io": "github:btford/angular-socket-io@0.7.0",
     "angular-strap": "github:mgcrea/angular-strap@2.3.8",
-    "angular-tree-control": "github:wix/angular-tree-control@0.2.25",
+    "angular-tree-control": "github:wix/angular-tree-control@0.2.26",
     "angular-ui-grid": "github:angular-ui/bower-ui-grid@3.1.1",
     "angular-ui-router": "github:angular-ui/ui-router@0.2.18",
     "angular-ui-router-metatags": "github:tinusn/ui-router-metatags@1.0.3",
@@ -39,11 +39,11 @@ System.config({
     "css": "github:systemjs/plugin-css@0.1.21",
     "file-saver": "github:eligrey/FileSaver.js@master",
     "font-awesome": "npm:font-awesome@4.5.0",
-    "jade": "github:johnsoftek/plugin-jade@0.6.0",
+    "jade": "github:johnsoftek/plugin-jade@0.6.3",
     "jquery": "github:components/jquery@2.2.1",
-    "json": "github:systemjs/plugin-json@0.1.0",
+    "json": "github:systemjs/plugin-json@0.1.2",
     "jszip": "github:Stuk/jszip@2.6.0",
-    "lodash": "github:lodash/lodash@4.11.1",
+    "lodash": "github:lodash/lodash@4.13.0",
     "pdfmake": "github:bpampuch/pdfmake@0.1.20",
     "query-command-supported": "github:zenorocha/document.queryCommandSupported@1.0.0",
     "socket.io-client": "github:socketio/socket.io-client@1.4.5",
@@ -69,12 +69,11 @@ System.config({
     "github:eligrey/FileSaver.js@master": {
       "blob": "github:eligrey/Blob.js@master"
     },
-    "github:johnsoftek/plugin-jade@0.6.0": {
-      "jade-compiler": "npm:jade@1.11.0",
-      "text": "github:systemjs/plugin-text@0.0.4"
+    "github:johnsoftek/plugin-jade@0.6.3": {
+      "jade-compiler": "npm:jade@1.11.0"
     },
     "github:jspm/nodelibs-assert@0.1.0": {
-      "assert": "npm:assert@1.3.0"
+      "assert": "npm:assert@1.4.0"
     },
     "github:jspm/nodelibs-buffer@0.1.0": {
       "buffer": "npm:buffer@3.6.0"
@@ -100,7 +99,7 @@ System.config({
       "path-browserify": "npm:path-browserify@0.0.0"
     },
     "github:jspm/nodelibs-process@0.1.2": {
-      "process": "npm:process@0.11.2"
+      "process": "npm:process@0.11.3"
     },
     "github:jspm/nodelibs-stream@0.1.0": {
       "stream-browserify": "npm:stream-browserify@1.0.0"
@@ -117,7 +116,7 @@ System.config({
     "github:jspm/nodelibs-vm@0.1.0": {
       "vm-browserify": "npm:vm-browserify@0.0.4"
     },
-    "github:krispo/angular-nvd3@1.0.6": {
+    "github:krispo/angular-nvd3@1.0.7": {
       "d3": "npm:d3@3.5.14",
       "nvd3": "npm:nvd3@1.8.1"
     },
@@ -132,7 +131,7 @@ System.config({
       "angular-sanitize": "github:angular/bower-angular-sanitize@1.5.5"
     },
     "github:twbs/bootstrap@3.3.6": {
-      "jquery": "npm:jquery@2.2.3"
+      "jquery": "npm:jquery@2.2.4"
     },
     "npm:acorn-globals@1.0.9": {
       "acorn": "npm:acorn@2.7.0"
@@ -150,7 +149,7 @@ System.config({
       "stream": "github:jspm/nodelibs-stream@0.1.0"
     },
     "npm:align-text@0.1.4": {
-      "kind-of": "npm:kind-of@3.0.2",
+      "kind-of": "npm:kind-of@3.0.3",
       "longest": "npm:longest@1.0.1",
       "repeat-string": "npm:repeat-string@1.5.4"
     },
@@ -163,7 +162,11 @@ System.config({
     "npm:asap@1.0.0": {
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
-    "npm:assert@1.3.0": {
+    "npm:assert@1.4.0": {
+      "assert": "github:jspm/nodelibs-assert@0.1.0",
+      "buffer": "github:jspm/nodelibs-buffer@0.1.0",
+      "buffer-shims": "npm:buffer-shims@1.0.0",
+      "process": "github:jspm/nodelibs-process@0.1.2",
       "util": "npm:util@0.10.3"
     },
     "npm:async@0.2.10": {
@@ -172,6 +175,9 @@ System.config({
     "npm:babel-runtime@5.8.38": {
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
+    "npm:buffer-shims@1.0.0": {
+      "buffer": "github:jspm/nodelibs-buffer@0.1.0"
+    },
     "npm:buffer@3.6.0": {
       "base64-js": "npm:base64-js@0.0.8",
       "child_process": "github:jspm/nodelibs-child_process@0.1.0",
@@ -182,7 +188,7 @@ System.config({
     },
     "npm:center-align@0.1.3": {
       "align-text": "npm:align-text@0.1.4",
-      "lazy-cache": "npm:lazy-cache@1.0.3"
+      "lazy-cache": "npm:lazy-cache@1.0.4"
     },
     "npm:clean-css@3.4.12": {
       "buffer": "github:jspm/nodelibs-buffer@0.1.0",
@@ -223,7 +229,7 @@ System.config({
       "fs": "github:jspm/nodelibs-fs@0.1.2",
       "path": "github:jspm/nodelibs-path@0.1.0",
       "process": "github:jspm/nodelibs-process@0.1.2",
-      "systemjs-json": "github:systemjs/plugin-json@0.1.0"
+      "systemjs-json": "github:systemjs/plugin-json@0.1.2"
     },
     "npm:core-util-is@1.0.2": {
       "buffer": "github:jspm/nodelibs-buffer@0.1.0"
@@ -250,6 +256,9 @@ System.config({
     "npm:is-buffer@1.1.3": {
       "buffer": "github:jspm/nodelibs-buffer@0.1.0"
     },
+    "npm:isarray@1.0.0": {
+      "systemjs-json": "github:systemjs/plugin-json@0.1.2"
+    },
     "npm:jade@1.11.0": {
       "buffer": "github:jspm/nodelibs-buffer@0.1.0",
       "character-parser": "npm:character-parser@1.2.1",
@@ -260,7 +269,7 @@ System.config({
       "mkdirp": "npm:mkdirp@0.5.1",
       "path": "github:jspm/nodelibs-path@0.1.0",
       "process": "github:jspm/nodelibs-process@0.1.2",
-      "systemjs-json": "github:systemjs/plugin-json@0.1.0",
+      "systemjs-json": "github:systemjs/plugin-json@0.1.2",
       "transformers": "npm:transformers@2.1.0",
       "uglify-js": "npm:uglify-js@2.6.2",
       "void-elements": "npm:void-elements@2.0.1",
@@ -272,11 +281,11 @@ System.config({
       "is-promise": "npm:is-promise@2.1.0",
       "promise": "npm:promise@6.1.0"
     },
-    "npm:kind-of@3.0.2": {
+    "npm:kind-of@3.0.3": {
       "buffer": "github:jspm/nodelibs-buffer@0.1.0",
       "is-buffer": "npm:is-buffer@1.1.3"
     },
-    "npm:lazy-cache@1.0.3": {
+    "npm:lazy-cache@1.0.4": {
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
     "npm:mkdirp@0.5.1": {
@@ -299,7 +308,7 @@ System.config({
     "npm:path-browserify@0.0.0": {
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
-    "npm:process@0.11.2": {
+    "npm:process@0.11.3": {
       "assert": "github:jspm/nodelibs-assert@0.1.0"
     },
     "npm:promise@2.0.0": {
@@ -335,7 +344,7 @@ System.config({
       "amdefine": "npm:amdefine@1.0.0",
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
-    "npm:source-map@0.5.3": {
+    "npm:source-map@0.5.6": {
       "process": "github:jspm/nodelibs-process@0.1.2"
     },
     "npm:stream-browserify@1.0.0": {
@@ -369,7 +378,7 @@ System.config({
       "fs": "github:jspm/nodelibs-fs@0.1.2",
       "path": "github:jspm/nodelibs-path@0.1.0",
       "process": "github:jspm/nodelibs-process@0.1.2",
-      "source-map": "npm:source-map@0.5.3",
+      "source-map": "npm:source-map@0.5.6",
       "uglify-to-browserify": "npm:uglify-to-browserify@1.0.2",
       "yargs": "npm:yargs@3.10.0"
     },

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/admin-controller.js b/modules/web-console/src/main/js/controllers/admin-controller.js
index 5abee04..f46bab0 100644
--- a/modules/web-console/src/main/js/controllers/admin-controller.js
+++ b/modules/web-console/src/main/js/controllers/admin-controller.js
@@ -32,21 +32,21 @@ consoleModule.controller('adminController', [
                         user.userName = user.firstName + ' ' + user.lastName;
                         user.countryCode = Countries.getByName(user.country).code;
                         user.label = user.userName + ' ' + user.email + ' ' +
-                            (user.company || '') + ' ' + (user.country || '');
-                    })
+                            (user.company || '') + ' ' + (user.countryCode || '');
+                    });
                 })
                 .catch((err) => $common.showError(err));
         };
 
         _reloadUsers();
 
-        $scope.becomeUser = function (user) {
+        $scope.becomeUser = function(user) {
             $http.get('/api/v1/admin/become', { params: {viewedUserId: user._id}})
                 .then(User.read)
-                .then((user) => {
-                    $rootScope.$broadcast('user', user);
+                .then((becomeUser) => {
+                    $rootScope.$broadcast('user', becomeUser);
 
-                    $state.go('base.configuration.clusters')
+                    $state.go('base.configuration.clusters');
                 })
                 .catch((errMsg) => $common.showError($common.errorMessage(errMsg)));
         };
@@ -64,7 +64,7 @@ consoleModule.controller('adminController', [
                             $common.showInfo('User has been removed: "' + user.userName + '"');
                         })
                         .error((errMsg, status) => {
-                            if (status == 503)
+                            if (status === 503)
                                 $common.showInfo(errMsg);
                             else
                                 $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"');

http://git-wip-us.apache.org/repos/asf/ignite/blob/541e17d0/modules/web-console/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/caches-controller.js b/modules/web-console/src/main/js/controllers/caches-controller.js
index 8f4bedd..ac4d951 100644
--- a/modules/web-console/src/main/js/controllers/caches-controller.js
+++ b/modules/web-console/src/main/js/controllers/caches-controller.js
@@ -20,14 +20,14 @@ import consoleModule from 'controllers/common-module';
 
 consoleModule.controller('cachesController', [
     '$scope', '$http', '$state', '$filter', '$timeout', '$common', '$confirm', '$clone', '$loading', '$cleanup', '$unsavedChangesGuard',
-    function ($scope, $http, $state, $filter, $timeout, $common, $confirm, $clone, $loading, $cleanup, $unsavedChangesGuard) {
+    function($scope, $http, $state, $filter, $timeout, $common, $confirm, $clone, $loading, $cleanup, $unsavedChangesGuard) {
         $unsavedChangesGuard.install($scope);
 
-        var emptyCache = {empty: true};
+        const emptyCache = {empty: true};
 
-        var __original_value;
+        let __original_value;
 
-        var blank = {
+        const blank = {
             evictionPolicy: {},
             cacheStoreFactory: {},
             nearConfiguration: {}
@@ -44,15 +44,15 @@ consoleModule.controller('cachesController', [
         $scope.saveBtnTipText = $common.saveBtnTipText;
         $scope.widthIsSufficient = $common.widthIsSufficient;
 
-        var showPopoverMessage = $common.showPopoverMessage;
+        const showPopoverMessage = $common.showPopoverMessage;
 
-        $scope.contentVisible = function () {
-            var item = $scope.backupItem;
+        $scope.contentVisible = function() {
+            const item = $scope.backupItem;
 
             return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
         };
 
-        $scope.toggleExpanded = function () {
+        $scope.toggleExpanded = function() {
             $scope.ui.expanded = !$scope.ui.expanded;
 
             $common.hidePopover();
@@ -71,10 +71,9 @@ consoleModule.controller('cachesController', [
         }
 
         function cacheDomains(item) {
-            return _.reduce($scope.domains, function (memo, domain) {
-                if (item && _.includes(item.domains, domain.value)) {
+            return _.reduce($scope.domains, function(memo, domain) {
+                if (item && _.includes(item.domains, domain.value))
                     memo.push(domain.meta);
-                }
 
                 return memo;
             }, []);
@@ -84,18 +83,15 @@ consoleModule.controller('cachesController', [
 
         // When landing on the page, get caches and show them.
         $http.post('/api/v1/configuration/caches/list')
-            .success(function (data) {
-                var validFilter = $filter('domainsValidation');
+            .success(function(data) {
+                const validFilter = $filter('domainsValidation');
 
                 $scope.spaces = data.spaces;
-
-                _.forEach(data.caches, function (cache) {
-                    cache.label = _cacheLbl(cache);
-                });
-
                 $scope.caches = data.caches;
 
-                $scope.clusters = _.map(data.clusters, function (cluster) {
+                _.forEach($scope.caches, (cache) => cache.label = _cacheLbl(cache));
+
+                $scope.clusters = _.map(data.clusters, function(cluster) {
                     return {
                         value: cluster._id,
                         label: cluster.name,
@@ -103,7 +99,7 @@ consoleModule.controller('cachesController', [
                     };
                 });
 
-                $scope.domains = _.sortBy(_.map(validFilter(data.domains, true, false), function (domain) {
+                $scope.domains = _.sortBy(_.map(validFilter(data.domains, true, false), function(domain) {
                     return {
                         value: domain._id,
                         label: domain.valueType,
@@ -112,13 +108,13 @@ consoleModule.controller('cachesController', [
                     };
                 }), 'label');
 
-                if ($state.params.id)
-                    $scope.createItem($state.params.id);
+                if ($state.params.linkId)
+                    $scope.createItem($state.params.linkId);
                 else {
-                    var lastSelectedCache = angular.fromJson(sessionStorage.lastSelectedCache);
+                    const lastSelectedCache = angular.fromJson(sessionStorage.lastSelectedCache);
 
                     if (lastSelectedCache) {
-                        var idx = _.findIndex($scope.caches, function (cache) {
+                        const idx = _.findIndex($scope.caches, function(cache) {
                             return cache._id === lastSelectedCache;
                         });
 
@@ -135,30 +131,29 @@ consoleModule.controller('cachesController', [
                 }
 
                 $scope.$watch('ui.inputForm.$valid', function(valid) {
-                    if (valid && __original_value === JSON.stringify($cleanup($scope.backupItem))) {
+                    if (valid && _.isEqual(__original_value, $cleanup($scope.backupItem)))
                         $scope.ui.inputForm.$dirty = false;
-                    }
                 });
 
-                $scope.$watch('backupItem', function (val) {
-                    var form = $scope.ui.inputForm;
+                $scope.$watch('backupItem', function(val) {
+                    const form = $scope.ui.inputForm;
 
-                    if (form.$pristine || (form.$valid && __original_value === JSON.stringify($cleanup(val))))
+                    if (form.$pristine || (form.$valid && _.isEqual(__original_value, $cleanup(val))))
                         form.$setPristine();
                     else
                         form.$setDirty();
                 }, true);
             })
-            .catch(function (errMsg) {
+            .catch(function(errMsg) {
                 $common.showError(errMsg);
             })
-            .finally(function () {
+            .finally(function() {
                 $scope.ui.ready = true;
                 $scope.ui.inputForm.$setPristine();
                 $loading.finish('loadingCachesScreen');
             });
 
-        $scope.selectItem = function (item, backup) {
+        $scope.selectItem = function(item, backup) {
             function selectItem() {
                 $scope.selectedItem = item;
 
@@ -181,7 +176,7 @@ consoleModule.controller('cachesController', [
 
                 $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
 
-                __original_value = JSON.stringify($cleanup($scope.backupItem));
+                __original_value = $cleanup($scope.backupItem);
 
                 if ($common.getQueryVariable('new'))
                     $state.go('base.configuration.caches');
@@ -190,44 +185,49 @@ consoleModule.controller('cachesController', [
             $common.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
         };
 
-        function prepareNewItem(id) {
+        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+        function prepareNewItem(linkId) {
             return {
                 space: $scope.spaces[0]._id,
                 cacheMode: 'PARTITIONED',
                 atomicityMode: 'ATOMIC',
                 readFromBackup: true,
                 copyOnRead: true,
-                clusters: id && _.find($scope.clusters, {value: id})
-                    ? [id] : _.map($scope.clusters, function (cluster) { return cluster.value; }),
-                domains: id && _.find($scope.domains, { value: id }) ? [id] : [],
+                clusters: linkId && _.find($scope.clusters, {value: linkId})
+                    ? [linkId] : _.map($scope.clusters, function(cluster) { return cluster.value; }),
+                domains: linkId && _.find($scope.domains, { value: linkId }) ? [linkId] : [],
                 cacheStoreFactory: {CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}}
             };
         }
 
         // Add new cache.
-        $scope.createItem = function (id) {
-            $timeout(function () {
-                $common.ensureActivePanel($scope.ui, 'general', 'cacheName');
-            });
+        $scope.createItem = function(linkId) {
+            $timeout(() => $common.ensureActivePanel($scope.ui, 'general', 'cacheName'));
 
-            $scope.selectItem(undefined, prepareNewItem(id));
+            $scope.selectItem(null, prepareNewItem(linkId));
         };
 
-        function checkDataSources() {
-            var clusters = _.filter($scope.clusters, function (cluster) {
-                return _.includes($scope.backupItem.clusters, cluster.value);
-            });
+        function cacheClusters() {
+            return _.filter($scope.clusters, (cluster) => _.includes($scope.backupItem.clusters, cluster.value));
+        }
 
-            var checkRes = { checked: true };
+        function clusterCaches(cluster) {
+            const caches = _.filter($scope.caches,
+                (cache) => cache._id !== $scope.backupItem._id && _.includes(cluster.caches, cache._id));
 
-            var failCluster = _.find(clusters, function (cluster) {
-                var caches = _.filter($scope.caches, function (cache) {
-                    return cache._id !== $scope.backupItem._id && _.find(cluster.caches, function (clusterCache) {
-                        return clusterCache === cache._id;
-                    });
-                });
+            caches.push($scope.backupItem);
 
-                caches.push($scope.backupItem);
+            return caches;
+        }
+
+        function checkDataSources() {
+            const clusters = cacheClusters();
+
+            let checkRes = {checked: true};
+
+            const failCluster = _.find(clusters, (cluster) => {
+                const caches = clusterCaches(cluster);
 
                 checkRes = $common.checkCachesDataSources(caches, $scope.backupItem);
 
@@ -245,129 +245,88 @@ consoleModule.controller('cachesController', [
             return true;
         }
 
-        // Check cache logical consistency.
-        function validate(item) {
-            $common.hidePopover();
-
-            if ($common.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Cache name should not be empty!');
-
-            if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !$common.isDefined(item.evictionPolicy.kind))
-                return showPopoverMessage($scope.ui, 'memory', 'evictionPolicyKind', 'Eviction policy should not be configured!');
+        function checkSQLSchemas() {
+            const clusters = cacheClusters();
 
-            var form = $scope.ui.inputForm;
-            var errors = form.$error;
-            var errKeys = Object.keys(errors);
+            let checkRes = {checked: true};
 
-            if (errKeys && errKeys.length > 0) {
-                var firstErrorKey = errKeys[0];
+            const failCluster = _.find(clusters, (cluster) => {
+                const caches = clusterCaches(cluster);
 
-                var firstError = errors[firstErrorKey][0];
-                var actualError = firstError.$error[firstErrorKey][0];
+                checkRes = $common.checkCacheSQLSchemas(caches, $scope.backupItem);
 
-                var errNameFull = actualError.$name;
-                var errNameShort = errNameFull;
+                return !checkRes.checked;
+            });
 
-                if (errNameShort.endsWith('TextInput'))
-                    errNameShort = errNameShort.substring(0, errNameShort.length - 9);
+            if (!checkRes.checked) {
+                return showPopoverMessage($scope.ui, 'query', 'sqlSchema',
+                    'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
+                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"', 10000);
+            }
 
-                var extractErrorMessage = function (errName) {
-                    try {
-                        return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
-                    }
-                    catch(ignored) {
-                        try {
-                            msg = form[firstError.$name].$errorMessages[errName][firstErrorKey];
-                        }
-                        catch(ignited) {
-                            return false;
-                        }
-                    }
-                };
+            return true;
+        }
 
-                var msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!';
+        function checkStoreFactoryBean(storeFactory, beanFieldId) {
+            if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, beanFieldId, $scope.ui, 'store'))
+                return false;
 
-                return showPopoverMessage($scope.ui, firstError.$name, errNameFull, msg);
-            }
+            return checkDataSources();
+        }
 
-            if (item.memoryMode === 'OFFHEAP_VALUES' && !_.isEmpty(item.domains))
-                return showPopoverMessage($scope.ui, 'memory', 'memoryMode',
-                    'Query indexing could not be enabled while values are stored off-heap!');
+        function checkStoreFactory(item) {
+            const cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
 
-            if (item.memoryMode === 'OFFHEAP_TIERED' && !$common.isDefined(item.offHeapMaxMemory))
-                return showPopoverMessage($scope.ui, 'memory', 'offHeapMaxMemory',
-                    'Off-heap max memory should be specified!');
+            if (cacheStoreFactorySelected) {
+                const storeFactory = item.cacheStoreFactory[item.cacheStoreFactory.kind];
 
-            var cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
+                if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' && !checkStoreFactoryBean(storeFactory, 'pojoDataSourceBean'))
+                    return false;
 
-            if (cacheStoreFactorySelected) {
-                var storeFactory = item.cacheStoreFactory[item.cacheStoreFactory.kind];
+                if (item.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory' && storeFactory.connectVia !== 'URL'
+                    && !checkStoreFactoryBean(storeFactory, 'blobDataSourceBean'))
+                    return false;
+            }
 
-                if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory') {
-                    if ($common.isEmptyString(storeFactory.dataSourceBean))
-                        return showPopoverMessage($scope.ui, 'store', 'dataSourceBean',
-                            'Data source bean name should not be empty!');
+            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
+                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!');
 
-                    if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.ui, 'store'))
-                        return false;
+            if (item.writeBehindEnabled && !cacheStoreFactorySelected)
+                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', 'Write behind enabled but store is not configured!');
 
-                    if (!storeFactory.dialect)
-                        return showPopoverMessage($scope.ui, 'store', 'pojoDialect',
-                            'Dialect should not be empty!');
+            if (cacheStoreFactorySelected && !item.readThrough && !item.writeThrough)
+                return showPopoverMessage($scope.ui, 'store', 'readThroughTooltip', 'Store is configured but read/write through are not enabled!');
 
-                    if (!checkDataSources())
-                        return false;
-                }
+            return true;
+        }
 
-                if (item.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory') {
-                    if (storeFactory.connectVia === 'URL') {
-                        if ($common.isEmptyString(storeFactory.connectionUrl))
-                            return showPopoverMessage($scope.ui, 'store', 'connectionUrl',
-                                'Connection URL should not be empty!');
+        // Check cache logical consistency.
+        function validate(item) {
+            $common.hidePopover();
 
-                        if ($common.isEmptyString(storeFactory.user))
-                            return showPopoverMessage($scope.ui, 'store', 'user',
-                                'User should not be empty!');
-                    }
-                    else {
-                        if ($common.isEmptyString(storeFactory.dataSourceBean))
-                            return showPopoverMessage($scope.ui, 'store', 'dataSourceBean',
-                                'Data source bean name should not be empty!');
+            if ($common.isEmptyString(item.name))
+                return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Cache name should not be empty!');
 
-                        if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, 'dataSourceBean', $scope.ui, 'store'))
-                            return false;
+            if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !$common.isDefined(item.evictionPolicy.kind))
+                return showPopoverMessage($scope.ui, 'memory', 'evictionPolicyKind', 'Eviction policy should not be configured!');
 
-                        if (!storeFactory.dialect)
-                            return showPopoverMessage($scope.ui, 'store', 'blobDialect',
-                                'Database should not be empty!');
+            if (!$common.checkFieldValidators($scope.ui))
+                return false;
 
-                        if (!checkDataSources())
-                            return false;
-                    }
-                }
-            }
+            if (item.memoryMode === 'OFFHEAP_VALUES' && !_.isEmpty(item.domains))
+                return showPopoverMessage($scope.ui, 'memory', 'memoryMode', 'Query indexing could not be enabled while values are stored off-heap!');
 
-            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory',
-                    (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!');
+            if (item.memoryMode === 'OFFHEAP_TIERED' && (!$common.isDefined(item.offHeapMaxMemory) || item.offHeapMaxMemory < 0))
+                return showPopoverMessage($scope.ui, 'memory', 'offHeapMaxMemory', 'Off-heap max memory should be specified!');
 
-            if (item.writeBehindEnabled && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory',
-                    'Write behind enabled but store is not configured!');
+            if (!checkSQLSchemas())
+                return false;
 
-            if (cacheStoreFactorySelected) {
-                if (!item.readThrough && !item.writeThrough)
-                    return showPopoverMessage($scope.ui, 'store', 'readThroughTooltip',
-                        'Store is configured but read/write through are not enabled!');
-            }
+            if (!checkStoreFactory(item))
+                return false;
 
             if (item.writeBehindFlushSize === 0 && item.writeBehindFlushFrequency === 0)
-                return showPopoverMessage($scope.ui, 'store', 'writeBehindFlushSize',
-                    'Both "Flush frequency" and "Flush size" are not allowed as 0!');
-
-            if (item.cacheMode !== 'LOCAL' && item.rebalanceMode !== 'NONE' && item.rebalanceBatchSize === 0)
-                return showPopoverMessage($scope.ui, 'rebalance', 'rebalanceBatchSize',
-                    'Batch size should be more than 0 if rebalance mode is "SYNC" or "ASYNC" !', 10000);
+                return showPopoverMessage($scope.ui, 'store', 'writeBehindFlushSize', 'Both "Flush frequency" and "Flush size" are not allowed as 0!');
 
             return true;
         }
@@ -375,12 +334,12 @@ consoleModule.controller('cachesController', [
         // Save cache in database.
         function save(item) {
             $http.post('/api/v1/configuration/caches/save', item)
-                .success(function (_id) {
+                .success(function(_id) {
                     item.label = _cacheLbl(item);
 
                     $scope.ui.inputForm.$setPristine();
 
-                    var idx = _.findIndex($scope.caches, function (cache) {
+                    const idx = _.findIndex($scope.caches, function(cache) {
                         return cache._id === _id;
                     });
 
@@ -391,18 +350,32 @@ consoleModule.controller('cachesController', [
                         $scope.caches.push(item);
                     }
 
+                    _.forEach($scope.clusters, (cluster) => {
+                        if (_.includes(item.clusters, cluster.value))
+                            cluster.caches = _.union(cluster.caches, [_id]);
+                        else
+                            _.remove(cluster.caches, (id) => id === _id);
+                    });
+
+                    _.forEach($scope.domains, (domain) => {
+                        if (_.includes(item.domains, domain.value))
+                            domain.meta.caches = _.union(domain.meta.caches, [_id]);
+                        else
+                            _.remove(domain.meta.caches, (id) => id === _id);
+                    });
+
                     $scope.selectItem(item);
 
                     $common.showInfo('Cache "' + item.name + '" saved.');
                 })
-                .error(function (errMsg) {
+                .error(function(errMsg) {
                     $common.showError(errMsg);
                 });
         }
 
         // Save cache.
-        $scope.saveItem = function () {
-            var item = $scope.backupItem;
+        $scope.saveItem = function() {
+            const item = $scope.backupItem;
 
             angular.extend(item, $common.autoCacheStoreConfiguration(item, cacheDomains(item)));
 
@@ -411,41 +384,43 @@ consoleModule.controller('cachesController', [
         };
 
         function _cacheNames() {
-            return _.map($scope.caches, function (cache) {
+            return _.map($scope.caches, function(cache) {
                 return cache.name;
             });
         }
 
         // Clone cache with new name.
-        $scope.cloneItem = function () {
+        $scope.cloneItem = function() {
             if (validate($scope.backupItem)) {
-                $clone.confirm($scope.backupItem.name, _cacheNames()).then(function (newName) {
-                    var item = angular.copy($scope.backupItem);
+                $clone.confirm($scope.backupItem.name, _cacheNames()).then(function(newName) {
+                    const item = angular.copy($scope.backupItem);
 
                     delete item._id;
 
                     item.name = newName;
 
+                    delete item.sqlSchema;
+
                     save(item);
                 });
             }
         };
 
         // Remove cache from db.
-        $scope.removeItem = function () {
-            var selectedItem = $scope.selectedItem;
+        $scope.removeItem = function() {
+            const selectedItem = $scope.selectedItem;
 
             $confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?')
-                .then(function () {
-                    var _id = selectedItem._id;
+                .then(function() {
+                    const _id = selectedItem._id;
 
-                    $http.post('/api/v1/configuration/caches/remove', {_id: _id})
-                        .success(function () {
+                    $http.post('/api/v1/configuration/caches/remove', {_id})
+                        .success(function() {
                             $common.showInfo('Cache has been removed: ' + selectedItem.name);
 
-                            var caches = $scope.caches;
+                            const caches = $scope.caches;
 
-                            var idx = _.findIndex(caches, function (cache) {
+                            const idx = _.findIndex(caches, function(cache) {
                                 return cache._id === _id;
                             });
 
@@ -454,37 +429,46 @@ consoleModule.controller('cachesController', [
 
                                 if (caches.length > 0)
                                     $scope.selectItem(caches[0]);
-                                else
+                                else {
                                     $scope.backupItem = emptyCache;
+                                    $scope.ui.inputForm.$setPristine();
+                                }
+
+                                _.forEach($scope.clusters, (cluster) => _.remove(cluster.caches, (id) => id === _id));
+                                _.forEach($scope.domains, (domain) => _.remove(domain.meta.caches, (id) => id === _id));
                             }
                         })
-                        .error(function (errMsg) {
+                        .error(function(errMsg) {
                             $common.showError(errMsg);
                         });
                 });
         };
 
         // Remove all caches from db.
-        $scope.removeAllItems = function () {
+        $scope.removeAllItems = function() {
             $confirm.confirm('Are you sure you want to remove all caches?')
-                .then(function () {
+                .then(function() {
                     $http.post('/api/v1/configuration/caches/remove/all')
-                        .success(function () {
+                        .success(function() {
                             $common.showInfo('All caches have been removed');
 
                             $scope.caches = [];
+
+                            _.forEach($scope.clusters, (cluster) => cluster.caches = []);
+                            _.forEach($scope.domains, (domain) => domain.meta.caches = []);
+
                             $scope.backupItem = emptyCache;
                             $scope.ui.inputForm.$setPristine();
                         })
-                        .error(function (errMsg) {
+                        .error(function(errMsg) {
                             $common.showError(errMsg);
                         });
                 });
         };
 
-        $scope.resetAll = function () {
+        $scope.resetAll = function() {
             $confirm.confirm('Are you sure you want to undo all changes for current cache?')
-                .then(function () {
+                .then(function() {
                     $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
                     $scope.ui.inputForm.$setPristine();
                 });