http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/app/services/LegacyTable.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/app/services/LegacyTable.service.js b/modules/web-console/src/main/js/app/services/LegacyTable.service.js new file mode 100644 index 0000000..8f3b791 --- /dev/null +++ b/modules/web-console/src/main/js/app/services/LegacyTable.service.js @@ -0,0 +1,205 @@ +/* + * 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. + */ + +// TODO: Refactor this service for legacy tables with more than one input field. +export default ['IgniteLegacyTable', ['IgniteLegacyUtils', 'IgniteFocus', (LegacyUtils, Focus) => { + function _model(item, field) { + return LegacyUtils.getModel(item, field); + } + + const table = {name: 'none', editIndex: -1}; + + function _tableReset() { + delete table.field; + table.name = 'none'; + table.editIndex = -1; + + LegacyUtils.hidePopover(); + } + + function _tableSaveAndReset() { + const field = table.field; + + const save = LegacyUtils.isDefined(field) && LegacyUtils.isDefined(field.save); + + if (!save || !LegacyUtils.isDefined(field) || field.save(field, table.editIndex, true)) { + _tableReset(); + + return true; + } + + return false; + } + + function _tableState(field, editIndex, specName) { + table.field = field; + table.name = specName || field.model; + table.editIndex = editIndex; + } + + function _tableUI(field) { + const ui = field.ui; + + return ui ? ui : field.type; + } + + function _tableFocus(focusId, index) { + Focus.move((index < 0 ? 'new' : 'cur') + focusId + (index >= 0 ? index : '')); + } + + function _tablePairValue(filed, index) { + return index < 0 ? {key: filed.newKey, value: filed.newValue} : {key: filed.curKey, value: filed.curValue}; + } + + function _tableStartEdit(item, tbl, index, save) { + _tableState(tbl, index); + + const val = _.get(_model(item, tbl), tbl.model)[index]; + + const ui = _tableUI(tbl); + + tbl.save = save; + + if (ui === 'table-pair') { + tbl.curKey = val[tbl.keyName]; + tbl.curValue = val[tbl.valueName]; + + _tableFocus('Key' + tbl.focusId, index); + } + else if (ui === 'table-db-fields') { + tbl.curDatabaseFieldName = val.databaseFieldName; + tbl.curDatabaseFieldType = val.databaseFieldType; + tbl.curJavaFieldName = val.javaFieldName; + tbl.curJavaFieldType = val.javaFieldType; + + _tableFocus('DatabaseFieldName' + tbl.focusId, index); + } + else if (ui === 'table-indexes') { + tbl.curIndexName = val.name; + tbl.curIndexType = val.indexType; + tbl.curIndexFields = val.fields; + + _tableFocus(tbl.focusId, index); + } + } + + function _tableNewItem(tbl) { + _tableState(tbl, -1); + + const ui = _tableUI(tbl); + + if (ui === 'table-pair') { + tbl.newKey = null; + tbl.newValue = null; + + _tableFocus('Key' + tbl.focusId, -1); + } + else if (ui === 'table-db-fields') { + tbl.newDatabaseFieldName = null; + tbl.newDatabaseFieldType = null; + tbl.newJavaFieldName = null; + tbl.newJavaFieldType = null; + + _tableFocus('DatabaseFieldName' + tbl.focusId, -1); + } + else if (ui === 'table-indexes') { + tbl.newIndexName = null; + tbl.newIndexType = 'SORTED'; + tbl.newIndexFields = null; + + _tableFocus(tbl.focusId, -1); + } + } + + return { + tableState: _tableState, + tableReset: _tableReset, + tableSaveAndReset: _tableSaveAndReset, + tableNewItem: _tableNewItem, + tableNewItemActive(tbl) { + return table.name === tbl.model && table.editIndex < 0; + }, + tableEditing(tbl, index) { + return table.name === tbl.model && table.editIndex === index; + }, + tableEditedRowIndex() { + return table.editIndex; + }, + tableField() { + return table.field; + }, + tableStartEdit: _tableStartEdit, + tableRemove(item, field, index) { + _tableReset(); + + _.get(_model(item, field), field.model).splice(index, 1); + }, + tablePairValue: _tablePairValue, + tablePairSave(pairValid, item, field, index, stopEdit) { + const valid = pairValid(item, field, index); + + if (valid) { + const pairValue = _tablePairValue(field, index); + + let pairModel = {}; + + const container = _.get(item, field.model); + + if (index < 0) { + pairModel[field.keyName] = pairValue.key; + pairModel[field.valueName] = pairValue.value; + + if (container) + container.push(pairModel); + else + _.set(item, field.model, [pairModel]); + + if (!stopEdit) + _tableNewItem(field); + } + else { + pairModel = container[index]; + + pairModel[field.keyName] = pairValue.key; + pairModel[field.valueName] = pairValue.value; + + if (!stopEdit) { + if (index < container.length - 1) + _tableStartEdit(item, field, index + 1); + else + _tableNewItem(field); + } + } + } + + return valid; + }, + tablePairSaveVisible(field, index) { + const pairValue = _tablePairValue(field, index); + + return !LegacyUtils.isEmptyString(pairValue.key) && !LegacyUtils.isEmptyString(pairValue.value); + }, + tableFocusInvalidField(index, id) { + _tableFocus(id, index); + + return false; + }, + tableFieldId(index, id) { + return (index < 0 ? 'new' : 'cur') + id + (index >= 0 ? index : ''); + } + }; +}]];
http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/app/services/LegacyUtils.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/app/services/LegacyUtils.service.js b/modules/web-console/src/main/js/app/services/LegacyUtils.service.js new file mode 100644 index 0000000..253ae74 --- /dev/null +++ b/modules/web-console/src/main/js/app/services/LegacyUtils.service.js @@ -0,0 +1,941 @@ +/* + * 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. + */ + +// 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), 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; + }); + + if (idx >= 0) { + const activePanels = ui.activePanels; + + if (!_.includes(ui.topPanels, idx)) { + ui.expanded = true; + + const customExpanded = ui[pnl]; + + if (customExpanded) + ui[customExpanded] = true; + } + + if (!activePanels || activePanels.length < 1) + ui.activePanels = [idx]; + else if (!_.includes(activePanels, idx)) { + const newActivePanels = angular.copy(activePanels); + + newActivePanels.push(idx); + + ui.activePanels = newActivePanels; + } + } + + if (isDefined(focusId)) + Focus.move(focusId); + } + } + + function showPopoverMessage(ui, panelId, id, message, showTime) { + if (popover) + popover.hide(); + + if (ui) { + ensureActivePanel(ui, panelId); + + $timeout(() => _showPopoverMessage(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500); + } + else + _showPopoverMessage(id, message, showTime); + + return false; + } + + 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 true; + } + + 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]); + + context.font = style.fontSize + ' ' + style.fontFamily; + } + + return context.measureText(text).width; + } + + /** + * 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; + + let remains = Math.min(nameLength - totalLength + classNameLen, classNameLen); + + if (remains < 3) + remains = Math.min(3, classNameLen); + + packages[packageCnt] = className.substring(0, remains) + '...'; + } + + let result = packages[0]; + + for (let i = 1; i < packages.length; i++) + result += '.' + packages[i]; + + names[nameIx] = result; + } + } + + 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]); + + if (widthByName[nameIx] > curNameWidth) { + fitted[nameIx] = true; + + remains += widthByName[nameIx] - curNameWidth; + + divideTo -= 1; + + widthByName[nameIx] = curNameWidth; + } + } + } + + const remainsByName = remains / divideTo; + + for (let nameIx = 0; nameIx < len; nameIx++) { + if (!fitted[nameIx]) + widthByName[nameIx] += remainsByName; + } + } + 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); + + if (totalWidth > widthByName[nameIx]) { + const packages = s.split('.'); + + const packageCnt = packages.length - 1; + + for (let i = 0; i < packageCnt && totalWidth > widthByName[nameIx]; i++) { + if (packages[i].length > 1) { + totalWidth -= measureText(packages[i].substring(1, packages[i].length)); + + packages[i] = packages[i][0]; + } + } + + let shortPackage = ''; + + for (let i = 0; i < packageCnt; i++) + shortPackage += packages[i] + '.'; + + const className = packages[packageCnt]; + + const classLen = className.length; + + let minLen = Math.min(classLen, 3); + + totalWidth = measureText(shortPackage + className); + + // Compact class name if shorten package path is very long. + if (totalWidth > widthByName[nameIx]) { + let maxLen = classLen; + let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0; + + while (middleLen !== minLen && middleLen !== maxLen) { + const middleLenPx = measureText(shortPackage + className.substr(0, middleLen) + '...'); + + if (middleLenPx > widthByName[nameIx]) + maxLen = middleLen; + else + minLen = middleLen; + + middleLen = (minLen + (maxLen - minLen) / 2 ) | 0; + } + + names[nameIx] = shortPackage + className.substring(0, middleLen) + '...'; + } + else + names[nameIx] = shortPackage + className; + } + } + } + + 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 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; + + if (width > 0) { + const children = $(cont).children(':not("a")'); + + _.forEach(children, function(child) { + if ('offsetWidth' in child) + width -= $(child).outerWidth(true); + }); + } + + 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; + } + + function extractDataSource(cache) { + if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) { + const storeFactory = cache.cacheStoreFactory[cache.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 }; + + function compareDataSources(firstCache, secondCache) { + const firstDs = extractDataSource(firstCache); + const secondDs = extractDataSource(secondCache); + + if (firstDs && secondDs) { + const firstDB = firstDs.dialect; + const secondDB = secondDs.dialect; + + if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB) + return {checked: false, firstCache, firstDB, secondCache, 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'}; + }); + }, + 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 label; + }, + widthIsSufficient(id, index, text) { + try { + const available = availableWidth(index, id); + + const required = measureText(text); + + 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(); + } + else + selectFunc(); + }, + saveBtnTipText(dirty, objectName) { + if (dirty) + return 'Save ' + objectName; + + return 'Nothing to save'; + }, + download(type, name, data) { + const file = document.createElement('a'); + + file.setAttribute('href', 'data:' + type + ';charset=utf-8,' + data); + file.setAttribute('download', name); + file.setAttribute('target', '_self'); + + file.style.display = 'none'; + + document.body.appendChild(file); + + file.click(); + + document.body.removeChild(file); + }, + formUI() { + return { + ready: false, + expanded: false, + loadedPanels: [], + loadPanel(pnl) { + if (!_.includes(this.loadedPanels, pnl)) + this.loadedPanels.push(pnl); + }, + isPanelLoaded(pnl) { + return _.includes(this.loadedPanels, pnl); + } + }; + }, + 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; + }, + checkCachesDataSources(caches, checkCacheExt) { + let res = DS_CHECK_SUCCESS; + + _.find(caches, function(curCache, curIx) { + if (isDefined(checkCacheExt)) { + if (checkCacheExt._id !== curCache._id) { + res = compareDataSources(checkCacheExt, curCache); + + return !res.checked; + } + + return false; + } + + return _.find(caches, function(checkCache, checkIx) { + if (checkIx < curIx) { + res = compareDataSources(checkCache, curCache); + + return !res.checked; + } + + return false; + }); + }); + + return res; + }, + checkCacheSQLSchemas(caches, checkCacheExt) { + let res = DS_CHECK_SUCCESS; + + _.find(caches, (curCache, curIx) => { + if (isDefined(checkCacheExt)) { + if (checkCacheExt._id !== curCache._id) { + res = compareSQLSchemaNames(checkCacheExt, curCache); + + return !res.checked; + } + + return false; + } + + 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' + } + }, + 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) { + try { + return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey]; + } + catch (ignored) { + try { + return form[firstError.$name].$errorMessages[errName][firstErrorKey]; + } + catch (ignited) { + return false; + } + } + }; + + const msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!'; + + return showPopoverMessage(ui, firstError.$name, errNameFull, msg); + } + + return true; + } + }; + } +]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/app/services/Messages.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/app/services/Messages.service.js b/modules/web-console/src/main/js/app/services/Messages.service.js new file mode 100644 index 0000000..f854160 --- /dev/null +++ b/modules/web-console/src/main/js/app/services/Messages.service.js @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Service to show various information and error messages. +export default ['IgniteMessages', ['$alert', ($alert) => { + // Common instance of alert modal. + let msgModal; + + function _showMessage(msg, type, duration, icon) { + if (msgModal) + msgModal.hide(); + + const title = msg ? msg.toString() : 'Internal error.'; + + msgModal = $alert({type, title, duration}); + + msgModal.$scope.icon = icon; + } + + return { + errorMessage(prefix, err) { + return prefix + (err ? err.toString() : 'Internal error.'); + }, + showError(msg) { + _showMessage(msg, 'danger', 10, 'fa-exclamation-triangle'); + + return false; + }, + showInfo(msg) { + _showMessage(msg, 'success', 3, 'fa-check-circle-o'); + }, + hideAlert() { + if (msgModal) + msgModal.hide(); + } + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js b/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js new file mode 100644 index 0000000..91244b0 --- /dev/null +++ b/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const MSG = 'You have unsaved changes.\n\nAre you sure you want to discard them?'; + +// Service that show confirmation about unsaved changes on user change location. +export default ['IgniteUnsavedChangesGuard', ['$rootScope', ($root) => { + return { + install(scope, customDirtyCheck = () => scope.ui.inputForm.$dirty) { + scope.$on('$destroy', () => window.onbeforeunload = null); + + const unbind = $root.$on('$stateChangeStart', (event) => { + if (_.get(scope, 'ui.inputForm', false) && customDirtyCheck()) { + if (!confirm(MSG)) // eslint-disable-line no-alert + event.preventDefault(); + else + unbind(); + } + }); + + window.onbeforeunload = () => _.get(scope, 'ui.inputForm.$dirty', false) ? MSG : null; + } + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/app/services/confirm.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/app/services/confirm.service.js b/modules/web-console/src/main/js/app/services/confirm.service.js index bb07cfd..c4e25a8 100644 --- a/modules/web-console/src/main/js/app/services/confirm.service.js +++ b/modules/web-console/src/main/js/app/services/confirm.service.js @@ -16,7 +16,7 @@ */ // Confirm popup service. -export default ['$confirm', ['$modal', '$rootScope', '$q', '$animate', ($modal, $root, $q, $animate) => { +export default ['IgniteConfirm', ['$rootScope', '$q', '$modal', '$animate', ($root, $q, $modal, $animate) => { const scope = $root.$new(); const modal = $modal({templateUrl: '/templates/confirm.html', scope, placement: 'center', show: false}); http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/controllers/admin-controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/controllers/admin-controller.js b/modules/web-console/src/main/js/controllers/admin-controller.js index f46bab0..9e5aea7 100644 --- a/modules/web-console/src/main/js/controllers/admin-controller.js +++ b/modules/web-console/src/main/js/controllers/admin-controller.js @@ -16,11 +16,9 @@ */ // Controller for Admin screen. -import consoleModule from 'controllers/common-module'; - -consoleModule.controller('adminController', [ - '$rootScope', '$scope', '$http', '$q', '$common', '$confirm', '$state', 'User', 'IgniteCountries', - ($rootScope, $scope, $http, $q, $common, $confirm, $state, User, Countries) => { +export default ['adminController', [ + '$rootScope', '$scope', '$http', '$q', '$state', 'IgniteMessages', 'IgniteConfirm', 'User', 'IgniteCountries', + ($rootScope, $scope, $http, $q, $state, Messages, Confirm, User, Countries) => { $scope.users = null; const _reloadUsers = () => { @@ -35,7 +33,7 @@ consoleModule.controller('adminController', [ (user.company || '') + ' ' + (user.countryCode || ''); }); }) - .catch((err) => $common.showError(err)); + .catch(Messages.showError); }; _reloadUsers(); @@ -48,11 +46,11 @@ consoleModule.controller('adminController', [ $state.go('base.configuration.clusters'); }) - .catch((errMsg) => $common.showError($common.errorMessage(errMsg))); + .catch(Messages.showError); }; $scope.removeUser = (user) => { - $confirm.confirm('Are you sure you want to remove user: "' + user.userName + '"?') + Confirm.confirm('Are you sure you want to remove user: "' + user.userName + '"?') .then(() => { $http.post('/api/v1/admin/remove', {userId: user._id}) .success(() => { @@ -61,13 +59,13 @@ consoleModule.controller('adminController', [ if (i >= 0) $scope.users.splice(i, 1); - $common.showInfo('User has been removed: "' + user.userName + '"'); + Messages.showInfo('User has been removed: "' + user.userName + '"'); }) - .error((errMsg, status) => { + .error((err, status) => { if (status === 503) - $common.showInfo(errMsg); + Messages.showInfo(err); else - $common.showError('Failed to remove user: "' + $common.errorMessage(errMsg) + '"'); + Messages.showError(Messages.errorMessage('Failed to remove user: ', err)); }); }); }; @@ -82,11 +80,12 @@ consoleModule.controller('adminController', [ .success(() => { user.admin = !user.admin; - $common.showInfo('Admin right was successfully toggled for user: "' + user.userName + '"'); - }).error((err) => { - $common.showError('Failed to toggle admin right for user: "' + $common.errorMessage(err) + '"'); + Messages.showInfo('Admin right was successfully toggled for user: "' + user.userName + '"'); + }) + .error((err) => { + Messages.showError(Messages.errorMessage('Failed to toggle admin right for user: ', err)); }) .finally(() => user.adminChanging = false); }; - }] -); + } +]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/controllers/caches-controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/controllers/caches-controller.js b/modules/web-console/src/main/js/controllers/caches-controller.js index ac4d951..6677c38 100644 --- a/modules/web-console/src/main/js/controllers/caches-controller.js +++ b/modules/web-console/src/main/js/controllers/caches-controller.js @@ -16,12 +16,10 @@ */ // Controller for Caches screen. -import consoleModule from 'controllers/common-module'; - -consoleModule.controller('cachesController', [ - '$scope', '$http', '$state', '$filter', '$timeout', '$common', '$confirm', '$clone', '$loading', '$cleanup', '$unsavedChangesGuard', - function($scope, $http, $state, $filter, $timeout, $common, $confirm, $clone, $loading, $cleanup, $unsavedChangesGuard) { - $unsavedChangesGuard.install($scope); +export default ['cachesController', [ + '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', '$loading', '$cleanup', 'IgniteUnsavedChangesGuard', + function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, $loading, $cleanup, UnsavedChangesGuard) { + UnsavedChangesGuard.install($scope); const emptyCache = {empty: true}; @@ -36,15 +34,15 @@ consoleModule.controller('cachesController', [ // We need to initialize backupItem with empty object in order to properly used from angular directives. $scope.backupItem = emptyCache; - $scope.ui = $common.formUI(); + $scope.ui = LegacyUtils.formUI(); $scope.ui.activePanels = [0]; $scope.ui.topPanels = [0, 1, 2, 3]; - $scope.hidePopover = $common.hidePopover; - $scope.saveBtnTipText = $common.saveBtnTipText; - $scope.widthIsSufficient = $common.widthIsSufficient; + $scope.hidePopover = LegacyUtils.hidePopover; + $scope.saveBtnTipText = LegacyUtils.saveBtnTipText; + $scope.widthIsSufficient = LegacyUtils.widthIsSufficient; - const showPopoverMessage = $common.showPopoverMessage; + const showPopoverMessage = LegacyUtils.showPopoverMessage; $scope.contentVisible = function() { const item = $scope.backupItem; @@ -55,7 +53,7 @@ consoleModule.controller('cachesController', [ $scope.toggleExpanded = function() { $scope.ui.expanded = !$scope.ui.expanded; - $common.hidePopover(); + LegacyUtils.hidePopover(); }; $scope.caches = []; @@ -144,9 +142,7 @@ consoleModule.controller('cachesController', [ form.$setDirty(); }, true); }) - .catch(function(errMsg) { - $common.showError(errMsg); - }) + .catch(Messages.showError) .finally(function() { $scope.ui.ready = true; $scope.ui.inputForm.$setPristine(); @@ -178,11 +174,11 @@ consoleModule.controller('cachesController', [ __original_value = $cleanup($scope.backupItem); - if ($common.getQueryVariable('new')) + if (LegacyUtils.getQueryVariable('new')) $state.go('base.configuration.caches'); } - $common.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem); + LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem); }; $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create'; @@ -203,7 +199,7 @@ consoleModule.controller('cachesController', [ // Add new cache. $scope.createItem = function(linkId) { - $timeout(() => $common.ensureActivePanel($scope.ui, 'general', 'cacheName')); + $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'cacheName')); $scope.selectItem(null, prepareNewItem(linkId)); }; @@ -229,7 +225,7 @@ consoleModule.controller('cachesController', [ const failCluster = _.find(clusters, (cluster) => { const caches = clusterCaches(cluster); - checkRes = $common.checkCachesDataSources(caches, $scope.backupItem); + checkRes = LegacyUtils.checkCachesDataSources(caches, $scope.backupItem); return !checkRes.checked; }); @@ -238,8 +234,8 @@ consoleModule.controller('cachesController', [ return showPopoverMessage($scope.ui, 'store', checkRes.firstCache.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect', 'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' + 'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean + - '" and different database: "' + $common.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' + - $common.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000); + '" and different database: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' + + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000); } return true; @@ -253,7 +249,7 @@ consoleModule.controller('cachesController', [ const failCluster = _.find(clusters, (cluster) => { const caches = clusterCaches(cluster); - checkRes = $common.checkCacheSQLSchemas(caches, $scope.backupItem); + checkRes = LegacyUtils.checkCacheSQLSchemas(caches, $scope.backupItem); return !checkRes.checked; }); @@ -268,7 +264,7 @@ consoleModule.controller('cachesController', [ } function checkStoreFactoryBean(storeFactory, beanFieldId) { - if (!$common.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, beanFieldId, $scope.ui, 'store')) + if (!LegacyUtils.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, beanFieldId, $scope.ui, 'store')) return false; return checkDataSources(); @@ -302,21 +298,21 @@ consoleModule.controller('cachesController', [ // Check cache logical consistency. function validate(item) { - $common.hidePopover(); + LegacyUtils.hidePopover(); - if ($common.isEmptyString(item.name)) + if (LegacyUtils.isEmptyString(item.name)) return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Cache name should not be empty!'); - if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !$common.isDefined(item.evictionPolicy.kind)) + 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!'); - if (!$common.checkFieldValidators($scope.ui)) + 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!'); - if (item.memoryMode === 'OFFHEAP_TIERED' && (!$common.isDefined(item.offHeapMaxMemory) || item.offHeapMaxMemory < 0)) + if (item.memoryMode === 'OFFHEAP_TIERED' && (!LegacyUtils.isDefined(item.offHeapMaxMemory) || item.offHeapMaxMemory < 0)) return showPopoverMessage($scope.ui, 'memory', 'offHeapMaxMemory', 'Off-heap max memory should be specified!'); if (!checkSQLSchemas()) @@ -366,18 +362,16 @@ consoleModule.controller('cachesController', [ $scope.selectItem(item); - $common.showInfo('Cache "' + item.name + '" saved.'); + Messages.showInfo('Cache "' + item.name + '" saved.'); }) - .error(function(errMsg) { - $common.showError(errMsg); - }); + .error(Messages.showError); } // Save cache. $scope.saveItem = function() { const item = $scope.backupItem; - angular.extend(item, $common.autoCacheStoreConfiguration(item, cacheDomains(item))); + angular.extend(item, LegacyUtils.autoCacheStoreConfiguration(item, cacheDomains(item))); if (validate(item)) save(item); @@ -392,7 +386,7 @@ consoleModule.controller('cachesController', [ // Clone cache with new name. $scope.cloneItem = function() { if (validate($scope.backupItem)) { - $clone.confirm($scope.backupItem.name, _cacheNames()).then(function(newName) { + Clone.confirm($scope.backupItem.name, _cacheNames()).then(function(newName) { const item = angular.copy($scope.backupItem); delete item._id; @@ -410,13 +404,13 @@ consoleModule.controller('cachesController', [ $scope.removeItem = function() { const selectedItem = $scope.selectedItem; - $confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?') + Confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?') .then(function() { const _id = selectedItem._id; $http.post('/api/v1/configuration/caches/remove', {_id}) .success(function() { - $common.showInfo('Cache has been removed: ' + selectedItem.name); + Messages.showInfo('Cache has been removed: ' + selectedItem.name); const caches = $scope.caches; @@ -438,19 +432,17 @@ consoleModule.controller('cachesController', [ _.forEach($scope.domains, (domain) => _.remove(domain.meta.caches, (id) => id === _id)); } }) - .error(function(errMsg) { - $common.showError(errMsg); - }); + .error(Messages.showError); }); }; // Remove all caches from db. $scope.removeAllItems = function() { - $confirm.confirm('Are you sure you want to remove all caches?') + Confirm.confirm('Are you sure you want to remove all caches?') .then(function() { $http.post('/api/v1/configuration/caches/remove/all') .success(function() { - $common.showInfo('All caches have been removed'); + Messages.showInfo('All caches have been removed'); $scope.caches = []; @@ -460,18 +452,16 @@ consoleModule.controller('cachesController', [ $scope.backupItem = emptyCache; $scope.ui.inputForm.$setPristine(); }) - .error(function(errMsg) { - $common.showError(errMsg); - }); + .error(Messages.showError); }); }; $scope.resetAll = function() { - $confirm.confirm('Are you sure you want to undo all changes for current cache?') + Confirm.confirm('Are you sure you want to undo all changes for current cache?') .then(function() { $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem(); $scope.ui.inputForm.$setPristine(); }); }; - }] -); + } +]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/00d8c0af/modules/web-console/src/main/js/controllers/clusters-controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/src/main/js/controllers/clusters-controller.js b/modules/web-console/src/main/js/controllers/clusters-controller.js index 3277397..a50af96 100644 --- a/modules/web-console/src/main/js/controllers/clusters-controller.js +++ b/modules/web-console/src/main/js/controllers/clusters-controller.js @@ -16,12 +16,10 @@ */ // Controller for Clusters screen. -import consoleModule from 'controllers/common-module'; - -consoleModule.controller('clustersController', [ - '$rootScope', '$scope', '$http', '$state', '$timeout', '$common', '$confirm', '$clone', '$loading', '$cleanup', '$unsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', '$table', - function($root, $scope, $http, $state, $timeout, $common, $confirm, $clone, $loading, $cleanup, $unsavedChangesGuard, igniteEventGroups, DemoInfo, $table) { - $unsavedChangesGuard.install($scope); +export default ['clustersController', [ + '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', '$loading', '$cleanup', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable', + function($root, $scope, $http, $state, $timeout, LegacyUtils, Messages, Confirm, Clone, $loading, $cleanup, UnsavedChangesGuard, igniteEventGroups, DemoInfo, LegacyTable) { + UnsavedChangesGuard.install($scope); const emptyCluster = {empty: true}; @@ -45,24 +43,24 @@ consoleModule.controller('clustersController', [ 'collision.JobStealing.stealingAttributes': {id: 'CAttribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'collision'} }; - const showPopoverMessage = $common.showPopoverMessage; + const showPopoverMessage = LegacyUtils.showPopoverMessage; $scope.tablePairValid = function(item, field, index) { const pairField = pairFields[field.model]; - const pairValue = $table.tablePairValue(field, index); + const pairValue = LegacyTable.tablePairValue(field, index); if (pairField) { const model = _.get(item, field.model); - if ($common.isDefined(model)) { + if (LegacyUtils.isDefined(model)) { const idx = _.findIndex(model, (pair) => { return pair[pairField.searchCol] === pairValue[pairField.valueCol]; }); // Found duplicate by key. if (idx >= 0 && idx !== index) - return showPopoverMessage($scope.ui, pairField.group, $table.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!'); + return showPopoverMessage($scope.ui, pairField.group, LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!'); } } @@ -70,19 +68,19 @@ consoleModule.controller('clustersController', [ }; $scope.tableSave = function(field, index, stopEdit) { - if ($table.tablePairSaveVisible(field, index)) - return $table.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit); + if (LegacyTable.tablePairSaveVisible(field, index)) + return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit); return true; }; $scope.tableReset = (trySave) => { - const field = $table.tableField(); + const field = LegacyTable.tableField(); - if (trySave && $common.isDefined(field) && !$scope.tableSave(field, $table.tableEditedRowIndex(), true)) + if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true)) return false; - $table.tableReset(); + LegacyTable.tableReset(); return true; }; @@ -90,32 +88,32 @@ consoleModule.controller('clustersController', [ $scope.tableNewItem = function(field) { if ($scope.tableReset(true)) { if (field.type === 'failoverSpi') { - if ($common.isDefined($scope.backupItem.failoverSpi)) + if (LegacyUtils.isDefined($scope.backupItem.failoverSpi)) $scope.backupItem.failoverSpi.push({}); else $scope.backupItem.failoverSpi = {}; } else - $table.tableNewItem(field); + LegacyTable.tableNewItem(field); } }; - $scope.tableNewItemActive = $table.tableNewItemActive; + $scope.tableNewItemActive = LegacyTable.tableNewItemActive; $scope.tableStartEdit = function(item, field, index) { if ($scope.tableReset(true)) - $table.tableStartEdit(item, field, index, $scope.tableSave); + LegacyTable.tableStartEdit(item, field, index, $scope.tableSave); }; - $scope.tableEditing = $table.tableEditing; + $scope.tableEditing = LegacyTable.tableEditing; $scope.tableRemove = function(item, field, index) { if ($scope.tableReset(true)) - $table.tableRemove(item, field, index); + LegacyTable.tableRemove(item, field, index); }; - $scope.tablePairSave = $table.tablePairSave; - $scope.tablePairSaveVisible = $table.tablePairSaveVisible; + $scope.tablePairSave = LegacyTable.tablePairSave; + $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible; $scope.attributesTbl = { type: 'attributes', @@ -144,13 +142,13 @@ consoleModule.controller('clustersController', [ // We need to initialize backupItem with empty object in order to properly used from angular directives. $scope.backupItem = emptyCluster; - $scope.ui = $common.formUI(); + $scope.ui = LegacyUtils.formUI(); $scope.ui.activePanels = [0]; $scope.ui.topPanels = [0]; - $scope.hidePopover = $common.hidePopover; - $scope.saveBtnTipText = $common.saveBtnTipText; - $scope.widthIsSufficient = $common.widthIsSufficient; + $scope.hidePopover = LegacyUtils.hidePopover; + $scope.saveBtnTipText = LegacyUtils.saveBtnTipText; + $scope.widthIsSufficient = LegacyUtils.widthIsSufficient; $scope.contentVisible = function() { const item = $scope.backupItem; @@ -161,7 +159,7 @@ consoleModule.controller('clustersController', [ $scope.toggleExpanded = function() { $scope.ui.expanded = !$scope.ui.expanded; - $common.hidePopover(); + LegacyUtils.hidePopover(); }; $scope.discoveries = [ @@ -256,9 +254,7 @@ consoleModule.controller('clustersController', [ DemoInfo.show(); } }) - .catch(function(errMsg) { - $common.showError(errMsg); - }) + .catch(Messages.showError) .finally(function() { $scope.ui.ready = true; $scope.ui.inputForm.$setPristine(); @@ -290,11 +286,11 @@ consoleModule.controller('clustersController', [ __original_value = $cleanup($scope.backupItem); - if ($common.getQueryVariable('new')) + if (LegacyUtils.getQueryVariable('new')) $state.go('base.configuration.clusters'); } - $common.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem); + LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem); }; $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create'; @@ -316,7 +312,7 @@ consoleModule.controller('clustersController', [ // Add new cluster. $scope.createItem = function(linkId) { - $timeout(() => $common.ensureActivePanel($scope.ui, 'general', 'clusterName')); + $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'clusterName')); $scope.selectItem(null, prepareNewItem(linkId)); }; @@ -333,14 +329,14 @@ consoleModule.controller('clustersController', [ function checkCacheDatasources(item) { const caches = clusterCaches(item); - const checkRes = $common.checkCachesDataSources(caches); + const checkRes = LegacyUtils.checkCachesDataSources(caches); if (!checkRes.checked) { return showPopoverMessage($scope.ui, 'general', 'caches', 'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' + 'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean + - '" and different databases: "' + $common.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstCache.name + '" and "' + - $common.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000); + '" and different databases: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstCache.name + '" and "' + + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000); } return true; @@ -349,7 +345,7 @@ consoleModule.controller('clustersController', [ function checkCacheSQLSchemas(item) { const caches = clusterCaches(item); - const checkRes = $common.checkCacheSQLSchemas(caches); + const checkRes = LegacyUtils.checkCacheSQLSchemas(caches); if (!checkRes.checked) { return showPopoverMessage($scope.ui, 'general', 'caches', @@ -363,12 +359,12 @@ consoleModule.controller('clustersController', [ function checkBinaryConfiguration(item) { const b = item.binaryConfiguration; - if ($common.isDefined(b)) { + if (LegacyUtils.isDefined(b)) { if (!_.isEmpty(b.typeConfigurations)) { for (let typeIx = 0; typeIx < b.typeConfigurations.length; typeIx++) { const type = b.typeConfigurations[typeIx]; - if ($common.isEmptyString(type.typeName)) + if (LegacyUtils.isEmptyString(type.typeName)) return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type name should be specified!'); if (_.find(b.typeConfigurations, (t, ix) => ix < typeIx && t.typeName === type.typeName)) @@ -383,12 +379,12 @@ consoleModule.controller('clustersController', [ function checkCommunicationConfiguration(item) { const c = item.communication; - if ($common.isDefined(c)) { - if ($common.isDefined(c.unacknowledgedMessagesBufferSize)) { - if ($common.isDefined(c.messageQueueLimit) && c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit) + 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!'); - if ($common.isDefined(c.ackSendThreshold) && c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold) + 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!'); } @@ -421,7 +417,7 @@ consoleModule.controller('clustersController', [ const sparsity = swap.maximumSparsity; - if ($common.isDefined(sparsity) && (sparsity < 0 || sparsity >= 1)) + 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!'); const readStripesNumber = swap.readStripesNumber; @@ -436,16 +432,16 @@ consoleModule.controller('clustersController', [ function checkSslConfiguration(item) { const r = item.connector; - if ($common.isDefined(r)) { - if (r.sslEnabled && $common.isEmptyString(r.sslFactory)) + if (LegacyUtils.isDefined(r)) { + if (r.sslEnabled && LegacyUtils.isEmptyString(r.sslFactory)) return showPopoverMessage($scope.ui, 'connector', 'connectorSslFactory', 'SSL factory should not be empty!'); } if (item.sslEnabled) { - if (!$common.isDefined(item.sslContextFactory) || $common.isEmptyString(item.sslContextFactory.keyStoreFilePath)) + if (!LegacyUtils.isDefined(item.sslContextFactory) || LegacyUtils.isEmptyString(item.sslContextFactory.keyStoreFilePath)) return showPopoverMessage($scope.ui, 'sslConfiguration', 'keyStoreFilePath', 'Key store file should not be empty!'); - if ($common.isEmptyString(item.sslContextFactory.trustStoreFilePath) && _.isEmpty(item.sslContextFactory.trustManagers)) + 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!'); } @@ -461,12 +457,12 @@ consoleModule.controller('clustersController', [ // Check cluster logical consistency. function validate(item) { - $common.hidePopover(); + LegacyUtils.hidePopover(); - if ($common.isEmptyString(item.name)) + if (LegacyUtils.isEmptyString(item.name)) return showPopoverMessage($scope.ui, 'general', 'clusterName', 'Cluster name should not be empty!'); - if (!$common.checkFieldValidators($scope.ui)) + if (!LegacyUtils.checkFieldValidators($scope.ui)) return false; if (!checkCacheSQLSchemas(item)) @@ -529,16 +525,16 @@ consoleModule.controller('clustersController', [ $scope.selectItem(item); - $common.showInfo('Cluster "' + item.name + '" saved.'); + Messages.showInfo('Cluster "' + item.name + '" saved.'); }) - .error((err) => $common.showError(err)); + .error(Messages.showError); } // Save cluster. $scope.saveItem = function() { const item = $scope.backupItem; - const swapSpi = $common.autoClusterSwapSpiConfiguration(item, clusterCaches(item)); + const swapSpi = LegacyUtils.autoClusterSwapSpiConfiguration(item, clusterCaches(item)); if (swapSpi) angular.extend(item, swapSpi); @@ -554,7 +550,7 @@ consoleModule.controller('clustersController', [ // Clone cluster with new name. $scope.cloneItem = function() { if (validate($scope.backupItem)) { - $clone.confirm($scope.backupItem.name, _clusterNames()).then(function(newName) { + Clone.confirm($scope.backupItem.name, _clusterNames()).then(function(newName) { const item = angular.copy($scope.backupItem); delete item._id; @@ -569,13 +565,13 @@ consoleModule.controller('clustersController', [ $scope.removeItem = function() { const selectedItem = $scope.selectedItem; - $confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?') + Confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?') .then(function() { const _id = selectedItem._id; $http.post('/api/v1/configuration/clusters/remove', {_id}) .success(function() { - $common.showInfo('Cluster has been removed: ' + selectedItem.name); + Messages.showInfo('Cluster has been removed: ' + selectedItem.name); const clusters = $scope.clusters; @@ -595,19 +591,17 @@ consoleModule.controller('clustersController', [ _.forEach($scope.igfss, (igfs) => _.remove(igfs.igfs.clusters, (id) => id === _id)); } }) - .error(function(errMsg) { - $common.showError(errMsg); - }); + .error(Messages.showError); }); }; // Remove all clusters from db. $scope.removeAllItems = function() { - $confirm.confirm('Are you sure you want to remove all clusters?') + Confirm.confirm('Are you sure you want to remove all clusters?') .then(function() { $http.post('/api/v1/configuration/clusters/remove/all') - .success(function() { - $common.showInfo('All clusters have been removed'); + .success(() => { + Messages.showInfo('All clusters have been removed'); $scope.clusters = []; @@ -617,18 +611,16 @@ consoleModule.controller('clustersController', [ $scope.backupItem = emptyCluster; $scope.ui.inputForm.$setPristine(); }) - .error(function(errMsg) { - $common.showError(errMsg); - }); + .error(Messages.showError); }); }; $scope.resetAll = function() { - $confirm.confirm('Are you sure you want to undo all changes for current cluster?') + Confirm.confirm('Are you sure you want to undo all changes for current cluster?') .then(function() { $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem(); $scope.ui.inputForm.$setPristine(); }); }; - }] -); + } +]];
