ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anovi...@apache.org
Subject [28/50] [abbrv] ignite git commit: IGNITE-3620 Moved popover functions and form function in separated services.
Date Thu, 08 Sep 2016 04:46:45 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/27176d59/modules/web-console/frontend/app/services/LegacyUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/LegacyUtils.service.js b/modules/web-console/frontend/app/services/LegacyUtils.service.js
index 21fab0c..6328895 100644
--- a/modules/web-console/frontend/app/services/LegacyUtils.service.js
+++ b/modules/web-console/frontend/app/services/LegacyUtils.service.js
@@ -16,958 +16,561 @@
  */
 
 // TODO: Refactor this service for legacy tables with more than one input field.
-export default ['IgniteLegacyUtils', [
-    '$alert', '$popover', '$anchorScroll', '$location', '$timeout', '$window', 'IgniteFocus',
-    ($alert, $popover, $anchorScroll, $location, $timeout, $window, Focus) => {
-        $anchorScroll.yOffset = 55;
-
-        function isDefined(v) {
-            return !_.isNil(v);
-        }
-
-        function isEmptyString(s) {
-            if (isDefined(s))
-                return s.trim().length === 0;
-
-            return true;
-        }
-
-        const javaBuiltInClasses = [
-            'BigDecimal', 'Boolean', 'Byte', 'Date', 'Double', 'Float', 'Integer', 'Long', 'Object', 'Short', 'String', 'Time', 'Timestamp', 'UUID'
-        ];
-
-        const javaBuiltInTypes = [
-            'BigDecimal', 'boolean', 'Boolean', 'byte', 'Byte', 'Date', 'double', 'Double', 'float', 'Float',
-            'int', 'Integer', 'long', 'Long', 'Object', 'short', 'Short', 'String', 'Time', 'Timestamp', 'UUID'
-        ];
-
-        const javaBuiltInFullNameClasses = [
-            'java.math.BigDecimal', 'java.lang.Boolean', 'java.lang.Byte', 'java.sql.Date', 'java.lang.Double',
-            'java.lang.Float', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Object', 'java.lang.Short',
-            'java.lang.String', 'java.sql.Time', 'java.sql.Timestamp', 'java.util.UUID'
-        ];
-
-        /**
-         * @param clsName Class name to check.
-         * @returns {Boolean} 'true' if given class name is a java build-in type.
-         */
-        function isJavaBuiltInClass(clsName) {
-            if (isEmptyString(clsName))
-                return false;
-
-            return _.includes(javaBuiltInClasses, clsName) || _.includes(javaBuiltInFullNameClasses, clsName);
-        }
-
-        const SUPPORTED_JDBC_TYPES = [
-            'BIGINT',
-            'BIT',
-            'BOOLEAN',
-            'BLOB',
-            'CHAR',
-            'CLOB',
-            'DATE',
-            'DECIMAL',
-            'DOUBLE',
-            'FLOAT',
-            'INTEGER',
-            'LONGNVARCHAR',
-            'LONGVARCHAR',
-            'NCHAR',
-            'NUMERIC',
-            'NVARCHAR',
-            'REAL',
-            'SMALLINT',
-            'TIME',
-            'TIMESTAMP',
-            'TINYINT',
-            'VARCHAR'
-        ];
-
-        const ALL_JDBC_TYPES = [
-            {dbName: 'BIT', dbType: -7, javaType: 'Boolean', primitiveType: 'boolean'},
-            {dbName: 'TINYINT', dbType: -6, javaType: 'Byte', primitiveType: 'byte'},
-            {dbName: 'SMALLINT', dbType: 5, javaType: 'Short', primitiveType: 'short'},
-            {dbName: 'INTEGER', dbType: 4, javaType: 'Integer', primitiveType: 'int'},
-            {dbName: 'BIGINT', dbType: -5, javaType: 'Long', primitiveType: 'long'},
-            {dbName: 'FLOAT', dbType: 6, javaType: 'Float', primitiveType: 'float'},
-            {dbName: 'REAL', dbType: 7, javaType: 'Double', primitiveType: 'double'},
-            {dbName: 'DOUBLE', dbType: 8, javaType: 'Double', primitiveType: 'double'},
-            {dbName: 'NUMERIC', dbType: 2, javaType: 'BigDecimal'},
-            {dbName: 'DECIMAL', dbType: 3, javaType: 'BigDecimal'},
-            {dbName: 'CHAR', dbType: 1, javaType: 'String'},
-            {dbName: 'VARCHAR', dbType: 12, javaType: 'String'},
-            {dbName: 'LONGVARCHAR', dbType: -1, javaType: 'String'},
-            {dbName: 'DATE', dbType: 91, javaType: 'Date'},
-            {dbName: 'TIME', dbType: 92, javaType: 'Time'},
-            {dbName: 'TIMESTAMP', dbType: 93, javaType: 'Timestamp'},
-            {dbName: 'BINARY', dbType: -2, javaType: 'Object'},
-            {dbName: 'VARBINARY', dbType: -3, javaType: 'Object'},
-            {dbName: 'LONGVARBINARY', dbType: -4, javaType: 'Object'},
-            {dbName: 'NULL', dbType: 0, javaType: 'Object'},
-            {dbName: 'OTHER', dbType: 1111, javaType: 'Object'},
-            {dbName: 'JAVA_OBJECT', dbType: 2000, javaType: 'Object'},
-            {dbName: 'DISTINCT', dbType: 2001, javaType: 'Object'},
-            {dbName: 'STRUCT', dbType: 2002, javaType: 'Object'},
-            {dbName: 'ARRAY', dbType: 2003, javaType: 'Object'},
-            {dbName: 'BLOB', dbType: 2004, javaType: 'Object'},
-            {dbName: 'CLOB', dbType: 2005, javaType: 'String'},
-            {dbName: 'REF', dbType: 2006, javaType: 'Object'},
-            {dbName: 'DATALINK', dbType: 70, javaType: 'Object'},
-            {dbName: 'BOOLEAN', dbType: 16, javaType: 'Boolean', primitiveType: 'boolean'},
-            {dbName: 'ROWID', dbType: -8, javaType: 'Object'},
-            {dbName: 'NCHAR', dbType: -15, javaType: 'String'},
-            {dbName: 'NVARCHAR', dbType: -9, javaType: 'String'},
-            {dbName: 'LONGNVARCHAR', dbType: -16, javaType: 'String'},
-            {dbName: 'NCLOB', dbType: 2011, javaType: 'String'},
-            {dbName: 'SQLXML', dbType: 2009, javaType: 'Object'}
-        ];
-
-        /*eslint-disable */
-        const JAVA_KEYWORDS = [
-            'abstract',     'assert',        'boolean',      'break',           'byte',
-            'case',         'catch',         'char',         'class',           'const',
-            'continue',     'default',       'do',           'double',          'else',
-            'enum',         'extends',       'false',        'final',           'finally',
-            'float',        'for',           'goto',         'if',              'implements',
-            'import',       'instanceof',    'int',          'interface',       'long',
-            'native',       'new',           'null',         'package',         'private',
-            'protected',    'public',        'return',       'short',           'static',
-            'strictfp',     'super',         'switch',       'synchronized',    'this',
-            'throw',        'throws',        'transient',    'true',            'try',
-            'void',         'volatile',      'while'
-        ];
-        /*eslint-enable */
-
-        const VALID_JAVA_IDENTIFIER = new RegExp('^[a-zA-Z_$][a-zA-Z\\d_$]*$');
-
-        let popover = null;
-
-        function isElementInViewport(el) {
-            const rect = el.getBoundingClientRect();
-
-            return (
-                rect.top >= 0 &&
-                rect.left >= 0 &&
-                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
-                rect.right <= (window.innerWidth || document.documentElement.clientWidth)
-            );
-        }
-
-        const _showPopoverMessage = (id, message, showTime) => {
-            const body = $('body');
-
-            let el = body.find('#' + id);
-
-            if (!el || el.length === 0)
-                el = body.find('[name="' + id + '"]');
-
-            if (el && el.length > 0) {
-                if (!isElementInViewport(el[0])) {
-                    $location.hash(el[0].id);
-
-                    $anchorScroll();
-                }
-
-                const newPopover = $popover(el, {content: message});
-
-                popover = newPopover;
-
-                $timeout(() => newPopover.$promise.then(() => {
-                    newPopover.show();
-
-                    // Workaround to fix popover location when content is longer than content template.
-                    // https://github.com/mgcrea/angular-strap/issues/1497
-                    $timeout(newPopover.$applyPlacement);
-                }), 400);
-                $timeout(() => newPopover.hide(), showTime || 5000);
-            }
-        };
-
-        function ensureActivePanel(ui, pnl, focusId) {
-            if (ui) {
-                const collapses = $('div.panel-collapse');
-
-                ui.loadPanel(pnl);
-
-                const idx = _.findIndex(collapses, function(collapse) {
-                    return collapse.id === pnl;
-                });
+export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
+    function isDefined(v) {
+        return !_.isNil(v);
+    }
 
-                if (idx >= 0) {
-                    const activePanels = ui.activePanels;
+    function isEmptyString(s) {
+        if (isDefined(s))
+            return s.trim().length === 0;
 
-                    if (!_.includes(ui.topPanels, idx)) {
-                        ui.expanded = true;
+        return true;
+    }
 
-                        const customExpanded = ui[pnl];
+    const javaBuiltInClasses = [
+        'BigDecimal',
+        'Boolean',
+        'Byte',
+        'Date',
+        'Double',
+        'Float',
+        'Integer',
+        'Long',
+        'Object',
+        'Short',
+        'String',
+        'Time',
+        'Timestamp',
+        'UUID'
+    ];
+
+    const javaBuiltInTypes = [
+        'BigDecimal',
+        'boolean',
+        'Boolean',
+        'byte',
+        'Byte',
+        'Date',
+        'double',
+        'Double',
+        'float',
+        'Float',
+        'int',
+        'Integer',
+        'long',
+        'Long',
+        'Object',
+        'short',
+        'Short',
+        'String',
+        'Time',
+        'Timestamp',
+        'UUID'
+    ];
+
+    const javaBuiltInFullNameClasses = [
+        'java.math.BigDecimal',
+        'java.lang.Boolean',
+        'java.lang.Byte',
+        'java.sql.Date',
+        'java.lang.Double',
+        'java.lang.Float',
+        'java.lang.Integer',
+        'java.lang.Long',
+        'java.lang.Object',
+        'java.lang.Short',
+        'java.lang.String',
+        'java.sql.Time',
+        'java.sql.Timestamp',
+        'java.util.UUID'
+    ];
+
+    /**
+     * @param clsName Class name to check.
+     * @returns {Boolean} 'true' if given class name is a java build-in type.
+     */
+    function isJavaBuiltInClass(clsName) {
+        if (isEmptyString(clsName))
+            return false;
 
-                        if (customExpanded)
-                            ui[customExpanded] = true;
-                    }
+        return _.includes(javaBuiltInClasses, clsName) || _.includes(javaBuiltInFullNameClasses, clsName);
+    }
 
-                    if (!activePanels || activePanels.length < 1)
-                        ui.activePanels = [idx];
-                    else if (!_.includes(activePanels, idx)) {
-                        const newActivePanels = angular.copy(activePanels);
+    const SUPPORTED_JDBC_TYPES = [
+        'BIGINT',
+        'BIT',
+        'BOOLEAN',
+        'BLOB',
+        'CHAR',
+        'CLOB',
+        'DATE',
+        'DECIMAL',
+        'DOUBLE',
+        'FLOAT',
+        'INTEGER',
+        'LONGNVARCHAR',
+        'LONGVARCHAR',
+        'NCHAR',
+        'NUMERIC',
+        'NVARCHAR',
+        'REAL',
+        'SMALLINT',
+        'TIME',
+        'TIMESTAMP',
+        'TINYINT',
+        'VARCHAR'
+    ];
+
+    const ALL_JDBC_TYPES = [
+        {dbName: 'BIT', dbType: -7, javaType: 'Boolean', primitiveType: 'boolean'},
+        {dbName: 'TINYINT', dbType: -6, javaType: 'Byte', primitiveType: 'byte'},
+        {dbName: 'SMALLINT', dbType: 5, javaType: 'Short', primitiveType: 'short'},
+        {dbName: 'INTEGER', dbType: 4, javaType: 'Integer', primitiveType: 'int'},
+        {dbName: 'BIGINT', dbType: -5, javaType: 'Long', primitiveType: 'long'},
+        {dbName: 'FLOAT', dbType: 6, javaType: 'Float', primitiveType: 'float'},
+        {dbName: 'REAL', dbType: 7, javaType: 'Double', primitiveType: 'double'},
+        {dbName: 'DOUBLE', dbType: 8, javaType: 'Double', primitiveType: 'double'},
+        {dbName: 'NUMERIC', dbType: 2, javaType: 'BigDecimal'},
+        {dbName: 'DECIMAL', dbType: 3, javaType: 'BigDecimal'},
+        {dbName: 'CHAR', dbType: 1, javaType: 'String'},
+        {dbName: 'VARCHAR', dbType: 12, javaType: 'String'},
+        {dbName: 'LONGVARCHAR', dbType: -1, javaType: 'String'},
+        {dbName: 'DATE', dbType: 91, javaType: 'Date'},
+        {dbName: 'TIME', dbType: 92, javaType: 'Time'},
+        {dbName: 'TIMESTAMP', dbType: 93, javaType: 'Timestamp'},
+        {dbName: 'BINARY', dbType: -2, javaType: 'Object'},
+        {dbName: 'VARBINARY', dbType: -3, javaType: 'Object'},
+        {dbName: 'LONGVARBINARY', dbType: -4, javaType: 'Object'},
+        {dbName: 'NULL', dbType: 0, javaType: 'Object'},
+        {dbName: 'OTHER', dbType: 1111, javaType: 'Object'},
+        {dbName: 'JAVA_OBJECT', dbType: 2000, javaType: 'Object'},
+        {dbName: 'DISTINCT', dbType: 2001, javaType: 'Object'},
+        {dbName: 'STRUCT', dbType: 2002, javaType: 'Object'},
+        {dbName: 'ARRAY', dbType: 2003, javaType: 'Object'},
+        {dbName: 'BLOB', dbType: 2004, javaType: 'Object'},
+        {dbName: 'CLOB', dbType: 2005, javaType: 'String'},
+        {dbName: 'REF', dbType: 2006, javaType: 'Object'},
+        {dbName: 'DATALINK', dbType: 70, javaType: 'Object'},
+        {dbName: 'BOOLEAN', dbType: 16, javaType: 'Boolean', primitiveType: 'boolean'},
+        {dbName: 'ROWID', dbType: -8, javaType: 'Object'},
+        {dbName: 'NCHAR', dbType: -15, javaType: 'String'},
+        {dbName: 'NVARCHAR', dbType: -9, javaType: 'String'},
+        {dbName: 'LONGNVARCHAR', dbType: -16, javaType: 'String'},
+        {dbName: 'NCLOB', dbType: 2011, javaType: 'String'},
+        {dbName: 'SQLXML', dbType: 2009, javaType: 'Object'}
+    ];
+
+    /*eslint-disable */
+    const JAVA_KEYWORDS = [
+        'abstract',
+        'assert',
+        'boolean',
+        'break',
+        'byte',
+        'case',
+        'catch',
+        'char',
+        'class',
+        'const',
+        'continue',
+        'default',
+        'do',
+        'double',
+        'else',
+        'enum',
+        'extends',
+        'false',
+        'final',
+        'finally',
+        'float',
+        'for',
+        'goto',
+        'if',
+        'implements',
+        'import',
+        'instanceof',
+        'int',
+        'interface',
+        'long',
+        'native',
+        'new',
+        'null',
+        'package',
+        'private',
+        'protected',
+        'public',
+        'return',
+        'short',
+        'static',
+        'strictfp',
+        'super',
+        'switch',
+        'synchronized',
+        'this',
+        'throw',
+        'throws',
+        'transient',
+        'true',
+        'try',
+        'void',
+        'volatile',
+        'while'
+    ];
+    /*eslint-enable */
+
+    const VALID_JAVA_IDENTIFIER = new RegExp('^[a-zA-Z_$][a-zA-Z\\d_$]*$');
+
+    function isValidJavaIdentifier(msg, ident, elemId, panels, panelId) {
+        if (isEmptyString(ident))
+            return ErrorPopover.show(elemId, msg + ' is invalid!', panels, panelId);
+
+        if (_.includes(JAVA_KEYWORDS, ident))
+            return ErrorPopover.show(elemId, msg + ' could not contains reserved java keyword: "' + ident + '"!', panels, panelId);
+
+        if (!VALID_JAVA_IDENTIFIER.test(ident))
+            return ErrorPopover.show(elemId, msg + ' contains invalid identifier: "' + ident + '"!', panels, panelId);
+
+        return true;
+    }
 
-                        newActivePanels.push(idx);
+    function getModel(obj, field) {
+        let path = field.path;
 
-                        ui.activePanels = newActivePanels;
-                    }
-                }
+        if (!isDefined(path) || !isDefined(obj))
+            return obj;
 
-                if (isDefined(focusId))
-                    Focus.move(focusId);
-            }
-        }
+        path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+        path = path.replace(/^\./, '');           // strip a leading dot
 
-        function showPopoverMessage(ui, panelId, id, message, showTime) {
-            if (popover)
-                popover.hide();
+        const segs = path.split('.');
+        let root = obj;
 
-            if (ui) {
-                ensureActivePanel(ui, panelId);
+        while (segs.length > 0) {
+            const pathStep = segs.shift();
 
-                $timeout(() => _showPopoverMessage(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500);
-            }
-            else
-                _showPopoverMessage(id, message, showTime);
+            if (typeof root[pathStep] === 'undefined')
+                root[pathStep] = {};
 
-            return false;
+            root = root[pathStep];
         }
 
-        function isValidJavaIdentifier(msg, ident, elemId, panels, panelId) {
-            if (isEmptyString(ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' is invalid!');
-
-            if (_.includes(JAVA_KEYWORDS, ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' could not contains reserved java keyword: "' + ident + '"!');
-
-            if (!VALID_JAVA_IDENTIFIER.test(ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' contains invalid identifier: "' + ident + '"!');
+        return root;
+    }
 
-            return true;
+    /**
+     * Extract datasource from cache or cluster.
+     *
+     * @param object Cache or cluster to extract datasource.
+     * @returns {*} Datasource object or null if not set.
+     */
+    function extractDataSource(object) {
+        // Extract from cluster object
+        if (_.get(object, 'discovery.kind') === 'Jdbc') {
+            const datasource = object.discovery.Jdbc;
+
+            if (datasource.dataSourceBean && datasource.dialect)
+                return datasource;
+        } // Extract from cache object
+        else if (_.get(object, 'cacheStoreFactory.kind')) {
+            const storeFactory = object.cacheStoreFactory[object.cacheStoreFactory.kind];
+
+            if (storeFactory.dialect || (storeFactory.connectVia === 'DataSource'))
+                return storeFactory;
         }
 
-        let context = null;
-
-        /**
-         * Calculate width of specified text in body's font.
-         *
-         * @param text Text to calculate width.
-         * @returns {Number} Width of text in pixels.
-         */
-        function measureText(text) {
-            if (!context) {
-                const canvas = document.createElement('canvas');
-
-                context = canvas.getContext('2d');
-
-                const style = window.getComputedStyle(document.getElementsByTagName('body')[0]);
+        return null;
+    }
 
-                context.font = style.fontSize + ' ' + style.fontFamily;
-            }
+    const cacheStoreJdbcDialects = [
+        {value: 'Generic', label: 'Generic JDBC'},
+        {value: 'Oracle', label: 'Oracle'},
+        {value: 'DB2', label: 'IBM DB2'},
+        {value: 'SQLServer', label: 'Microsoft SQL Server'},
+        {value: 'MySQL', label: 'MySQL'},
+        {value: 'PostgreSQL', label: 'PostgreSQL'},
+        {value: 'H2', label: 'H2 database'}
+    ];
+
+    function domainForStoreConfigured(domain) {
+        const isEmpty = !isDefined(domain) || (isEmptyString(domain.databaseSchema) &&
+            isEmptyString(domain.databaseTable) &&
+            _.isEmpty(domain.keyFields) &&
+            _.isEmpty(domain.valueFields));
+
+        return !isEmpty;
+    }
 
-            return context.measureText(text).width;
+    const DS_CHECK_SUCCESS = {checked: true};
+
+    /**
+     * Compare datasources of caches or clusters.
+     *
+     * @param firstObj First cache or cluster.
+     * @param secondObj Second cache or cluster.
+     * @returns {*} Check result object.
+     */
+    function compareDataSources(firstObj, secondObj) {
+        const firstDs = extractDataSource(firstObj);
+        const secondDs = extractDataSource(secondObj);
+
+        if (firstDs && secondDs) {
+            const firstDB = firstDs.dialect;
+            const secondDB = secondDs.dialect;
+
+            if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB)
+                return {checked: false, firstObj, firstDB, secondObj, secondDB};
         }
 
-        /**
-         * Compact java full class name by max number of characters.
-         *
-         * @param names Array of class names to compact.
-         * @param nameLength Max available width in characters for simple name.
-         * @returns {*} Array of compacted class names.
-         */
-        function compactByMaxCharts(names, nameLength) {
-            for (let nameIx = 0; nameIx < names.length; nameIx++) {
-                const s = names[nameIx];
-
-                if (s.length > nameLength) {
-                    let totalLength = s.length;
-
-                    const packages = s.split('.');
-
-                    const packageCnt = packages.length - 1;
-
-                    for (let i = 0; i < packageCnt && totalLength > nameLength; i++) {
-                        if (packages[i].length > 0) {
-                            totalLength -= packages[i].length - 1;
-
-                            packages[i] = packages[i][0];
-                        }
-                    }
-
-                    if (totalLength > nameLength) {
-                        const className = packages[packageCnt];
-
-                        const classNameLen = className.length;
+        return DS_CHECK_SUCCESS;
+    }
 
-                        let remains = Math.min(nameLength - totalLength + classNameLen, classNameLen);
+    function compareSQLSchemaNames(firstCache, secondCache) {
+        const firstName = firstCache.sqlSchema;
+        const secondName = secondCache.sqlSchema;
 
-                        if (remains < 3)
-                            remains = Math.min(3, classNameLen);
+        if (firstName && secondName && (firstName === secondName))
+            return {checked: false, firstCache, secondCache};
 
-                        packages[packageCnt] = className.substring(0, remains) + '...';
-                    }
+        return DS_CHECK_SUCCESS;
+    }
 
-                    let result = packages[0];
+    function toJavaName(prefix, name) {
+        const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
 
-                    for (let i = 1; i < packages.length; i++)
-                        result += '.' + packages[i];
+        return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
+    }
 
-                    names[nameIx] = result;
+    return {
+        getModel,
+        mkOptions(options) {
+            return _.map(options, (option) => {
+                return {value: option, label: isDefined(option) ? option : 'Not set'};
+            });
+        },
+        isDefined,
+        hasProperty(obj, props) {
+            for (const propName in props) {
+                if (props.hasOwnProperty(propName)) {
+                    if (obj[propName])
+                        return true;
                 }
             }
 
-            return names;
-        }
-
-        /**
-         * Compact java full class name by max number of pixels.
-         *
-         * @param names Array of class names to compact.
-         * @param nameLength Max available width in characters for simple name. Used for calculation optimization.
-         * @param nameWidth Maximum available width in pixels for simple name.
-         * @returns {*} Array of compacted class names.
-         */
-        function compactByMaxPixels(names, nameLength, nameWidth) {
-            if (nameWidth <= 0)
-                return names;
-
-            const fitted = [];
-
-            const widthByName = [];
-
-            const len = names.length;
-
-            let divideTo = len;
-
-            for (let nameIx = 0; nameIx < len; nameIx++) {
-                fitted[nameIx] = false;
-
-                widthByName[nameIx] = nameWidth;
-            }
-
-            // Try to distribute space from short class names to long class names.
-            let remains = 0;
-
-            do {
-                for (let nameIx = 0; nameIx < len; nameIx++) {
-                    if (!fitted[nameIx]) {
-                        const curNameWidth = measureText(names[nameIx]);
+            return false;
+        },
+        isEmptyString,
+        SUPPORTED_JDBC_TYPES,
+        findJdbcType(jdbcType) {
+            const res = _.find(ALL_JDBC_TYPES, function (item) {
+                return item.dbType === jdbcType;
+            });
+
+            return res ? res : {dbName: 'Unknown', javaType: 'Unknown'};
+        },
+        javaBuiltInClasses,
+        javaBuiltInTypes,
+        isJavaBuiltInClass,
+        isValidJavaIdentifier,
+        isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId) {
+            if (isEmptyString(ident))
+                return ErrorPopover.show(elemId, msg + ' could not be empty!', panels, panelId);
 
-                        if (widthByName[nameIx] > curNameWidth) {
-                            fitted[nameIx] = true;
+            const parts = ident.split('.');
 
-                            remains += widthByName[nameIx] - curNameWidth;
+            const len = parts.length;
 
-                            divideTo -= 1;
+            if (!allowBuiltInClass && isJavaBuiltInClass(ident))
+                return ErrorPopover.show(elemId, msg + ' should not be the Java build-in class!', panels, panelId);
 
-                            widthByName[nameIx] = curNameWidth;
-                        }
-                    }
-                }
+            if (len < 2 && !isJavaBuiltInClass(ident) && !packageOnly)
+                return ErrorPopover.show(elemId, msg + ' does not have package specified!', panels, panelId);
 
-                const remainsByName = remains / divideTo;
+            for (let i = 0; i < parts.length; i++) {
+                const part = parts[i];
 
-                for (let nameIx = 0; nameIx < len; nameIx++) {
-                    if (!fitted[nameIx])
-                        widthByName[nameIx] += remainsByName;
-                }
+                if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId))
+                    return false;
             }
-            while (remains > 0);
 
-            // Compact class names to available for each space.
-            for (let nameIx = 0; nameIx < len; nameIx++) {
-                const s = names[nameIx];
-
-                if (s.length > (nameLength / 2 | 0)) {
-                    let totalWidth = measureText(s);
+            return true;
+        },
+        domainForQueryConfigured(domain) {
+            const isEmpty = !isDefined(domain) || (_.isEmpty(domain.fields) &&
+                _.isEmpty(domain.aliases) &&
+                _.isEmpty(domain.indexes));
 
-                    if (totalWidth > widthByName[nameIx]) {
-                        const packages = s.split('.');
+            return !isEmpty;
+        },
+        domainForStoreConfigured,
+        download(type, name, data) {
+            const file = document.createElement('a');
 
-                        const packageCnt = packages.length - 1;
+            file.setAttribute('href', 'data:' + type + ';charset=utf-8,' + data);
+            file.setAttribute('download', name);
+            file.setAttribute('target', '_self');
 
-                        for (let i = 0; i < packageCnt && totalWidth > widthByName[nameIx]; i++) {
-                            if (packages[i].length > 1) {
-                                totalWidth -= measureText(packages[i].substring(1, packages[i].length));
+            file.style.display = 'none';
 
-                                packages[i] = packages[i][0];
-                            }
-                        }
+            document.body.appendChild(file);
 
-                        let shortPackage = '';
+            file.click();
 
-                        for (let i = 0; i < packageCnt; i++)
-                            shortPackage += packages[i] + '.';
+            document.body.removeChild(file);
+        },
+        getQueryVariable(name) {
+            const attrs = window.location.search.substring(1).split('&');
+            const attr = _.find(attrs, (a) => a === name || (a.indexOf('=') >= 0 && a.substr(0, a.indexOf('=')) === name));
 
-                        const className = packages[packageCnt];
-
-                        const classLen = className.length;
+            if (!isDefined(attr))
+                return null;
 
-                        let minLen = Math.min(classLen, 3);
+            if (attr === name)
+                return true;
 
-                        totalWidth = measureText(shortPackage + className);
+            return attr.substr(attr.indexOf('=') + 1);
+        },
+        cacheStoreJdbcDialects,
+        cacheStoreJdbcDialectsLabel(dialect) {
+            const found = _.find(cacheStoreJdbcDialects, function (dialectVal) {
+                return dialectVal.value === dialect;
+            });
 
-                        // Compact class name if shorten package path is very long.
-                        if (totalWidth > widthByName[nameIx]) {
-                            let maxLen = classLen;
-                            let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+            return found ? found.label : null;
+        },
+        checkDataSources(cluster, caches, checkCacheExt) {
+            let res = DS_CHECK_SUCCESS;
 
-                            while (middleLen !== minLen && middleLen !== maxLen) {
-                                const middleLenPx = measureText(shortPackage + className.substr(0, middleLen) + '...');
+            _.find(caches, function (curCache, curIx) {
+                res = compareDataSources(curCache, cluster);
 
-                                if (middleLenPx > widthByName[nameIx])
-                                    maxLen = middleLen;
-                                else
-                                    minLen = middleLen;
+                if (!res.checked)
+                    return true;
 
-                                middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-                            }
+                if (isDefined(checkCacheExt)) {
+                    if (checkCacheExt._id !== curCache._id) {
+                        res = compareDataSources(checkCacheExt, curCache);
 
-                            names[nameIx] = shortPackage + className.substring(0, middleLen) + '...';
-                        }
-                        else
-                            names[nameIx] = shortPackage + className;
+                        return !res.checked;
                     }
-                }
-            }
-
-            return names;
-        }
 
-        /**
-         * Compact any string by max number of pixels.
-         *
-         * @param label String to compact.
-         * @param nameWidth Maximum available width in pixels for simple name.
-         * @returns {*} Compacted string.
-         */
-        function compactLabelByPixels(label, nameWidth) {
-            if (nameWidth <= 0)
-                return label;
-
-            const totalWidth = measureText(label);
-
-            if (totalWidth > nameWidth) {
-                let maxLen = label.length;
-                let minLen = Math.min(maxLen, 3);
-                let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-
-                while (middleLen !== minLen && middleLen !== maxLen) {
-                    const middleLenPx = measureText(label.substr(0, middleLen) + '...');
-
-                    if (middleLenPx > nameWidth)
-                        maxLen = middleLen;
-                    else
-                        minLen = middleLen;
-
-                    middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+                    return false;
                 }
 
-                return label.substring(0, middleLen) + '...';
-            }
-
-            return label;
-        }
-
-        /**
-         * Calculate available width for text in link to edit element.
-         *
-         * @param index Showed index of element for calculation of maximum width in pixels.
-         * @param id Id of contains link table.
-         * @returns {*[]} First element is length of class for single value, second element is length for pair vlaue.
-         */
-        function availableWidth(index, id) {
-            const idElem = $('#' + id);
-
-            let width = 0;
-
-            switch (idElem.prop('tagName')) {
-                // Detection of available width in presentation table row.
-                case 'TABLE':
-                    const cont = $(idElem.find('tr')[index - 1]).find('td')[0];
-
-                    width = cont.clientWidth;
+                return _.find(caches, function (checkCache, checkIx) {
+                    if (checkIx < curIx) {
+                        res = compareDataSources(checkCache, curCache);
 
-                    if (width > 0) {
-                        const children = $(cont).children(':not("a")');
-
-                        _.forEach(children, function(child) {
-                            if ('offsetWidth' in child)
-                                width -= $(child).outerWidth(true);
-                        });
+                        return !res.checked;
                     }
 
-                    break;
-
-                // Detection of available width in dropdown row.
-                case 'A':
-                    width = idElem.width();
-
-                    $(idElem).children(':not("span")').each(function(ix, child) {
-                        if ('offsetWidth' in child)
-                            width -= child.offsetWidth;
-                    });
-
-                    break;
-
-                default:
-            }
-
-            return width | 0;
-        }
-
-        function getModel(obj, field) {
-            let path = field.path;
-
-            if (!isDefined(path) || !isDefined(obj))
-                return obj;
-
-            path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
-            path = path.replace(/^\./, '');           // strip a leading dot
-
-            const segs = path.split('.');
-            let root = obj;
-
-            while (segs.length > 0) {
-                const pathStep = segs.shift();
-
-                if (typeof root[pathStep] === 'undefined')
-                    root[pathStep] = {};
-
-                root = root[pathStep];
-            }
-
-            return root;
-        }
-
-        /**
-         * Extract datasource from cache or cluster.
-         *
-         * @param object Cache or cluster to extract datasource.
-         * @returns {*} Datasource object or null if not set.
-         */
-        function extractDataSource(object) {
-            // Extract from cluster object
-            if (_.get(object, 'discovery.kind') === 'Jdbc') {
-                const datasource = object.discovery.Jdbc;
-
-                if (datasource.dataSourceBean && datasource.dialect)
-                    return datasource;
-            } // Extract from cache object
-            else if (_.get(object, 'cacheStoreFactory.kind')) {
-                const storeFactory = object.cacheStoreFactory[object.cacheStoreFactory.kind];
-
-                if (storeFactory.dialect || (storeFactory.connectVia === 'DataSource'))
-                    return storeFactory;
-            }
-
-            return null;
-        }
-
-        const cacheStoreJdbcDialects = [
-            {value: 'Generic', label: 'Generic JDBC'},
-            {value: 'Oracle', label: 'Oracle'},
-            {value: 'DB2', label: 'IBM DB2'},
-            {value: 'SQLServer', label: 'Microsoft SQL Server'},
-            {value: 'MySQL', label: 'MySQL'},
-            {value: 'PostgreSQL', label: 'PostgreSQL'},
-            {value: 'H2', label: 'H2 database'}
-        ];
-
-        function domainForStoreConfigured(domain) {
-            const isEmpty = !isDefined(domain) || (isEmptyString(domain.databaseSchema) &&
-                isEmptyString(domain.databaseTable) &&
-                _.isEmpty(domain.keyFields) &&
-                _.isEmpty(domain.valueFields));
-
-            return !isEmpty;
-        }
-
-        const DS_CHECK_SUCCESS = { checked: true };
-
-        /**
-         * Compare datasources of caches or clusters.
-         *
-         * @param firstObj First cache or cluster.
-         * @param secondObj Second cache or cluster.
-         * @returns {*} Check result object.
-         */
-        function compareDataSources(firstObj, secondObj) {
-            const firstDs = extractDataSource(firstObj);
-            const secondDs = extractDataSource(secondObj);
-
-            if (firstDs && secondDs) {
-                const firstDB = firstDs.dialect;
-                const secondDB = secondDs.dialect;
-
-                if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB)
-                    return {checked: false, firstObj, firstDB, secondObj, secondDB};
-            }
-
-            return DS_CHECK_SUCCESS;
-        }
-
-        function compareSQLSchemaNames(firstCache, secondCache) {
-            const firstName = firstCache.sqlSchema;
-            const secondName = secondCache.sqlSchema;
-
-            if (firstName && secondName && (firstName === secondName))
-                return {checked: false, firstCache, secondCache};
-
-            return DS_CHECK_SUCCESS;
-        }
-
-        function toJavaName(prefix, name) {
-            const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
-
-            return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
-        }
-
-        return {
-            getModel,
-            mkOptions(options) {
-                return _.map(options, (option) => {
-                    return {value: option, label: isDefined(option) ? option : 'Not set'};
+                    return false;
                 });
-            },
-            isDefined,
-            hasProperty(obj, props) {
-                for (const propName in props) {
-                    if (props.hasOwnProperty(propName)) {
-                        if (obj[propName])
-                            return true;
-                    }
-                }
-
-                return false;
-            },
-            isEmptyString,
-            SUPPORTED_JDBC_TYPES,
-            findJdbcType(jdbcType) {
-                const res = _.find(ALL_JDBC_TYPES, function(item) {
-                    return item.dbType === jdbcType;
-                });
-
-                return res ? res : {dbName: 'Unknown', javaType: 'Unknown'};
-            },
-            javaBuiltInClasses,
-            javaBuiltInTypes,
-            isJavaBuiltInClass,
-            isValidJavaIdentifier,
-            isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId) {
-                if (isEmptyString(ident))
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' could not be empty!');
-
-                const parts = ident.split('.');
+            });
 
-                const len = parts.length;
-
-                if (!allowBuiltInClass && isJavaBuiltInClass(ident))
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' should not be the Java build-in class!');
-
-                if (len < 2 && !isJavaBuiltInClass(ident) && !packageOnly)
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' does not have package specified!');
-
-                for (let i = 0; i < parts.length; i++) {
-                    const part = parts[i];
-
-                    if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId))
-                        return false;
-                }
-
-                return true;
-            },
-            domainForQueryConfigured(domain) {
-                const isEmpty = !isDefined(domain) || (_.isEmpty(domain.fields) &&
-                    _.isEmpty(domain.aliases) &&
-                    _.isEmpty(domain.indexes));
-
-                return !isEmpty;
-            },
-            domainForStoreConfigured,
-            /**
-             * Cut class name by width in pixel or width in symbol count.
-             *
-             * @param id Id of parent table.
-             * @param index Row number in table.
-             * @param maxLength Maximum length in symbols for all names.
-             * @param names Array of class names to compact.
-             * @param divider String to visualy divide items.
-             * @returns {*} Array of compacted class names.
-             */
-            compactJavaName(id, index, maxLength, names, divider) {
-                divider = ' ' + divider + ' ';
-
-                const prefix = index + ') ';
-
-                const nameCnt = names.length;
-
-                const nameLength = ((maxLength - 3 * (nameCnt - 1)) / nameCnt) | 0;
-
-                try {
-                    const nameWidth = (availableWidth(index, id) - measureText(prefix) - (nameCnt - 1) * measureText(divider)) /
-                        nameCnt | 0;
-
-                    // HTML5 calculation of showed message width.
-                    names = compactByMaxPixels(names, nameLength, nameWidth);
-                }
-                catch (err) {
-                    names = compactByMaxCharts(names, nameLength);
-                }
-
-                let result = prefix + names[0];
-
-                for (let nameIx = 1; nameIx < names.length; nameIx++)
-                    result += divider + names[nameIx];
-
-                return result;
-            },
-            /**
-             * Compact text by width in pixels or symbols count.
-             *
-             * @param id Id of parent table.
-             * @param index Row number in table.
-             * @param maxLength Maximum length in symbols for all names.
-             * @param label Text to compact.
-             * @returns Compacted label text.
-             */
-            compactTableLabel(id, index, maxLength, label) {
-                label = index + ') ' + label;
-
-                try {
-                    const nameWidth = availableWidth(index, id) | 0;
-
-                    // HTML5 calculation of showed message width.
-                    label = compactLabelByPixels(label, nameWidth);
-                }
-                catch (err) {
-                    const nameLength = maxLength - 3 | 0;
-
-                    label = label.length > maxLength ? label.substr(0, nameLength) + '...' : label;
-                }
+            return res;
+        },
+        checkCacheSQLSchemas(caches, checkCacheExt) {
+            let res = DS_CHECK_SUCCESS;
 
-                return label;
-            },
-            widthIsSufficient(id, index, text) {
-                try {
-                    const available = availableWidth(index, id);
+            _.find(caches, (curCache, curIx) => {
+                if (isDefined(checkCacheExt)) {
+                    if (checkCacheExt._id !== curCache._id) {
+                        res = compareSQLSchemaNames(checkCacheExt, curCache);
 
-                    const required = measureText(text);
+                        return !res.checked;
+                    }
 
-                    return !available || available >= Math.floor(required);
-                }
-                catch (err) {
-                    return true;
-                }
-            },
-            ensureActivePanel(panels, id, focusId) {
-                ensureActivePanel(panels, id, focusId);
-            },
-            showPopoverMessage,
-            hidePopover() {
-                if (popover)
-                    popover.hide();
-            },
-            confirmUnsavedChanges(dirty, selectFunc) {
-                if (dirty) {
-                    if ($window.confirm('You have unsaved changes.\n\nAre you sure you want to discard them?'))
-                        selectFunc();
+                    return false;
                 }
-                else
-                    selectFunc();
-            },
-            saveBtnTipText(dirty, objectName) {
-                if (dirty)
-                    return 'Save ' + objectName;
 
-                return 'Nothing to save';
-            },
-            download(type, name, data) {
-                const file = document.createElement('a');
+                return _.find(caches, function (checkCache, checkIx) {
+                    if (checkIx < curIx) {
+                        res = compareSQLSchemaNames(checkCache, curCache);
 
-                file.setAttribute('href', 'data:' + type + ';charset=utf-8,' + data);
-                file.setAttribute('download', name);
-                file.setAttribute('target', '_self');
+                        return !res.checked;
+                    }
 
-                file.style.display = 'none';
+                    return false;
+                });
+            });
 
-                document.body.appendChild(file);
+            return res;
+        },
+        autoCacheStoreConfiguration(cache, domains) {
+            const cacheStoreFactory = isDefined(cache.cacheStoreFactory) &&
+                isDefined(cache.cacheStoreFactory.kind);
 
-                file.click();
+            if (!cacheStoreFactory && _.findIndex(domains, domainForStoreConfigured) >= 0) {
+                const dflt = !cache.readThrough && !cache.writeThrough;
 
-                document.body.removeChild(file);
-            },
-            formUI() {
                 return {
-                    ready: false,
-                    expanded: false,
-                    loadedPanels: [],
-                    loadPanel(pnl) {
-                        if (!_.includes(this.loadedPanels, pnl))
-                            this.loadedPanels.push(pnl);
+                    cacheStoreFactory: {
+                        kind: 'CacheJdbcPojoStoreFactory',
+                        CacheJdbcPojoStoreFactory: {
+                            dataSourceBean: toJavaName('ds', cache.name),
+                            dialect: 'Generic'
+                        },
+                        CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}
                     },
-                    isPanelLoaded(pnl) {
-                        return _.includes(this.loadedPanels, pnl);
-                    }
+                    readThrough: dflt || cache.readThrough,
+                    writeThrough: dflt || cache.writeThrough
                 };
-            },
-            getQueryVariable(name) {
-                const attrs = window.location.search.substring(1).split('&');
-                const attr = _.find(attrs, (a) => a === name || (a.indexOf('=') >= 0 && a.substr(0, a.indexOf('=')) === name));
-
-                if (!isDefined(attr))
-                    return null;
-
-                if (attr === name)
-                    return true;
-
-                return attr.substr(attr.indexOf('=') + 1);
-            },
-            cacheStoreJdbcDialects,
-            cacheStoreJdbcDialectsLabel(dialect) {
-                const found = _.find(cacheStoreJdbcDialects, function(dialectVal) {
-                    return dialectVal.value === dialect;
-                });
-
-                return found ? found.label : null;
-            },
-            checkDataSources(cluster, caches, checkCacheExt) {
-                let res = DS_CHECK_SUCCESS;
-
-                _.find(caches, function(curCache, curIx) {
-                    res = compareDataSources(curCache, cluster);
-
-                    if (!res.checked)
-                        return true;
-
-                    if (isDefined(checkCacheExt)) {
-                        if (checkCacheExt._id !== curCache._id) {
-                            res = compareDataSources(checkCacheExt, curCache);
+            }
+        },
+        autoClusterSwapSpiConfiguration(cluster, caches) {
+            const swapConfigured = cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind;
 
-                            return !res.checked;
-                        }
+            if (!swapConfigured && _.find(caches, (cache) => cache.swapEnabled))
+                return {swapSpaceSpi: {kind: 'FileSwapSpaceSpi'}};
 
-                        return false;
-                    }
+            return null;
+        },
+        randomString(len) {
+            const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+            const possibleLen = possible.length;
 
-                    return _.find(caches, function(checkCache, checkIx) {
-                        if (checkIx < curIx) {
-                            res = compareDataSources(checkCache, curCache);
+            let res = '';
 
-                            return !res.checked;
-                        }
+            for (let i = 0; i < len; i++)
+                res += possible.charAt(Math.floor(Math.random() * possibleLen));
 
-                        return false;
-                    });
-                });
+            return res;
+        },
+        checkFieldValidators(ui) {
+            const form = ui.inputForm;
+            const errors = form.$error;
+            const errKeys = Object.keys(errors);
 
-                return res;
-            },
-            checkCacheSQLSchemas(caches, checkCacheExt) {
-                let res = DS_CHECK_SUCCESS;
+            if (errKeys && errKeys.length > 0) {
+                const firstErrorKey = errKeys[0];
 
-                _.find(caches, (curCache, curIx) => {
-                    if (isDefined(checkCacheExt)) {
-                        if (checkCacheExt._id !== curCache._id) {
-                            res = compareSQLSchemaNames(checkCacheExt, curCache);
+                const firstError = errors[firstErrorKey][0];
+                const actualError = firstError.$error[firstErrorKey][0];
 
-                            return !res.checked;
-                        }
+                const errNameFull = actualError.$name;
+                const errNameShort = errNameFull.endsWith('TextInput') ? errNameFull.substring(0, errNameFull.length - 9) : errNameFull;
 
-                        return false;
+                const extractErrorMessage = function (errName) {
+                    try {
+                        return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
                     }
-
-                    return _.find(caches, function(checkCache, checkIx) {
-                        if (checkIx < curIx) {
-                            res = compareSQLSchemaNames(checkCache, curCache);
-
-                            return !res.checked;
-                        }
-
-                        return false;
-                    });
-                });
-
-                return res;
-            },
-            autoCacheStoreConfiguration(cache, domains) {
-                const cacheStoreFactory = isDefined(cache.cacheStoreFactory) &&
-                    isDefined(cache.cacheStoreFactory.kind);
-
-                if (!cacheStoreFactory && _.findIndex(domains, domainForStoreConfigured) >= 0) {
-                    const dflt = !cache.readThrough && !cache.writeThrough;
-
-                    return {
-                        cacheStoreFactory: {
-                            kind: 'CacheJdbcPojoStoreFactory',
-                            CacheJdbcPojoStoreFactory: {
-                                dataSourceBean: toJavaName('ds', cache.name),
-                                dialect: 'Generic'
-                            },
-                            CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
-                        },
-                        readThrough: dflt || cache.readThrough,
-                        writeThrough: dflt || cache.writeThrough
-                    };
-                }
-            },
-            autoClusterSwapSpiConfiguration(cluster, caches) {
-                const swapConfigured = cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind;
-
-                if (!swapConfigured && _.find(caches, (cache) => cache.swapEnabled))
-                    return {swapSpaceSpi: {kind: 'FileSwapSpaceSpi'}};
-
-                return null;
-            },
-            randomString(len) {
-                const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-                const possibleLen = possible.length;
-
-                let res = '';
-
-                for (let i = 0; i < len; i++)
-                    res += possible.charAt(Math.floor(Math.random() * possibleLen));
-
-                return res;
-            },
-            checkFieldValidators(ui) {
-                const form = ui.inputForm;
-                const errors = form.$error;
-                const errKeys = Object.keys(errors);
-
-                if (errKeys && errKeys.length > 0) {
-                    const firstErrorKey = errKeys[0];
-
-                    const firstError = errors[firstErrorKey][0];
-                    const actualError = firstError.$error[firstErrorKey][0];
-
-                    const errNameFull = actualError.$name;
-                    const errNameShort = errNameFull.endsWith('TextInput') ? errNameFull.substring(0, errNameFull.length - 9) : errNameFull;
-
-                    const extractErrorMessage = function(errName) {
+                    catch (ignored) {
                         try {
-                            return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
+                            return form[firstError.$name].$errorMessages[errName][firstErrorKey];
                         }
-                        catch (ignored) {
-                            try {
-                                return form[firstError.$name].$errorMessages[errName][firstErrorKey];
-                            }
-                            catch (ignited) {
-                                return false;
-                            }
+                        catch (ignited) {
+                            return false;
                         }
-                    };
+                    }
+                };
 
-                    const msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!';
+                const msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!';
 
-                    return showPopoverMessage(ui, firstError.$name, errNameFull, msg);
-                }
-
-                return true;
+                return ErrorPopover.show(errNameFull, msg, ui, firstError.$name);
             }
-        };
-    }
-]];
+
+            return true;
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/27176d59/modules/web-console/frontend/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/caches-controller.js b/modules/web-console/frontend/controllers/caches-controller.js
index 90c82b4..3a8a849 100644
--- a/modules/web-console/frontend/controllers/caches-controller.js
+++ b/modules/web-console/frontend/controllers/caches-controller.js
@@ -17,8 +17,8 @@
 
 // Controller for Caches screen.
 export default ['cachesController', [
-    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteConfigurationResource',
-    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, Resource) {
+    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, Resource, ErrorPopover, FormUtils) {
         UnsavedChangesGuard.install($scope);
 
         const emptyCache = {empty: true};
@@ -34,17 +34,14 @@ export default ['cachesController', [
         // We need to initialize backupItem with empty object in order to properly used from angular directives.
         $scope.backupItem = emptyCache;
 
-        $scope.ui = LegacyUtils.formUI();
+        $scope.ui = FormUtils.formUI();
         $scope.ui.activePanels = [0];
         $scope.ui.topPanels = [0, 1, 2, 3];
 
-        $scope.hidePopover = LegacyUtils.hidePopover;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
         $scope.offHeapMode = 'DISABLED';
 
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
         $scope.contentVisible = function() {
             const item = $scope.backupItem;
 
@@ -54,7 +51,7 @@ export default ['cachesController', [
         $scope.toggleExpanded = function() {
             $scope.ui.expanded = !$scope.ui.expanded;
 
-            LegacyUtils.hidePopover();
+            ErrorPopover.hide();
         };
 
         $scope.caches = [];
@@ -162,6 +159,10 @@ export default ['cachesController', [
                 }, true);
 
                 $scope.$watch('backupItem.offHeapMode', setOffHeapMaxMemory);
+
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
             })
             .catch(Messages.showError)
             .then(() => {
@@ -206,7 +207,7 @@ export default ['cachesController', [
                     $state.go('base.configuration.caches');
             }
 
-            LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
         };
 
         $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
@@ -227,7 +228,7 @@ export default ['cachesController', [
 
         // Add new cache.
         $scope.createItem = function(linkId) {
-            $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'cacheName'));
+            $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'cacheName'));
 
             $scope.selectItem(null, prepareNewItem(linkId));
         };
@@ -260,18 +261,20 @@ export default ['cachesController', [
 
             if (!checkRes.checked) {
                 if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
-                    return showPopoverMessage($scope.ui, 'store', checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
+                    return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
                         'Found cluster "' + failCluster.label + '" with the same data source bean name "' +
                         checkRes.secondObj.discovery.Jdbc.dataSourceBean + '" and different database: "' +
                         LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
-                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in"' + checkRes.secondObj.label + '" cluster', 10000);
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in"' + checkRes.secondObj.label + '" cluster',
+                        $scope.ui, 'store', 10000);
                 }
 
-                return showPopoverMessage($scope.ui, 'store', checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
+                return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
                     'Found cache "' + checkRes.secondObj.name + '" in cluster "' + failCluster.label + '" ' +
                     'with the same data source bean name "' + checkRes.firstObj.cacheStoreFactory[checkRes.firstObj.cacheStoreFactory.kind].dataSourceBean +
                     '" and different database: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
-                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache', 10000);
+                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache',
+                    $scope.ui, 'store', 10000);
             }
 
             return true;
@@ -291,9 +294,10 @@ export default ['cachesController', [
             });
 
             if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'query', 'sqlSchema',
+                return ErrorPopover.show('sqlSchema',
                     'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
-                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"', 10000);
+                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"',
+                    $scope.ui, 'query', 10000);
             }
 
             return true;
@@ -321,35 +325,35 @@ export default ['cachesController', [
             }
 
             if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!');
+                return ErrorPopover.show('cacheStoreFactory', (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!', $scope.ui, 'store');
 
             if (item.writeBehindEnabled && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', 'Write behind enabled but store is not configured!');
+                return ErrorPopover.show('cacheStoreFactory', 'Write behind enabled but store is not configured!', $scope.ui, 'store');
 
             if (cacheStoreFactorySelected && !item.readThrough && !item.writeThrough)
-                return showPopoverMessage($scope.ui, 'store', 'readThroughTooltip', 'Store is configured but read/write through are not enabled!');
+                return ErrorPopover.show('readThroughTooltip', 'Store is configured but read/write through are not enabled!', $scope.ui, 'store');
 
             return true;
         }
 
         // Check cache logical consistency.
         function validate(item) {
-            LegacyUtils.hidePopover();
+            ErrorPopover.hide();
 
             if (LegacyUtils.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Cache name should not be empty!');
+                return ErrorPopover.show('cacheName', 'Cache name should not be empty!', $scope.ui, 'general');
 
             if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !LegacyUtils.isDefined(item.evictionPolicy.kind))
-                return showPopoverMessage($scope.ui, 'memory', 'evictionPolicyKind', 'Eviction policy should not be configured!');
+                return ErrorPopover.show('evictionPolicyKind', 'Eviction policy should not be configured!', $scope.ui, 'memory');
 
             if (!LegacyUtils.checkFieldValidators($scope.ui))
                 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!');
+                return ErrorPopover.show('memoryMode', 'Query indexing could not be enabled while values are stored off-heap!', $scope.ui, 'memory');
 
             if (item.memoryMode === 'OFFHEAP_TIERED' && item.offHeapMaxMemory === -1)
-                return showPopoverMessage($scope.ui, 'memory', 'offHeapMode', 'Invalid value!');
+                return ErrorPopover.show('offHeapMode', 'Invalid value!', $scope.ui, 'memory');
 
             if (!checkSQLSchemas())
                 return false;
@@ -358,10 +362,10 @@ export default ['cachesController', [
                 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!');
+                return ErrorPopover.show('writeBehindFlushSize', 'Both "Flush frequency" and "Flush size" are not allowed as 0!', $scope.ui, 'store');
 
             if (item.nodeFilter && item.nodeFilter.kind === 'OnNodes' && _.isEmpty(item.nodeFilter.OnNodes.nodeIds))
-                return showPopoverMessage($scope.ui, 'nodeFilter', 'nodeFilter-title', 'At least one node ID should be specified!');
+                return ErrorPopover.show('nodeFilter-title', 'At least one node ID should be specified!', $scope.ui, 'nodeFilter');
 
             return true;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/27176d59/modules/web-console/frontend/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/clusters-controller.js b/modules/web-console/frontend/controllers/clusters-controller.js
index 3a6d93c..7389578 100644
--- a/modules/web-console/frontend/controllers/clusters-controller.js
+++ b/modules/web-console/frontend/controllers/clusters-controller.js
@@ -17,8 +17,8 @@
 
 // Controller for Clusters screen.
 export default ['clustersController', [
-    '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable', 'igniteConfigurationResource',
-    function($root, $scope, $http, $state, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, igniteEventGroups, DemoInfo, LegacyTable, Resource) {
+    '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($root, $scope, $http, $state, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, igniteEventGroups, DemoInfo, LegacyTable, Resource, ErrorPopover, FormUtils) {
         UnsavedChangesGuard.install($scope);
 
         const emptyCluster = {empty: true};
@@ -43,8 +43,6 @@ export default ['clustersController', [
             'collision.JobStealing.stealingAttributes': {id: 'CAttribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'collision'}
         };
 
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
         $scope.tablePairValid = function(item, field, index) {
             const pairField = pairFields[field.model];
 
@@ -60,7 +58,7 @@ export default ['clustersController', [
 
                     // Found duplicate by key.
                     if (idx >= 0 && idx !== index)
-                        return showPopoverMessage($scope.ui, pairField.group, LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!');
+                        return ErrorPopover.show(LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!', $scope.ui, pairField.group);
                 }
             }
 
@@ -142,13 +140,12 @@ export default ['clustersController', [
         // We need to initialize backupItem with empty object in order to properly used from angular directives.
         $scope.backupItem = emptyCluster;
 
-        $scope.ui = LegacyUtils.formUI();
+        $scope.ui = FormUtils.formUI();
         $scope.ui.activePanels = [0];
         $scope.ui.topPanels = [0];
 
-        $scope.hidePopover = LegacyUtils.hidePopover;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
 
         $scope.contentVisible = function() {
             const item = $scope.backupItem;
@@ -159,7 +156,7 @@ export default ['clustersController', [
         $scope.toggleExpanded = function() {
             $scope.ui.expanded = !$scope.ui.expanded;
 
-            LegacyUtils.hidePopover();
+            ErrorPopover.hide();
         };
 
         $scope.discoveries = [
@@ -249,6 +246,10 @@ export default ['clustersController', [
                         form.$setDirty();
                 }, true);
 
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
+
                 if ($root.IgniteDemoMode && sessionStorage.showDemoInfo !== 'true') {
                     sessionStorage.showDemoInfo = 'true';
 
@@ -294,7 +295,7 @@ export default ['clustersController', [
                     $state.go('base.configuration.clusters');
             }
 
-            LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
         };
 
         $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
@@ -321,7 +322,7 @@ export default ['clustersController', [
 
         // Add new cluster.
         $scope.createItem = function(linkId) {
-            $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'clusterName'));
+            $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'clusterName'));
 
             $scope.selectItem(null, prepareNewItem(linkId));
         };
@@ -342,18 +343,20 @@ export default ['clustersController', [
 
             if (!checkRes.checked) {
                 if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
-                    return showPopoverMessage($scope.ui, 'general', 'dialect',
+                    return ErrorPopover.show('dialect',
                         'Found cache "' + checkRes.firstObj.name + '" with the same data source bean name "' +
                         item.discovery.Jdbc.dataSourceBean + '" and different database: "' +
                         LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in current cluster and "' +
-                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstObj.name + '" cache', 10000);
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstObj.name + '" cache',
+                        $scope.ui, 'general', 10000);
                 }
 
-                return showPopoverMessage($scope.ui, 'general', 'caches',
+                return ErrorPopover.show('caches',
                     'Found caches "' + checkRes.firstObj.name + '" and "' + checkRes.secondObj.name + '" ' +
                     'with the same data source bean name "' + checkRes.firstObj.cacheStoreFactory[checkRes.firstObj.cacheStoreFactory.kind].dataSourceBean +
                     '" and different databases: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstObj.name + '" and "' +
-                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache', 10000);
+                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache',
+                    $scope.ui, 'general', 10000);
             }
 
             return true;
@@ -365,9 +368,10 @@ export default ['clustersController', [
             const checkRes = LegacyUtils.checkCacheSQLSchemas(caches);
 
             if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'general', 'caches',
+                return ErrorPopover.show('caches',
                     'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' +
-                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"', 10000);
+                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"',
+                    $scope.ui, 'general', 10000);
             }
 
             return true;
@@ -382,10 +386,10 @@ export default ['clustersController', [
                         const type = b.typeConfigurations[typeIx];
 
                         if (LegacyUtils.isEmptyString(type.typeName))
-                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type name should be specified!');
+                            return ErrorPopover.show('typeName' + typeIx, 'Type name should be specified!', $scope.ui, 'binary');
 
                         if (_.find(b.typeConfigurations, (t, ix) => ix < typeIx && t.typeName === type.typeName))
-                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type with such name is already specified!');
+                            return ErrorPopover.show('typeName' + typeIx, 'Type with such name is already specified!', $scope.ui, 'binary');
                     }
                 }
             }
@@ -403,10 +407,10 @@ export default ['clustersController', [
                 const type = cfgs[typeIx];
 
                 if (LegacyUtils.isEmptyString(type.typeName))
-                    return showPopoverMessage($scope.ui, 'cacheKeyCfg', 'cacheKeyTypeName' + typeIx, 'Cache type configuration name should be specified!');
+                    return ErrorPopover.show('cacheKeyTypeName' + typeIx, 'Cache type configuration name should be specified!', $scope.ui, 'cacheKeyCfg');
 
                 if (_.find(cfgs, (t, ix) => ix < typeIx && t.typeName === type.typeName))
-                    return showPopoverMessage($scope.ui, 'cacheKeyCfg', 'cacheKeyTypeName' + typeIx, 'Cache type configuration with such name is already specified!');
+                    return ErrorPopover.show('cacheKeyTypeName' + typeIx, 'Cache type configuration with such name is already specified!', $scope.ui, 'cacheKeyCfg');
             }
 
             return true;
@@ -418,14 +422,14 @@ export default ['clustersController', [
             if (LegacyUtils.isDefined(c)) {
                 if (LegacyUtils.isDefined(c.unacknowledgedMessagesBufferSize)) {
                     if (LegacyUtils.isDefined(c.messageQueueLimit) && c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit)
-                        return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit!');
+                        return ErrorPopover.show('unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit!', $scope.ui, 'communication');
 
                     if (LegacyUtils.isDefined(c.ackSendThreshold) && c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold)
-                        return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold!');
+                        return ErrorPopover.show('unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold!', $scope.ui, 'communication');
                 }
 
                 if (c.sharedMemoryPort === 0)
-                    return showPopoverMessage($scope.ui, 'communication', 'sharedMemoryPort', 'Shared memory port should be more than "0" or equals to "-1"!');
+                    return ErrorPopover.show('sharedMemoryPort', 'Shared memory port should be more than "0" or equals to "-1"!', $scope.ui, 'communication');
             }
 
             return true;
@@ -436,10 +440,10 @@ export default ['clustersController', [
 
             if (d) {
                 if ((_.isNil(d.maxAckTimeout) ? 600000 : d.maxAckTimeout) < (d.ackTimeout || 5000))
-                    return showPopoverMessage($scope.ui, 'discovery', 'ackTimeout', 'Acknowledgement timeout should be less than max acknowledgement timeout!');
+                    return ErrorPopover.show('ackTimeout', 'Acknowledgement timeout should be less than max acknowledgement timeout!', $scope.ui, 'discovery');
 
                 if (d.kind === 'Vm' && d.Vm && d.Vm.addresses.length === 0)
-                    return showPopoverMessage($scope.ui, 'general', 'addresses', 'Addresses are not specified!');
+                    return ErrorPopover.show('addresses', 'Addresses are not specified!', $scope.ui, 'general');
             }
 
             return true;
@@ -454,12 +458,12 @@ export default ['clustersController', [
                 const sparsity = swap.maximumSparsity;
 
                 if (LegacyUtils.isDefined(sparsity) && (sparsity < 0 || sparsity >= 1))
-                    return showPopoverMessage($scope.ui, 'swap', 'maximumSparsity', 'Maximum sparsity should be more or equal 0 and less than 1!');
+                    return ErrorPopover.show('maximumSparsity', 'Maximum sparsity should be more or equal 0 and less than 1!', $scope.ui, 'swap');
 
                 const readStripesNumber = swap.readStripesNumber;
 
                 if (readStripesNumber && !(readStripesNumber === -1 || (readStripesNumber & (readStripesNumber - 1)) === 0))
-                    return showPopoverMessage($scope.ui, 'swap', 'readStripesNumber', 'Read stripe size must be positive and power of two!');
+                    return ErrorPopover.show('readStripesNumber', 'Read stripe size must be positive and power of two!', $scope.ui, 'swap');
             }
 
             return true;
@@ -470,15 +474,15 @@ export default ['clustersController', [
 
             if (LegacyUtils.isDefined(r)) {
                 if (r.sslEnabled && LegacyUtils.isEmptyString(r.sslFactory))
-                    return showPopoverMessage($scope.ui, 'connector', 'connectorSslFactory', 'SSL factory should not be empty!');
+                    return ErrorPopover.show('connectorSslFactory', 'SSL factory should not be empty!', $scope.ui, 'connector');
             }
 
             if (item.sslEnabled) {
                 if (!LegacyUtils.isDefined(item.sslContextFactory) || LegacyUtils.isEmptyString(item.sslContextFactory.keyStoreFilePath))
-                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'keyStoreFilePath', 'Key store file should not be empty!');
+                    return ErrorPopover.show('keyStoreFilePath', 'Key store file should not be empty!', $scope.ui, 'sslConfiguration');
 
                 if (LegacyUtils.isEmptyString(item.sslContextFactory.trustStoreFilePath) && _.isEmpty(item.sslContextFactory.trustManagers))
-                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'sslConfiguration-title', 'Trust storage file or managers should be configured!');
+                    return ErrorPopover.show('sslConfiguration-title', 'Trust storage file or managers should be configured!', $scope.ui, 'sslConfiguration');
             }
 
             return true;
@@ -486,17 +490,17 @@ export default ['clustersController', [
 
         function checkPoolSizes(item) {
             if (item.rebalanceThreadPoolSize && item.systemThreadPoolSize && item.systemThreadPoolSize <= item.rebalanceThreadPoolSize)
-                return showPopoverMessage($scope.ui, 'pools', 'rebalanceThreadPoolSize', 'Rebalance thread pool size exceed or equals System thread pool size!');
+                return ErrorPopover.show('rebalanceThreadPoolSize', 'Rebalance thread pool size exceed or equals System thread pool size!', $scope.ui, 'pools');
 
             return true;
         }
 
         // Check cluster logical consistency.
         function validate(item) {
-            LegacyUtils.hidePopover();
+            ErrorPopover.hide();
 
             if (LegacyUtils.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'clusterName', 'Cluster name should not be empty!');
+                return ErrorPopover.show('clusterName', 'Cluster name should not be empty!', $scope.ui, 'general');
 
             if (!LegacyUtils.checkFieldValidators($scope.ui))
                 return false;


Mime
View raw message