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/09/28 02:26:42 UTC

[02/18] ignite git commit: Web console beta-4.

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/backend/test/unit/ClusterService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/ClusterService.test.js b/modules/web-console/backend/test/unit/ClusterService.test.js
index ab0e912..aff54f7 100644
--- a/modules/web-console/backend/test/unit/ClusterService.test.js
+++ b/modules/web-console/backend/test/unit/ClusterService.test.js
@@ -15,11 +15,10 @@
  * limitations under the License.
  */
 
-
-import {assert} from 'chai';
-import injector from '../injector';
-import testClusters from '../data/clusters.json';
-import testAccounts from '../data/accounts.json';
+const assert = require('chai').assert;
+const injector = require('../injector');
+const testClusters = require('../data/clusters.json');
+const testAccounts = require('../data/accounts.json');
 
 let clusterService;
 let mongo;
@@ -78,7 +77,7 @@ suite('ClusterServiceTestsSuite', () => {
 
         clusterService.merge(testClusters[0])
             .then((cluster) => {
-                const clusterBeforeMerge = {...testClusters[0], _id: cluster._id, name: newName};
+                const clusterBeforeMerge = Object.assign({}, testClusters[0], {_id: cluster._id, name: newName});
 
                 return clusterService.merge(clusterBeforeMerge);
             })
@@ -91,8 +90,10 @@ suite('ClusterServiceTestsSuite', () => {
     });
 
     test('Create duplicated cluster', (done) => {
+        const dupleCluster = Object.assign({}, testClusters[0], {_id: null});
+
         clusterService.merge(testClusters[0])
-            .then(() => clusterService.merge(testClusters[0]))
+            .then(() => clusterService.merge(dupleCluster))
             .catch((err) => {
                 assert.instanceOf(err, errors.DuplicateKeyException);
 
@@ -143,7 +144,7 @@ suite('ClusterServiceTestsSuite', () => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
                 const currentUser = accounts[0];
-                const userCluster = {...testClusters[0], space: spaces[0][0]._id};
+                const userCluster = Object.assign({}, testClusters[0], {space: spaces[0][0]._id});
 
                 return clusterService.merge(userCluster)
                     .then(() => clusterService.removeAll(currentUser._id, false));
@@ -158,7 +159,7 @@ suite('ClusterServiceTestsSuite', () => {
     test('Get all clusters by space', (done) => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
-                const userCluster = {...testClusters[0], space: spaces[0][0]._id};
+                const userCluster = Object.assign({}, testClusters[0], {space: spaces[0][0]._id});
 
                 return clusterService.merge(userCluster)
                     .then((existCluster) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/backend/test/unit/DomainService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/DomainService.test.js b/modules/web-console/backend/test/unit/DomainService.test.js
index 477b454..8ce3fef 100644
--- a/modules/web-console/backend/test/unit/DomainService.test.js
+++ b/modules/web-console/backend/test/unit/DomainService.test.js
@@ -15,11 +15,10 @@
  * limitations under the License.
  */
 
-
-import {assert} from 'chai';
-import injector from '../injector';
-import testDomains from '../data/domains.json';
-import testAccounts from '../data/accounts.json';
+const assert = require('chai').assert;
+const injector = require('../injector');
+const testDomains = require('../data/domains.json');
+const testAccounts = require('../data/accounts.json');
 
 let domainService;
 let mongo;
@@ -82,7 +81,7 @@ suite('DomainsServiceTestsSuite', () => {
             .then((results) => {
                 const domain = results.savedDomains[0];
 
-                const domainBeforeMerge = {...testDomains[0], _id: domain._id, valueType: newValType};
+                const domainBeforeMerge = Object.assign({}, testDomains[0], {_id: domain._id, valueType: newValType});
 
                 return domainService.batchMerge([domainBeforeMerge]);
             })
@@ -95,8 +94,10 @@ suite('DomainsServiceTestsSuite', () => {
     });
 
     test('Create duplicated domain', (done) => {
+        const dupleDomain = Object.assign({}, testDomains[0], {_id: null});
+
         domainService.batchMerge([testDomains[0]])
-            .then(() => domainService.batchMerge([testDomains[0]]))
+            .then(() => domainService.batchMerge([dupleDomain]))
             .catch((err) => {
                 assert.instanceOf(err, errors.DuplicateKeyException);
 
@@ -149,7 +150,7 @@ suite('DomainsServiceTestsSuite', () => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
                 const currentUser = accounts[0];
-                const userDomain = {...testDomains[0], space: spaces[0][0]._id};
+                const userDomain = Object.assign({}, testDomains[0], {space: spaces[0][0]._id});
 
                 return domainService.batchMerge([userDomain])
                     .then(() => domainService.removeAll(currentUser._id, false));
@@ -164,7 +165,7 @@ suite('DomainsServiceTestsSuite', () => {
     test('Get all domains by space', (done) => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
-                const userDomain = {...testDomains[0], space: spaces[0][0]._id};
+                const userDomain = Object.assign({}, testDomains[0], {space: spaces[0][0]._id});
 
                 return domainService.batchMerge([userDomain])
                     .then((results) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/backend/test/unit/IgfsService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/IgfsService.test.js b/modules/web-console/backend/test/unit/IgfsService.test.js
index 3d78148..4fab279 100644
--- a/modules/web-console/backend/test/unit/IgfsService.test.js
+++ b/modules/web-console/backend/test/unit/IgfsService.test.js
@@ -15,11 +15,10 @@
  * limitations under the License.
  */
 
-
-import {assert} from 'chai';
-import injector from '../injector';
-import testIgfss from '../data/igfss.json';
-import testAccounts from '../data/accounts.json';
+const assert = require('chai').assert;
+const injector = require('../injector');
+const testIgfss = require('../data/igfss.json');
+const testAccounts = require('../data/accounts.json');
 
 let igfsService;
 let mongo;
@@ -78,7 +77,7 @@ suite('IgfsServiceTestsSuite', () => {
 
         igfsService.merge(testIgfss[0])
             .then((existIgfs) => {
-                const igfsBeforeMerge = {...testIgfss[0], _id: existIgfs._id, name: newName};
+                const igfsBeforeMerge = Object.assign({}, testIgfss[0], {_id: existIgfs._id, name: newName});
 
                 return igfsService.merge(igfsBeforeMerge);
             })
@@ -91,8 +90,10 @@ suite('IgfsServiceTestsSuite', () => {
     });
 
     test('Create duplicated igfs', (done) => {
+        const dupleIfgs = Object.assign({}, testIgfss[0], {_id: null});
+
         igfsService.merge(testIgfss[0])
-            .then(() => igfsService.merge(testIgfss[0]))
+            .then(() => igfsService.merge(dupleIfgs))
             .catch((err) => {
                 assert.instanceOf(err, errors.DuplicateKeyException);
 
@@ -143,7 +144,7 @@ suite('IgfsServiceTestsSuite', () => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
                 const currentUser = accounts[0];
-                const userIgfs = {...testIgfss[0], space: spaces[0][0]._id};
+                const userIgfs = Object.assign({}, testIgfss[0], {space: spaces[0][0]._id});
 
                 return igfsService.merge(userIgfs)
                     .then(() => igfsService.removeAll(currentUser._id, false));
@@ -158,7 +159,7 @@ suite('IgfsServiceTestsSuite', () => {
     test('Get all igfss by space', (done) => {
         prepareUserSpaces()
             .then(([accounts, spaces]) => {
-                const userIgfs = {...testIgfss[0], space: spaces[0][0]._id};
+                const userIgfs = Object.assign({}, testIgfss[0], {space: spaces[0][0]._id});
 
                 return igfsService.merge(userIgfs)
                     .then((existIgfs) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/app.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.config.js b/modules/web-console/frontend/app/app.config.js
index 25c24b0..7adfc94 100644
--- a/modules/web-console/frontend/app/app.config.js
+++ b/modules/web-console/frontend/app/app.config.js
@@ -46,7 +46,7 @@ igniteConsoleCfg.config(['$popoverProvider', ($popoverProvider) => {
 igniteConsoleCfg.config(['$tooltipProvider', ($tooltipProvider) => {
     angular.extend($tooltipProvider.defaults, {
         container: 'body',
-        delay: 150,
+        delay: {show: 150, hide: 150},
         placement: 'right',
         html: 'true',
         trigger: 'click hover'

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js
index 45851a2..830d067 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -43,7 +43,6 @@ import './modules/navbar/navbar.module';
 import './modules/configuration/configuration.module';
 import './modules/getting-started/GettingStarted.provider';
 import './modules/dialog/dialog.module';
-import './modules/version/Version.provider';
 import './modules/ace.module';
 import './modules/socket.module';
 import './modules/loading/loading.module';
@@ -67,6 +66,7 @@ import igniteUiAcePojos from './directives/ui-ace-pojos/ui-ace-pojos.directive';
 import igniteUiAcePom from './directives/ui-ace-pom/ui-ace-pom.directive';
 import igniteUiAceTabs from './directives/ui-ace-tabs.directive';
 import igniteUiAceXml from './directives/ui-ace-xml/ui-ace-xml.directive';
+import igniteRetainSelection from './directives/retain-selection.directive';
 
 // Services.
 import ChartColors from './services/ChartColors.service';
@@ -75,19 +75,18 @@ import Confirm from './services/Confirm.service.js';
 import ConfirmBatch from './services/ConfirmBatch.service.js';
 import CopyToClipboard from './services/CopyToClipboard.service';
 import Countries from './services/Countries.service';
+import ErrorPopover from './services/ErrorPopover.service';
 import Focus from './services/Focus.service';
+import FormUtils from './services/FormUtils.service';
 import InetAddress from './services/InetAddress.service';
 import JavaTypes from './services/JavaTypes.service';
-import Messages from './services/Messages.service';
-import ModelNormalizer from './services/ModelNormalizer.service.js';
+import SqlTypes from './services/SqlTypes.service';
 import LegacyTable from './services/LegacyTable.service';
-import ErrorPopover from './services/ErrorPopover.service';
-import FormUtils from './services/FormUtils.service';
 import LegacyUtils from './services/LegacyUtils.service';
+import Messages from './services/Messages.service';
+import ModelNormalizer from './services/ModelNormalizer.service.js';
 import UnsavedChangesGuard from './services/UnsavedChangesGuard.service';
 
-// Providers.
-
 // Filters.
 import byName from './filters/byName.filter';
 import domainsValidation from './filters/domainsValidation.filter';
@@ -167,7 +166,6 @@ angular
     'ignite-console.navbar',
     'ignite-console.configuration',
     'ignite-console.getting-started',
-    'ignite-console.version',
     'ignite-console.loading',
     // Ignite configuration module.
     'ignite-console.config',
@@ -192,7 +190,11 @@ angular
 .directive(...igniteUiAcePom)
 .directive(...igniteUiAceTabs)
 .directive(...igniteUiAceXml)
+.directive(...igniteRetainSelection)
 // Services.
+.service('IgniteErrorPopover', ErrorPopover)
+.service('JavaTypes', JavaTypes)
+.service('SqlTypes', SqlTypes)
 .service(...ChartColors)
 .service(...Clone)
 .service(...Confirm)
@@ -201,11 +203,9 @@ angular
 .service(...Countries)
 .service(...Focus)
 .service(...InetAddress)
-.service(...JavaTypes)
 .service(...Messages)
 .service(...ModelNormalizer)
 .service(...LegacyTable)
-.service('IgniteErrorPopover', ErrorPopover)
 .service(...FormUtils)
 .service(...LegacyUtils)
 .service(...UnsavedChangesGuard)
@@ -254,16 +254,17 @@ angular
         _.forEach(angular.element('.modal'), (m) => angular.element(m).scope().$hide());
     });
 }])
-.run(['$rootScope', '$http', '$state', 'IgniteMessages', 'User',
-    ($root, $http, $state, Messages, User) => { // eslint-disable-line no-shadow
+.run(['$rootScope', '$http', '$state', 'IgniteMessages', 'User', 'IgniteNotebookData',
+    ($root, $http, $state, Messages, User, Notebook) => { // eslint-disable-line no-shadow
         $root.revertIdentity = () => {
             $http.get('/api/v1/admin/revert/identity')
-                .then(User.load)
+                .then(() => User.load())
                 .then((user) => {
                     $root.$broadcast('user', user);
 
                     $state.go('settings.admin');
                 })
+                .then(() => Notebook.load())
                 .catch(Messages.showError);
         };
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/data/jdbc-types.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/jdbc-types.json b/modules/web-console/frontend/app/data/jdbc-types.json
new file mode 100644
index 0000000..07abbaf
--- /dev/null
+++ b/modules/web-console/frontend/app/data/jdbc-types.json
@@ -0,0 +1,44 @@
+[
+    {"dbName": "BIT", "dbType": -7, "signed": {"javaType": "Boolean", "primitiveType": "boolean"}},
+    {"dbName": "TINYINT", "dbType": -6,
+        "signed": {"javaType": "Byte", "primitiveType": "byte"},
+        "unsigned": {"javaType": "Short", "primitiveType": "short"}},
+    {"dbName": "SMALLINT", "dbType": 5,
+        "signed": {"javaType": "Short", "primitiveType": "short"},
+        "unsigned": {"javaType": "Integer", "primitiveType": "int"}},
+    {"dbName": "INTEGER", "dbType": 4,
+        "signed": {"javaType": "Integer", "primitiveType": "int"},
+        "unsigned": {"javaType": "Long", "primitiveType": "long"}},
+    {"dbName": "BIGINT", "dbType": -5, "signed": {"javaType": "Long", "primitiveType": "long"}},
+    {"dbName": "FLOAT", "dbType": 6, "signed": {"javaType": "Float", "primitiveType": "float"}},
+    {"dbName": "REAL", "dbType": 7, "signed": {"javaType": "Double", "primitiveType": "double"}},
+    {"dbName": "DOUBLE", "dbType": 8, "signed": {"javaType": "Double", "primitiveType": "double"}},
+    {"dbName": "NUMERIC", "dbType": 2, "signed": {"javaType": "BigDecimal"}},
+    {"dbName": "DECIMAL", "dbType": 3, "signed": {"javaType": "BigDecimal"}},
+    {"dbName": "CHAR", "dbType": 1, "signed": {"javaType": "String"}},
+    {"dbName": "VARCHAR", "dbType": 12, "signed": {"javaType": "String"}},
+    {"dbName": "LONGVARCHAR", "dbType": -1, "signed": {"javaType": "String"}},
+    {"dbName": "DATE", "dbType": 91, "signed": {"javaType": "Date"}},
+    {"dbName": "TIME", "dbType": 92, "signed": {"javaType": "Time"}},
+    {"dbName": "TIMESTAMP", "dbType": 93, "signed": {"javaType": "Timestamp"}},
+    {"dbName": "BINARY", "dbType": -2, "signed": {"javaType": "Object"}},
+    {"dbName": "VARBINARY", "dbType": -3, "signed": {"javaType": "Object"}},
+    {"dbName": "LONGVARBINARY", "dbType": -4, "signed": {"javaType": "Object"}},
+    {"dbName": "NULL", "dbType": 0, "signed": {"javaType": "Object"}},
+    {"dbName": "OTHER", "dbType": 1111, "signed": {"javaType": "Object"}},
+    {"dbName": "JAVA_OBJECT", "dbType": 2000, "signed": {"javaType": "Object"}},
+    {"dbName": "DISTINCT", "dbType": 2001, "signed": {"javaType": "Object"}},
+    {"dbName": "STRUCT", "dbType": 2002, "signed": {"javaType": "Object"}},
+    {"dbName": "ARRAY", "dbType": 2003, "signed": {"javaType": "Object"}},
+    {"dbName": "BLOB", "dbType": 2004, "signed": {"javaType": "Object"}},
+    {"dbName": "CLOB", "dbType": 2005, "signed": {"javaType": "String"}},
+    {"dbName": "REF", "dbType": 2006, "signed": {"javaType": "Object"}},
+    {"dbName": "DATALINK", "dbType": 70, "signed": {"javaType": "Object"}},
+    {"dbName": "BOOLEAN", "dbType": 16, "signed": {"javaType": "Boolean", "primitiveType": "boolean"}},
+    {"dbName": "ROWID", "dbType": -8, "signed": {"javaType": "Object"}},
+    {"dbName": "NCHAR", "dbType": -15, "signed": {"javaType": "String"}},
+    {"dbName": "NVARCHAR", "dbType": -9, "signed": {"javaType": "String"}},
+    {"dbName": "LONGNVARCHAR", "dbType": -16, "signed": {"javaType": "String"}},
+    {"dbName": "NCLOB", "dbType": 2011, "signed": {"javaType": "String"}},
+    {"dbName": "SQLXML", "dbType": 2009, "signed": {"javaType": "Object"}}
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/data/sql-keywords.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/sql-keywords.json b/modules/web-console/frontend/app/data/sql-keywords.json
new file mode 100644
index 0000000..00f4eeb
--- /dev/null
+++ b/modules/web-console/frontend/app/data/sql-keywords.json
@@ -0,0 +1,41 @@
+[
+  "CROSS",
+  "CURRENT_DATE",
+  "CURRENT_TIME",
+  "CURRENT_TIMESTAMP",
+  "DISTINCT",
+  "EXCEPT",
+  "EXISTS",
+  "FALSE",
+  "FETCH",
+  "FOR",
+  "FROM",
+  "FULL",
+  "GROUP",
+  "HAVING",
+  "INNER",
+  "INTERSECT",
+  "IS",
+  "JOIN",
+  "LIKE",
+  "LIMIT",
+  "MINUS",
+  "NATURAL",
+  "NOT",
+  "NULL",
+  "OFFSET",
+  "ON",
+  "ORDER",
+  "PRIMARY",
+  "ROWNUM",
+  "SELECT",
+  "SYSDATE",
+  "SYSTIMESTAMP",
+  "SYSTIME",
+  "TODAY",
+  "TRUE",
+  "UNION",
+  "UNIQUE",
+  "WHERE",
+  "WITH"
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/decorator/tooltip.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/decorator/tooltip.js b/modules/web-console/frontend/app/decorator/tooltip.js
index a47337a..221cf7c 100644
--- a/modules/web-console/frontend/app/decorator/tooltip.js
+++ b/modules/web-console/frontend/app/decorator/tooltip.js
@@ -25,31 +25,45 @@ import angular from 'angular';
 angular.module('mgcrea.ngStrap.tooltip')
     .decorator('$tooltip', ['$delegate', ($delegate) => {
         function TooltipFactoryDecorated(element, config) {
-            const delegate = $delegate(element, config);
+            let tipElementEntered = false;
 
-            const scope = delegate.$scope;
+            config.onShow = ($tooltip) => {
+                $tooltip.$element.on('mouseenter', () => tipElementEntered = true);
+                $tooltip.$element.on('mouseleave', () => {
+                    tipElementEntered = false;
 
-            const options = delegate.$options;
+                    $tooltip.leave();
+                });
+            };
+
+            const $tooltip = $delegate(element, config);
 
-            const hideWraped = delegate.hide;
+            const scope = $tooltip.$scope;
+            const options = $tooltip.$options;
 
-            delegate.hide = (blur) => {
-                if (!delegate.$isShown)
+            const _hide = $tooltip.hide;
+
+            $tooltip.hide = (blur) => {
+                if (!$tooltip.$isShown || tipElementEntered)
                     return;
 
-                if (delegate.$element !== null)
-                    return hideWraped(blur);
+                if ($tooltip.$element) {
+                    $tooltip.$element.off('mouseenter');
+                    $tooltip.$element.off('mouseleave');
+
+                    return _hide(blur);
+                }
 
-                scope.$emit(options.prefixEvent + '.hide.before', delegate);
+                scope.$emit(options.prefixEvent + '.hide.before', $tooltip);
 
                 if (angular.isDefined(options.onBeforeHide) && angular.isFunction(options.onBeforeHide))
-                    options.onBeforeHide(delegate);
+                    options.onBeforeHide($tooltip);
 
-                delegate.$isShown = scope.$isShown = false;
+                $tooltip.$isShown = scope.$isShown = false;
                 scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
             };
 
-            return delegate;
+            return $tooltip;
         }
 
         return TooltipFactoryDecorated;

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/directives/retain-selection.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/retain-selection.directive.js b/modules/web-console/frontend/app/directives/retain-selection.directive.js
new file mode 100644
index 0000000..74d6872
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/retain-selection.directive.js
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+// Directive to workaround known issue with type ahead edit lost cursor position.
+export default ['igniteRetainSelection', ['$timeout', ($timeout) => {
+    let promise;
+
+    return function(scope, elem) {
+        elem.on('keydown', function(evt) {
+            const key = evt.which;
+            const ctrlDown = evt.ctrlKey || evt.metaKey;
+            const input = this;
+            let start = input.selectionStart;
+
+            if (promise)
+                $timeout.cancel(promise);
+
+            promise = $timeout(() => {
+                let setCursor = false;
+
+                // Handle Backspace[8].
+                if (key === 8 && start > 0) {
+                    start -= 1;
+
+                    setCursor = true;
+                }
+                // Handle Del[46].
+                else if (key === 46)
+                    setCursor = true;
+                // Handle: Caps Lock[20], Tab[9], Shift[16], Ctrl[17], Alt[18], Esc[27], Enter[13], Arrows[37..40], Home[36], End[35], Ins[45], PgUp[33], PgDown[34], F1..F12[111..124], Num Lock[], Scroll Lock[145].
+                else if (!(key === 8 || key === 9 || key === 13 || (key > 15 && key < 20) || key === 27 ||
+                    (key > 32 && key < 41) || key === 45 || (key > 111 && key < 124) || key === 144 || key === 145)) {
+                    // Handle: Ctrl + [A[65], C[67], V[86]].
+                    if (!(ctrlDown && (key === 65 || key === 67 || key === 86))) {
+                        start += 1;
+
+                        setCursor = true;
+                    }
+                }
+
+                if (setCursor)
+                    input.setSelectionRange(start, start);
+
+                promise = null;
+            });
+        });
+
+        // Removes bound events in the element itself when the scope is destroyed
+        scope.$on('$destroy', function() {
+            elem.off('keydown');
+        });
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
index ec880bd..82afeac 100644
--- a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
+++ b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-export default ['$scope', 'GeneratorPom', 'IgniteVersion', function($scope, pom, IgniteVersion) {
+export default ['$scope', 'GeneratorPom', 'IgniteVersion', function($scope, pom, Version) {
     const ctrl = this;
 
     // Watchers definition.
@@ -25,7 +25,7 @@ export default ['$scope', 'GeneratorPom', 'IgniteVersion', function($scope, pom,
         if (!value)
             return;
 
-        ctrl.data = pom.generate($scope.cluster, IgniteVersion.version).asString();
+        ctrl.data = pom.generate($scope.cluster, Version.ignite).asString();
     };
 
     // Setup watchers.

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form.jade b/modules/web-console/frontend/app/helpers/jade/form.jade
index 4b017ea..c0c558d 100644
--- a/modules/web-console/frontend/app/helpers/jade/form.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form.jade
@@ -17,6 +17,7 @@
 include ./form/form-field-feedback.jade
 include ./form/form-field-label.jade
 include ./form/form-field-text.jade
+include ./form/form-field-password.jade
 include ./form/form-field-dropdown.jade
 include ./form/form-field-datalist.jade
 include ./form/form-field-checkbox.jade

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
index 98a0b9a..25e5805 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
@@ -37,10 +37,10 @@ mixin form-field-datalist(label, model, name, disabled, required, placeholder, o
             data-ignite-form-panel-field=''
         )&attributes(attributes.attributes)
 
-    div
-        +ignite-form-field-label(label, name, required)
-        .col-xs-8.col-sm-8.col-md-8
-            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+    .ignite-form-field
+        +ignite-form-field__label(label, name, required)
+        .ignite-form-field__control
+            i.tipField.fa.fa-question-circle(bs-tooltip='' data-title=tip)
 
             +form-field-feedback(name, 'required', errLbl + ' could not be empty!')
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
index a8496bc..f5d035d 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
@@ -38,10 +38,10 @@ mixin ignite-form-field-dropdown(label, model, name, disabled, required, multipl
             data-ignite-form-panel-field=''
         )&attributes(attributes.attributes)
 
-    div
-        +ignite-form-field-label(label, name, required)
-        .col-xs-8.col-sm-8.col-md-8
-            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+    .ignite-form-field
+        +ignite-form-field__label(label, name, required)
+        .ignite-form-field__control
+            i.tipField.fa.fa-question-circle(bs-tooltip='' data-title=tip)
 
             if block
                 block

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
index cd5f8fc..d6aef81 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
@@ -14,8 +14,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-mixin ignite-form-field-label(label, name, required)
-    label.col-xs-4.col-sm-4.col-md-4(
+mixin ignite-form-field__label(label, name, required)
+    label.ignite-form-field__label(
         id='{{ #{name} }}Label'
         for='{{ #{name} }}Input'
         class="{{ #{required} ? 'required' : '' }}"

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
index c32d3d9..62b3e09 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
@@ -35,10 +35,10 @@ mixin ignite-form-field-number(label, model, name, disabled, required, placehold
             data-ignite-form-panel-field=''
         )&attributes(attributes.attributes)
 
-    div
-        +ignite-form-field-label(label, name, required)
-        .col-xs-8.col-sm-8.col-md-8
-            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+    .ignite-form-field
+        +ignite-form-field__label(label, name, required)
+        .ignite-form-field__control
+            i.tipField.fa.fa-question-circle(bs-tooltip='' data-title=tip)
             
             +form-field-feedback(name, 'required', 'This field could not be empty')
             +form-field-feedback(name, 'min', 'Value is less than allowable minimum: '+ min || 0)

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-password.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-password.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-password.jade
new file mode 100644
index 0000000..51cc109
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-password.jade
@@ -0,0 +1,47 @@
+//-
+    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.
+
+mixin ignite-form-field-password-input(name, model, disabled, required, placeholder)
+    input.form-control(
+        id='{{ #{name} }}Input'
+        name='{{ #{name} }}'
+        placeholder=placeholder
+        type='password'
+
+        data-ng-model=model
+
+        data-ng-required=required && '#{required}'
+        data-ng-disabled=disabled && '#{disabled}'
+        data-ng-focus='tableReset()'
+
+        data-ignite-form-panel-field=''
+    )&attributes(attributes ? attributes.attributes ? attributes.attributes : attributes : {})
+
+mixin ignite-form-field-password(label, model, name, disabled, required, placeholder, tip)
+    -var errLbl = label.substring(0, label.length - 1)
+
+    .ignite-form-field
+        +ignite-form-field__label(label, name, required)
+        .ignite-form-field__control
+            i.tipField.fa.fa-question-circle(bs-tooltip='' data-title=tip)
+            
+            if block
+                block
+
+            +form-field-feedback(name, 'required', errLbl + ' could not be empty!')
+
+            .input-tip
+                +ignite-form-field-password-input(name, model, disabled, required, placeholder)(attributes=attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
index 796e641..55b850d 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
@@ -28,15 +28,15 @@ mixin ignite-form-field-input(name, model, disabled, required, placeholder)
         data-ng-focus='tableReset()'
 
         data-ignite-form-panel-field=''
-    )&attributes(attributes ? attributes.attributes ? attributes.attributes : attributes : {})
+    )&attributes(attributes ? attributes.attributes ? attributes.attributes : attributes: {})
 
 mixin ignite-form-field-text(label, model, name, disabled, required, placeholder, tip)
     -var errLbl = label.substring(0, label.length - 1)
 
-    div
-        +ignite-form-field-label(label, name, required)
-        .col-xs-8.col-sm-8.col-md-8
-            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+    .ignite-form-field
+        +ignite-form-field__label(label, name, required)
+        .ignite-form-field__control
+            i.tipField.fa.fa-question-circle(bs-tooltip='' data-title=tip)
             
             if block
                 block

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/helpers/jade/mixins.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/mixins.jade b/modules/web-console/frontend/app/helpers/jade/mixins.jade
index c37ab15..4979c12 100644
--- a/modules/web-console/frontend/app/helpers/jade/mixins.jade
+++ b/modules/web-console/frontend/app/helpers/jade/mixins.jade
@@ -101,25 +101,20 @@ mixin uuid-feedback(name)
 mixin checkbox(lbl, model, name, tip)
     +form-field-checkbox(lbl, model, name, false, false, tip)
 
+//- Function that convert enabled state to corresponding disabled state.
+-var enabledToDisabled = function (enabled) {
+-    return (enabled === false || enabled === true) ? !enabled : '!(' + enabled + ')';
+-}
+
 //- Mixin for checkbox with enabled condition.
 mixin checkbox-enabled(lbl, model, name, enabled, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-        
-    +form-field-checkbox(lbl, model, name, disabled, false, tip)
+    +form-field-checkbox(lbl, model, name, enabledToDisabled(enabled), false, tip)
 
 //- Mixin for java name field with enabled condition.
 mixin java-class(lbl, model, name, enabled, required, tip)
     -var errLbl = lbl.substring(0, lbl.length - 1)
 
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-
-    +ignite-form-field-text(lbl, model, name, disabled, required, 'Enter fully qualified class name', tip)(
+    +ignite-form-field-text(lbl, model, name, enabledToDisabled(enabled), required, 'Enter fully qualified class name', tip)(
         data-java-identifier='true'
         data-java-package-specified='true'
         data-java-keywords='true'
@@ -133,13 +128,11 @@ mixin java-class(lbl, model, name, enabled, required, tip)
         +form-field-feedback(name, 'javaPackageSpecified', errLbl + ' does not have package specified!')
         +form-field-feedback(name, 'javaIdentifier', errLbl + ' is invalid Java identifier!')
 
-        
-
 //- Mixin for text field with enabled condition with options.
 mixin java-class-typeahead(lbl, model, name, options, enabled, required, placeholder, tip)
     -var errLbl = lbl.substring(0, lbl.length - 1)
 
-    +form-field-datalist(lbl, model, name, '!('+enabled+')', required, placeholder, options, tip)(
+    +form-field-datalist(lbl, model, name, enabledToDisabled(enabled), required, placeholder, options, tip)(
         data-java-identifier='true'
         data-java-package-specified='allow-built-in'
         data-java-keywords='true'
@@ -148,25 +141,30 @@ mixin java-class-typeahead(lbl, model, name, options, enabled, required, placeho
         +form-field-feedback(name, 'javaPackageSpecified', errLbl + ' does not have package specified!')
         +form-field-feedback(name, 'javaIdentifier', errLbl + ' is invalid Java identifier!')
 
+//- Mixin for java package field with enabled condition.
+mixin java-package(lbl, model, name, enabled, required, tip)
+    +ignite-form-field-text(lbl, model, name, enabledToDisabled(enabled), required, 'Enter package name', tip)(
+        data-java-keywords='true'
+        data-java-package-name='package-only'
+    )
+        +form-field-feedback(name, 'javaPackageName', 'Package name is invalid')
+        +form-field-feedback(name, 'javaKeywords', 'Package name could not contains reserved java keyword')
+
 //- Mixin for text field with IP address check.
 mixin text-ip-address(lbl, model, name, enabled, placeholder, tip)
-    +ignite-form-field-text(lbl, model, name, '!('+enabled+')', false, placeholder, tip)(data-ipaddress='true')
+    +ignite-form-field-text(lbl, model, name, enabledToDisabled(enabled), false, placeholder, tip)(data-ipaddress='true')
         +ipaddress-feedback(name)
 
-//- Mixin for text field with IP address and port check.
-mixin text-ip-address-with-port(lbl, model, name, enabled, placeholder, tip)
-    +ignite-form-field-text(lbl, model, name, '!('+enabled+')', false, placeholder, tip)(data-ipaddress='true' data-ipaddress-with-port='true')
+//- Mixin for text field with IP address and port range check.
+mixin text-ip-address-with-port-range(lbl, model, name, enabled, placeholder, tip)
+    +ignite-form-field-text(lbl, model, name, enabledToDisabled(enabled), false, placeholder, tip)(data-ipaddress='true' data-ipaddress-with-port='true' data-ipaddress-with-port-range='true')
         +ipaddress-feedback(name)
         +ipaddress-port-feedback(name)
+        +ipaddress-port-range-feedback(name)
 
 //- Mixin for text field.
 mixin text-enabled(lbl, model, name, enabled, required, placeholder, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-        
-    +ignite-form-field-text(lbl, model, name, disabled, required, placeholder, tip)
+    +ignite-form-field-text(lbl, model, name, enabledToDisabled(enabled), required, placeholder, tip)
         if  block
             block
 
@@ -176,67 +174,53 @@ mixin text(lbl, model, name, required, placeholder, tip)
         if  block
             block
 
+//- Mixin for password field.
+mixin password(lbl, model, name, required, placeholder, tip)
+    +ignite-form-field-password(lbl, model, name, false, required, placeholder, tip)
+        if  block
+            block
+
 //- Mixin for text field with enabled condition with options.
 mixin text-options(lbl, model, name, options, enabled, required, placeholder, tip)
-    +form-field-datalist(lbl, model, name, '!('+enabled+')', required, placeholder, options, tip)
+    +form-field-datalist(lbl, model, name, enabledToDisabled(enabled), required, placeholder, options, tip)
 
 //- Mixin for required numeric field.
 mixin number-required(lbl, model, name, enabled, required, placeholder, min, tip)
-    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', required, placeholder, min, false, false, tip)
+    +ignite-form-field-number(lbl, model, name, enabledToDisabled(enabled), required, placeholder, min, false, false, tip)
 
 //- Mixin for required numeric field with maximum and minimum limit.
 mixin number-min-max(lbl, model, name, enabled, placeholder, min, max, tip)
-    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, max, '1', tip)
+    +ignite-form-field-number(lbl, model, name, enabledToDisabled(enabled), false, placeholder, min, max, '1', tip)
 
 //- Mixin for required numeric field with maximum and minimum limit.
 mixin number-min-max-step(lbl, model, name, enabled, placeholder, min, max, step, tip)
-    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, max, step, tip)
+    +ignite-form-field-number(lbl, model, name, enabledToDisabled(enabled), false, placeholder, min, max, step, tip)
 
 //- Mixin for numeric field.
 mixin number(lbl, model, name, enabled, placeholder, min, tip)
-    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, false, false, tip)
+    +ignite-form-field-number(lbl, model, name, enabledToDisabled(enabled), false, placeholder, min, false, false, tip)
 
 //- Mixin for required dropdown field.
 mixin dropdown-required-empty(lbl, model, name, enabled, required, placeholder, placeholderEmpty, options, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-
-    +ignite-form-field-dropdown(lbl, model, name, disabled, required, false, placeholder, placeholderEmpty, options, tip)
+    +ignite-form-field-dropdown(lbl, model, name, enabledToDisabled(enabled), required, false, placeholder, placeholderEmpty, options, tip)
         if  block
             block
-                
+
 //- Mixin for required dropdown field.
 mixin dropdown-required(lbl, model, name, enabled, required, placeholder, options, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-
-    +ignite-form-field-dropdown(lbl, model, name, disabled, required, false, placeholder, '', options, tip)
+    +ignite-form-field-dropdown(lbl, model, name, enabledToDisabled(enabled), required, false, placeholder, '', options, tip)
         if  block
             block
 
 //- Mixin for dropdown field.
 mixin dropdown(lbl, model, name, enabled, placeholder, options, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-
-    +ignite-form-field-dropdown(lbl, model, name, disabled, false, false, placeholder, '', options, tip)
+    +ignite-form-field-dropdown(lbl, model, name, enabledToDisabled(enabled), false, false, placeholder, '', options, tip)
         if  block
             block
 
 //- Mixin for dropdown-multiple field.
 mixin dropdown-multiple(lbl, model, name, enabled, placeholder, placeholderEmpty, options, tip)
-    if enabled === false || enabled === true 
-        -var disabled = !enabled
-    else
-        -var disabled = '!('+enabled+')'
-
-    +ignite-form-field-dropdown(lbl, model, name, disabled, false, true, placeholder, placeholderEmpty, options, tip)
+    +ignite-form-field-dropdown(lbl, model, name, enabledToDisabled(enabled), false, true, placeholder, placeholderEmpty, options, tip)
         if  block
             block
 
@@ -319,7 +303,7 @@ mixin table-java-package-field(name, model, items, valid, save, newItem)
     .input-tip
         +ignite-form-field-input(name, model, false, 'true', 'Enter package name')(
             data-java-keywords='true'
-            data-java-package-name='true'
+            data-java-package-name='package-only'
 
             data-ignite-unique=items
             data-ignite-form-field-input-autofocus='true'
@@ -360,7 +344,7 @@ mixin table-address-field(name, model, items, valid, save, newItem, portRange)
         )
 
 //- Mixin for table UUID field.
-mixin table-uuid-field(name, model, items, valid, save, newItem, portRange)
+mixin table-uuid-field(name, model, items, valid, save, newItem)
     -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
     -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
 
@@ -506,7 +490,6 @@ mixin table-pair-edit(tbl, prefix, keyPlaceholder, valPlaceholder, keyJavaBuiltI
             else
                 input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder=keyPlaceholder ignite-on-escape='tableReset()')
     .col-xs-6.col-sm-6.col-md-6
-        -var arg = keyModel + ', ' + valModel
         -var btnVisible = 'tablePairSaveVisible(' + tbl + ', ' + index + ')'
         -var btnSave = 'tablePairSave(tablePairValid, backupItem, ' + tbl + ', ' + index + ')'
         -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
@@ -529,7 +512,7 @@ mixin dialect(lbl, model, name, required, tipTitle, genericDialectName, placehol
                 {value: "PostgreSQL", label: "PostgreSQL"},\
                 {value: "H2", label: "H2 database"}\
         ]',
-        tipTitle + 
+        tipTitle +
         '<ul>\
             <li>' + genericDialectName + '</li>\
             <li>Oracle database</li>\

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/configuration/Version.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/Version.service.js b/modules/web-console/frontend/app/modules/configuration/Version.service.js
new file mode 100644
index 0000000..c36a98b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/Version.service.js
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Utility service for version.
+ */
+export default () => {
+    return {
+        ignite: '1.7.0'
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/configuration/configuration.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/configuration.module.js b/modules/web-console/frontend/app/modules/configuration/configuration.module.js
index 99830b0..dc6fa2f 100644
--- a/modules/web-console/frontend/app/modules/configuration/configuration.module.js
+++ b/modules/web-console/frontend/app/modules/configuration/configuration.module.js
@@ -19,6 +19,7 @@ import angular from 'angular';
 
 import igniteEventGroups from './EventGroups.provider';
 import igniteSidebar from './Sidebar.provider';
+import Version from './Version.service';
 
 import GeneratorXml from './generator/Xml.service';
 import GeneratorJava from './generator/Java.service';
@@ -35,6 +36,7 @@ angular
 .provider(...igniteEventGroups)
 .provider(...igniteSidebar)
 .directive(...igniteSidebarDirective)
+.service('IgniteVersion', Version)
 .service(...GeneratorXml)
 .service(...GeneratorJava)
 .service(...GeneratorDocker)

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
index 627a1e3..f2d04b0 100644
--- a/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
@@ -52,10 +52,10 @@ class GeneratorPom {
         res.endBlock('</resource>');
     }
 
-    artifact(res, cluster, igniteVersion) {
+    artifact(res, cluster, version) {
         this.addProperty(res, 'groupId', 'org.apache.ignite');
         this.addProperty(res, 'artifactId', this.escapeId(cluster.name) + '-project');
-        this.addProperty(res, 'version', igniteVersion);
+        this.addProperty(res, 'version', version);
 
         res.needEmptyLine = true;
     }
@@ -143,11 +143,11 @@ class GeneratorPom {
      * Generate pom.xml.
      *
      * @param cluster Cluster  to take info about dependencies.
-     * @param igniteVersion Ignite version for Ignite dependencies.
+     * @param version Ignite version for Ignite dependencies.
      * @param res Resulting output with generated pom.
      * @returns {string} Generated content.
      */
-    generate(cluster, igniteVersion, res) {
+    generate(cluster, version, res) {
         const caches = cluster.caches;
         const deps = [];
         const storeDeps = [];
@@ -163,14 +163,14 @@ class GeneratorPom {
                 this.storeFactoryDependency(storeDeps, cache.cacheStoreFactory[cache.cacheStoreFactory.kind]);
 
             if (_.get(cache, 'nodeFilter.kind') === 'Exclude')
-                this.addDependency(deps, 'org.apache.ignite', 'ignite-extdata-p2p', igniteVersion);
+                this.addDependency(deps, 'org.apache.ignite', 'ignite-extdata-p2p', version);
         });
 
         res.line('<?xml version="1.0" encoding="UTF-8"?>');
 
         res.needEmptyLine = true;
 
-        res.line('<!-- ' + $generatorCommon.mainComment() + ' -->');
+        res.line('<!-- ' + $generatorCommon.mainComment('Maven project') + ' -->');
 
         res.needEmptyLine = true;
 
@@ -180,18 +180,18 @@ class GeneratorPom {
 
         res.needEmptyLine = true;
 
-        this.artifact(res, cluster, igniteVersion);
+        this.artifact(res, cluster, version);
 
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-core', igniteVersion);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-core', version);
 
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-spring', igniteVersion);
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-indexing', igniteVersion);
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-rest-http', igniteVersion);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-spring', version);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-indexing', version);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-rest-http', version);
 
         let dep = POM_DEPENDENCIES[cluster.discovery.kind];
 
         if (dep)
-            this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
+            this.addDependency(deps, 'org.apache.ignite', dep.artifactId, version);
 
         if (cluster.discovery.kind === 'Jdbc') {
             const store = cluster.discovery.Jdbc;
@@ -201,16 +201,16 @@ class GeneratorPom {
         }
 
         if (_.find(cluster.igfss, (igfs) => igfs.secondaryFileSystemEnabled))
-            this.addDependency(deps, 'org.apache.ignite', 'ignite-hadoop', igniteVersion);
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-hadoop', version);
 
         if (_.find(caches, blobStoreFactory))
-            this.addDependency(deps, 'org.apache.ignite', 'ignite-hibernate', igniteVersion);
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-hibernate', version);
 
         if (cluster.logger && cluster.logger.kind) {
             dep = POM_DEPENDENCIES[cluster.logger.kind];
 
             if (dep)
-                this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
+                this.addDependency(deps, 'org.apache.ignite', dep.artifactId, version);
         }
 
         this.dependencies(res, cluster, deps.concat(storeDeps));

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
index 5cbf7fb..2abe1df 100644
--- a/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
+++ b/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
@@ -17,10 +17,10 @@
 
 export default ['javaIdentifier', ['JavaTypes', (JavaTypes) => {
     const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaIdentifier) || !attrs.javaIdentifier)
+        if (_.isNil(attrs.javaIdentifier) || attrs.javaIdentifier !== 'true')
             return;
 
-        ngModel.$validators.javaIdentifier = (value) => JavaTypes.validIdentifier(value);
+        ngModel.$validators.javaIdentifier = (value) => _.isEmpty(value) || JavaTypes.validClassName(value);
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
index d97e59a..c9eef41 100644
--- a/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
+++ b/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
@@ -17,17 +17,17 @@
 
 export default ['javaKeywords', ['JavaTypes', (JavaTypes) => {
     const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaKeywords) || !attrs.javaKeywords)
+        if (_.isNil(attrs.javaKeywords) || attrs.javaKeywords === 'false')
             return;
 
         const packageOnly = attrs.javaPackageName === 'package-only';
 
         ngModel.$validators.javaKeywords = (value) => {
             if (value) {
-                if (!JavaTypes.validIdentifier(value) || (!packageOnly && !JavaTypes.packageSpecified(value)))
+                if (_.isEmpty(value) || !JavaTypes.validClassName(value) || (!packageOnly && !JavaTypes.packageSpecified(value)))
                     return true;
 
-                return _.findIndex(value.split('.'), JavaTypes.isKeywords) < 0;
+                return _.findIndex(value.split('.'), JavaTypes.isKeyword) < 0;
             }
 
             return true;

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
index ac38179..49d4b55 100644
--- a/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
+++ b/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
@@ -17,10 +17,10 @@
 
 export default ['javaPackageName', ['JavaTypes', (JavaTypes) => {
     const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaPackageName) || !attrs.javaPackageName)
+        if (_.isNil(attrs.javaPackageName) || attrs.javaPackageName === 'false')
             return;
 
-        ngModel.$validators.javaPackageName = (value) => JavaTypes.validPackage(value);
+        ngModel.$validators.javaPackageName = (value) => _.isEmpty(value) || JavaTypes.validPackage(value);
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
index 451d7ec..5f24eb7 100644
--- a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
+++ b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
@@ -17,13 +17,14 @@
 
 export default ['javaPackageSpecified', ['JavaTypes', (JavaTypes) => {
     const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaPackageSpecified))
+        if (_.isNil(attrs.javaPackageSpecified) || attrs.javaPackageSpecified === 'false')
             return;
 
         const allowBuiltIn = attrs.javaPackageSpecified === 'allow-built-in';
 
-        ngModel.$validators.javaPackageSpecified = (value) => !value || !JavaTypes.validIdentifier(value) || JavaTypes.packageSpecified(value) ||
-                (allowBuiltIn && !JavaTypes.nonBuiltInClass(value));
+        ngModel.$validators.javaPackageSpecified = (value) => _.isEmpty(value) ||
+            !JavaTypes.validClassName(value) || JavaTypes.packageSpecified(value) ||
+            (allowBuiltIn && !JavaTypes.nonBuiltInClass(value));
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js b/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
index 0704175..94c6e3f 100644
--- a/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
+++ b/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
@@ -17,16 +17,10 @@
 
 export default ['uuid', ['JavaTypes', (JavaTypes) => {
     const link = (scope, el, attrs, [ngModel]) => {
-        const isEmpty = (modelValue) => {
-            return ngModel.$isEmpty(modelValue) || _.isUndefined(attrs.uuid) || attrs.uuid !== 'true';
-        };
+        if (_.isNil(attrs.uuid) || attrs.uuid !== 'true')
+            return;
 
-        ngModel.$validators.uuid = (modelValue) => {
-            if (isEmpty(modelValue))
-                return true;
-
-            return JavaTypes.validUUID(modelValue);
-        };
+        ngModel.$validators.uuid = (modelValue) => _.isEmpty(modelValue) || JavaTypes.validUUID(modelValue);
     };
 
     return {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/sql/Notebook.data.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/Notebook.data.js b/modules/web-console/frontend/app/modules/sql/Notebook.data.js
index aef72eb..f66faba 100644
--- a/modules/web-console/frontend/app/modules/sql/Notebook.data.js
+++ b/modules/web-console/frontend/app/modules/sql/Notebook.data.js
@@ -83,18 +83,26 @@ export default class NotebookData {
         this.$q = $q;
     }
 
-    read() {
-        if (!_.isNil(this.initLatch))
-            return this.initLatch;
+    load() {
+        if (this.demo) {
+            if (this.initLatch)
+                return this.initLatch;
 
-        if (this.demo)
             return this.initLatch = this.$q.when(this.notebooks = [DEMO_NOTEBOOK]);
+        }
 
         return this.initLatch = this.$http.get('/api/v1/notebooks')
             .then(({data}) => this.notebooks = data)
             .catch(({data}) => Promise.reject(data));
     }
 
+    read() {
+        if (this.initLatch)
+            return this.initLatch;
+
+        return this.load();
+    }
+
     find(_id) {
         return this.read()
             .then(() => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
index debbe0d..e9f29fd 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
@@ -78,7 +78,7 @@ include ../../../../../app/helpers/jade/mixins.jade
                 .settings-row(data-ng-if=model + '.offHeapMode === 1 && ' + model + '.memoryMode !== "OFFHEAP_VALUES"')
                     +number-required('Off-heap memory max size:', model + '.offHeapMaxMemory', '"offHeapMaxMemory"', 'true',
                         model + '.offHeapMode === 1', '', 1,
-                        'Sets maximum amount of memory available to off-heap storage in bytes')
+                        'Maximum amount of memory available to off-heap storage in bytes')
                 .settings-row
                     -var onHeapTired = model + '.memoryMode === "ONHEAP_TIERED"'
                     -var swapEnabled = model + '.swapEnabled'
@@ -94,8 +94,7 @@ include ../../../../../app/helpers/jade/mixins.jade
                             <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
                         </ul>')
                 .settings-row
-                    +number('Start size:', model + '.startSize', '"startSize"', 'true', '1500000', '0',
-                        'Initial cache size which will be used to pre-create internal hash table after start')
+                    +number('Start size:', model + '.startSize', '"startSize"', 'true', '1500000', '0', 'Initial cache size in entries number')
                 .settings-row
                     +checkbox('Swap enabled', model + '.swapEnabled', '"swapEnabled"', 'Flag indicating whether swap storage is enabled or not for this cache')
             .col-sm-6

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
index c83114b..c709135 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
@@ -30,7 +30,15 @@ include ../../../../../app/helpers/jade/mixins.jade
         .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
             .col-sm-6
                 .settings-row
-                    +text('SQL schema name:', model + '.sqlSchema', '"sqlSchema"', 'false', 'Input schema name', 'Schema name for cache according to SQL ANSI-99')
+                    +text('SQL schema name:', model + '.sqlSchema', '"sqlSchema"', 'false', 'Input schema name',
+                        'Schema name allow to use existing database queries in your application and according to SQL ANSI-99<br>\
+                        Cache is reffered by schema name in cross-cache queries<br/>\
+                        Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive<br/>\
+                        When SQL schema is not specified, quoted cache name should be used<br/>\
+                        Query example without schema name:<br>\
+                        SELECT .... FROM "cache1".Type1 JOIN "cache2".Type2 ...<br>\
+                        The same query using schema name:<br>\
+                        SELECT .... FROM cache1.Type1 JOIN cache2.Type2 ...')
                 .settings-row
                     +number('On-heap cache for off-heap indexes:', model + '.sqlOnheapRowCacheSize', '"sqlOnheapRowCacheSize"', 'true', '10240', '1',
                         'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access')
@@ -89,7 +97,7 @@ include ../../../../../app/helpers/jade/mixins.jade
                         'Flag indicating whether SQL indexes should support snapshots')
                 .settings-row
                     +checkbox('Escape table and filed names', model + '.sqlEscapeAll', '"sqlEscapeAll"',
-                        'If set then all the SQL table and field names will be escaped with double quotes<br/>\
+                        'If enabled than all the SQL table and field names will be escaped with double quotes like "tableName"."fieldName"<br/>\
                         This enforces case sensitivity for field names and also allows having special characters in table and field names')
             .col-sm-6
                 +preview-xml-java(model, 'cacheQuery', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
index a078bf1..3531c77 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
@@ -25,7 +25,7 @@ include ../../../../../app/helpers/jade/mixins.jade
         ignite-form-panel-chevron
         label Cache key configuration
         ignite-form-field-tooltip.tipLabel
-            | Cache key configuration allows to collocate objects in a partitioned cache based on field in cache key without explicit usage of annotations on user classes.
+            | Cache key configuration allows to collocate objects in a partitioned cache based on field in cache key without explicit usage of annotations on user classes
         ignite-form-revert
     .panel-collapse(role='tabpanel' bs-collapse-target id=form)
         .panel-body(ng-if='ui.isPanelLoaded("#{form}")')

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
index 0643555..2c60478 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
@@ -90,7 +90,7 @@ include ../../../../../app/helpers/jade/mixins.jade
                 .settings-row
                     +checkbox('Direct buffer', communication + '.directBuffer', '"directBuffer"',
                     'If value is true, then SPI will use ByteBuffer.allocateDirect(int) call<br/>\
-                    Otherwise, SPI will use ByteBuffer.allocate(int) call.')
+                    Otherwise, SPI will use ByteBuffer.allocate(int) call')
                 .settings-row
                     +checkbox('Direct send buffer', communication + '.directSendBuffer', '"directSendBuffer"', 'Flag defining whether direct send buffer should be used')
                 .settings-row

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.jade
new file mode 100644
index 0000000..c267891
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/odbc.jade
@@ -0,0 +1,47 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'odbcConfiguration'
+-var model = 'backupItem.odbc'
+-var enabled = model + '.odbcEnabled'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label ODBC configuration
+        ignite-form-field-tooltip.tipLabel
+            | ODBC server configuration
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +checkbox('Enabled', enabled, '"odbcEnabled"', 'Flag indicating whether to configure ODBC configuration')
+                .settings-row
+                    +text-ip-address-with-port-range('ODBC endpoint address:', model + '.endpointAddress', '"endpointAddress"', enabled, '0.0.0.0:10800..10810',
+                        'ODBC endpoint address. <br/>\
+                        The following address formats are permitted:\
+                        <ul>\
+                            <li>hostname - will use provided hostname and default port range</li>\
+                            <li>hostname:port - will use provided hostname and port</li>\
+                            <li>hostname:port_from..port_to - will use provided hostname and port range</li>\
+                        </ul>')
+                .settings-row
+                    +number('Maximum open cursors', model + '.maxOpenCursors', '"maxOpenCursors"', enabled, '128', '1', 'Maximum number of opened cursors per connection')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterODBC')

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade b/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
index 5c55e0c..74895f5 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
@@ -16,8 +16,8 @@
 
 include ../../../../../app/helpers/jade/mixins.jade
 
-- var form = 'general'
-- var model = 'backupItem'
+-var form = 'general'
+-var model = 'backupItem'
 
 .panel.panel-default(ng-form=form novalidate)
     .panel-heading(bs-collapse-toggle)

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade b/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
index 33c358a..0cf21f5 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
@@ -16,14 +16,14 @@
 
 include ../../../../../app/helpers/jade/mixins.jade
 
-- var form = 'query'
-- var model = 'backupItem'
-- var queryFields = model + '.fields'
-- var queryAliases = model + '.aliases'
-- var queryIndexes = model + '.indexes'
-- var queryFieldsForm = 'queryFields'
-- var queryAliasesForm = 'queryAliases'
-- var queryIndexesForm = 'queryIndexes'
+-var form = 'query'
+-var model = 'backupItem'
+-var queryFields = model + '.fields'
+-var queryAliases = model + '.aliases'
+-var queryIndexes = model + '.indexes'
+-var queryFieldsForm = 'queryFields'
+-var queryAliasesForm = 'queryAliases'
+-var queryIndexesForm = 'queryIndexes'
 
 // LEGACY mixin for LEGACY index fields table.
 mixin table-index-item-edit(prefix, index, sortAvailable, idAddition)

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
index f0cb842..4aad7e2 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
+++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
@@ -21,7 +21,7 @@ import saver from 'file-saver';
 
 export default [
     '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteLoading', '$filter', 'igniteConfigurationResource', 'JavaTypes', 'IgniteVersion', 'GeneratorDocker', 'GeneratorPom', 'IgniteFormUtils',
-    function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, IgniteVersion, docker, pom, FormUtils) {
+    function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, Version, docker, pom, FormUtils) {
         const ctrl = this;
 
         $scope.ui = { ready: false };
@@ -81,6 +81,14 @@ export default [
             ]
         };
 
+        const loadFolder = {
+            type: 'folder',
+            name: 'load',
+            children: [
+                { type: 'file', name: 'LoadCaches.java' }
+            ]
+        };
+
         const javaStartupFolder = {
             type: 'folder',
             name: 'startup',
@@ -224,7 +232,11 @@ export default [
             sessionStorage.summarySelectedId = $scope.clusters.indexOf(cluster);
 
             mainFolder.children = [javaFolder];
-            javaFolder.children = [javaConfigFolder, javaStartupFolder];
+
+            if (_.find(cluster.caches, (cache) => !_.isNil(cache.cacheStoreFactory)))
+                javaFolder.children = [javaConfigFolder, loadFolder, javaStartupFolder];
+            else
+                javaFolder.children = [javaConfigFolder, javaStartupFolder];
 
             if ($generatorCommon.secretPropertiesNeeded(cluster))
                 mainFolder.children.push(resourcesFolder);
@@ -308,6 +320,12 @@ export default [
                     'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
             }
 
+            // Generate loader for caches with configured store.
+            const cachesToLoad = _.filter(cluster.caches, (cache) => !_.isNil(cache.cacheStoreFactory));
+
+            if (!_.isEmpty(cachesToLoad))
+                zip.file(srcPath + 'load/LoadCaches.java', $generatorJava.loadCaches(cachesToLoad, 'load', 'LoadCaches', '"' + clientXml + '"'));
+
             zip.file(srcPath + 'startup/ServerNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeSpringStartup', '"' + serverXml + '"'));
             zip.file(srcPath + 'startup/ClientNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeSpringStartup', '"' + clientXml + '"'));
 
@@ -316,7 +334,7 @@ export default [
             zip.file(srcPath + 'startup/ClientNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeCodeStartup',
                 'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCfg));
 
-            zip.file('pom.xml', pom.generate(cluster, IgniteVersion.version).asString());
+            zip.file('pom.xml', pom.generate(cluster, Version.ignite).asString());
 
             zip.file('README.txt', $generatorReadme.readme().asString());
             zip.file('jdbc-drivers/README.txt', $generatorReadme.readmeJdbc().asString());

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/modules/version/Version.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/version/Version.provider.js b/modules/web-console/frontend/app/modules/version/Version.provider.js
deleted file mode 100644
index 31ff8d0..0000000
--- a/modules/web-console/frontend/app/modules/version/Version.provider.js
+++ /dev/null
@@ -1,32 +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 angular from 'angular';
-
-angular
-    .module('ignite-console.version', [])
-    .provider('IgniteVersion', function() {
-        const version = {
-            version: '1.7.0'
-        };
-
-        this.update = (newVersion) => {
-            version.version = newVersion;
-        };
-
-        this.$get = [() => version];
-    });

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/services/ErrorPopover.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ErrorPopover.service.js b/modules/web-console/frontend/app/services/ErrorPopover.service.js
index 85e4fda..3130431 100644
--- a/modules/web-console/frontend/app/services/ErrorPopover.service.js
+++ b/modules/web-console/frontend/app/services/ErrorPopover.service.js
@@ -15,6 +15,9 @@
  * limitations under the License.
  */
 
+/**
+ * Service to show/hide error popover.
+ */
 export default class ErrorPopover {
     static $inject = ['$popover', '$anchorScroll', '$location', '$timeout', 'IgniteFormUtils'];
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/48d4a925/modules/web-console/frontend/app/services/JavaTypes.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/JavaTypes.service.js b/modules/web-console/frontend/app/services/JavaTypes.service.js
index e8d4903..8cb87be 100644
--- a/modules/web-console/frontend/app/services/JavaTypes.service.js
+++ b/modules/web-console/frontend/app/services/JavaTypes.service.js
@@ -15,79 +15,104 @@
  * limitations under the License.
  */
 
+import _ from 'lodash';
+
 // Java built-in class names.
 import JAVA_CLASSES from '../data/java-classes.json';
 
-// Java build-in primitive.
+// Java build-in primitives.
 import JAVA_PRIMITIVES from '../data/java-primitives.json';
 
+// Java keywords.
 import JAVA_KEYWORDS from '../data/java-keywords.json';
 
-export default ['JavaTypes', function() {
-    return {
-        /**
-         * @param {String} clsName Class name to check.
-         * @returns boolean 'true' if given class name non a Java built-in type.
-         */
-        nonBuiltInClass(clsName) {
-            return _.isNil(_.find(JAVA_CLASSES, (clazz) => clsName === clazz.short || clsName === clazz.full));
-        },
-        /**
-         * @param clsName Class name to check.
-         * @returns Full class name for java build-in types or source class otherwise.
-         */
-        fullClassName(clsName) {
-            const type = _.find(JAVA_CLASSES, (clazz) => clsName === clazz.short);
-
-            return type ? type.full : clsName;
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is valid Java identifier.
-         */
-        validIdentifier(value) {
-            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*)$/igm;
-
-            return value === '' || regexp.test(value);
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is valid Java package.
-         */
-        validPackage(value) {
-            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*(\.?\*)?)$/igm;
-
-            return value === '' || regexp.test(value);
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is valid Java UUID value.
-         */
-        validUUID(value) {
-            const regexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/igm;
-
-            return value === '' || regexp.test(value);
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is a Java type with package.
-         */
-        packageSpecified(value) {
-            return value.split('.').length >= 2;
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text non Java keyword.
-         */
-        isKeywords(value) {
-            return _.includes(JAVA_KEYWORDS, value);
-        },
-        /**
-         * @param {String} clsName Class name to check.
-         * @returns {boolean} 'true' if givent class name is java primitive.
-         */
-        isJavaPrimitive(clsName) {
-            return _.includes(JAVA_PRIMITIVES, clsName);
-        }
-    };
-}];
+// Regular expression to check Java identifier.
+const VALID_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/im;
+
+// Regular expression to check Java class name.
+const VALID_CLASS_NAME = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*)$/im;
+
+// Regular expression to check Java package.
+const VALID_PACKAGE = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*(\.?\*)?)$/im;
+
+// Regular expression to check UUID string representation.
+const VALID_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/im;
+
+/**
+ * Utility service for various check on java types.
+ */
+export default class JavaTypes {
+    /**
+     * @param clsName {String} Class name to check.
+     * @returns {boolean} 'true' if provided class name is a not Java built in class.
+     */
+    nonBuiltInClass(clsName) {
+        return _.isNil(_.find(JAVA_CLASSES, (clazz) => clsName === clazz.short || clsName === clazz.full));
+    }
+
+    /**
+     * @param clsName Class name to check.
+     * @returns Full class name for java build-in types or source class otherwise.
+     */
+    fullClassName(clsName) {
+        const type = _.find(JAVA_CLASSES, (clazz) => clsName === clazz.short);
+
+        return type ? type.full : clsName;
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given text is valid Java class name.
+     */
+    validIdentifier(value) {
+        return !!(value && VALID_IDENTIFIER.test(value));
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given text is valid Java class name.
+     */
+    validClassName(value) {
+        return !!(value && VALID_CLASS_NAME.test(value));
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given text is valid Java package.
+     */
+    validPackage(value) {
+        return !!(value && VALID_PACKAGE.test(value));
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given text is valid Java UUID value.
+     */
+    validUUID(value) {
+        return !!(value && VALID_UUID.test(value));
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given text is a Java type with package.
+     */
+    packageSpecified(value) {
+        return value.split('.').length >= 2;
+    }
+
+    /**
+     * @param value {String} Value text to check.
+     * @returns {boolean} 'true' if given value is one of Java reserved keywords.
+     */
+    isKeyword(value) {
+        return !!(value && _.includes(JAVA_KEYWORDS, value.toLowerCase()));
+    }
+
+    /**
+     * @param {String} clsName Class name to check.
+     * @returns {boolean} 'true' if given class name is java primitive.
+     */
+    isJavaPrimitive(clsName) {
+        return _.includes(JAVA_PRIMITIVES, clsName);
+    }
+}