You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/11/09 08:38:41 UTC
[27/50] [abbrv] ignite git commit: Web console beta-5.
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
index 4aad7e2..4bfbf48 100644
--- a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
+++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
@@ -20,8 +20,8 @@ import JSZip from 'jszip';
import saver from 'file-saver';
export default [
- '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteLoading', '$filter', 'igniteConfigurationResource', 'JavaTypes', 'IgniteVersion', 'GeneratorDocker', 'GeneratorPom', 'IgniteFormUtils',
- function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, Version, docker, pom, FormUtils) {
+ '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteLoading', '$filter', 'IgniteConfigurationResource', 'JavaTypes', 'IgniteVersion', 'IgniteConfigurationGenerator', 'SpringTransformer', 'JavaTransformer', 'GeneratorDocker', 'GeneratorPom', 'IgnitePropertiesGenerator', 'IgniteReadmeGenerator', 'IgniteFormUtils',
+ function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, Version, generator, spring, java, docker, pom, propsGenerator, readme, FormUtils) {
const ctrl = this;
$scope.ui = { ready: false };
@@ -108,11 +108,18 @@ export default [
]
};
+ const clnCfg = { type: 'file', name: 'client.xml' };
+ const srvCfg = { type: 'file', name: 'server.xml' };
+
const resourcesFolder = {
type: 'folder',
name: 'resources',
children: [
- { type: 'file', name: 'secret.properties' }
+ {
+ type: 'folder',
+ name: 'META-INF',
+ children: [clnCfg, srvCfg]
+ }
]
};
@@ -131,10 +138,6 @@ export default [
]
};
- const clnCfg = { type: 'file', name: 'client.xml' };
-
- const srvCfg = { type: 'file', name: 'server.xml' };
-
const mainFolder = {
type: 'folder',
name: 'main',
@@ -147,11 +150,6 @@ export default [
children: [
{
type: 'folder',
- name: 'config',
- children: [clnCfg, srvCfg]
- },
- {
- type: 'folder',
name: 'jdbc-drivers',
children: [
{ type: 'file', name: 'README.txt' }
@@ -215,6 +213,16 @@ export default [
folder.children.push(leaf);
}
+ function cacheHasDatasource(cache) {
+ if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+ const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
+
+ return !!(storeFactory && (storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : false) : storeFactory.dialect)); // eslint-disable-line no-nested-ternary
+ }
+
+ return false;
+ }
+
$scope.selectItem = (cluster) => {
delete ctrl.cluster;
@@ -231,17 +239,17 @@ export default [
sessionStorage.summarySelectedId = $scope.clusters.indexOf(cluster);
- mainFolder.children = [javaFolder];
+ mainFolder.children = [javaFolder, resourcesFolder];
if (_.find(cluster.caches, (cache) => !_.isNil(cache.cacheStoreFactory)))
javaFolder.children = [javaConfigFolder, loadFolder, javaStartupFolder];
else
javaFolder.children = [javaConfigFolder, javaStartupFolder];
- if ($generatorCommon.secretPropertiesNeeded(cluster))
- mainFolder.children.push(resourcesFolder);
+ if (_.nonNil(_.find(cluster.caches, cacheHasDatasource)) || cluster.sslEnabled)
+ resourcesFolder.children.push({ type: 'file', name: 'secret.properties' });
- if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode))
+ if (java.isDemoConfigured(cluster, $root.IgniteDemoMode))
javaFolder.children.push(demoFolder);
if (cluster.discovery.kind === 'Jdbc' && cluster.discovery.Jdbc.dialect)
@@ -286,7 +294,6 @@ export default [
// TODO IGNITE-2114: implemented as independent logic for download.
$scope.downloadConfiguration = function() {
const cluster = $scope.cluster;
- const clientNearCfg = cluster.clientNearCfg;
const zip = new JSZip();
@@ -299,54 +306,65 @@ export default [
zip.file('Dockerfile', ctrl.data.docker);
zip.file('.dockerignore', docker.ignoreFile());
- const builder = $generatorProperties.generateProperties(cluster);
+ const cfg = generator.igniteConfiguration(cluster, false);
+ const clientCfg = generator.igniteConfiguration(cluster, true);
+ const clientNearCaches = _.filter(cluster.caches, (cache) => _.get(cache, 'clientNearConfiguration.enabled'));
+
+ const secProps = propsGenerator.generate(cfg);
- if (builder)
- zip.file('src/main/resources/secret.properties', builder.asString());
+ if (secProps)
+ zip.file('src/main/resources/secret.properties', secProps);
- const srcPath = 'src/main/java/';
+ const srcPath = 'src/main/java';
+ const resourcesPath = 'src/main/resources';
- const serverXml = 'config/' + cluster.name + '-server.xml';
- const clientXml = 'config/' + cluster.name + '-client.xml';
+ const serverXml = `${cluster.name}-server.xml`;
+ const clientXml = `${cluster.name}-client.xml`;
- zip.file(serverXml, $generatorXml.cluster(cluster));
- zip.file(clientXml, $generatorXml.cluster(cluster, clientNearCfg));
+ const metaPath = `${resourcesPath}/META-INF`;
- zip.file(srcPath + 'config/ServerConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ServerConfigurationFactory', null));
- zip.file(srcPath + 'config/ClientConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ClientConfigurationFactory', clientNearCfg));
+ zip.file(`${metaPath}/${serverXml}`, spring.igniteConfiguration(cfg).asString());
+ zip.file(`${metaPath}/${clientXml}`, spring.igniteConfiguration(clientCfg, clientNearCaches).asString());
- if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode)) {
- zip.file(srcPath + 'demo/DemoStartup.java', $generatorJava.nodeStartup(cluster, 'demo', 'DemoStartup',
+ const cfgPath = `${srcPath}/config`;
+
+ zip.file(`${cfgPath}/ServerConfigurationFactory.java`, java.igniteConfiguration(cfg, 'config', 'ServerConfigurationFactory').asString());
+ zip.file(`${cfgPath}/ClientConfigurationFactory.java`, java.igniteConfiguration(cfg, 'config', 'ClientConfigurationFactory', clientNearCaches).asString());
+
+ if (java.isDemoConfigured(cluster, $root.IgniteDemoMode)) {
+ zip.file(`${srcPath}/demo/DemoStartup.java`, java.nodeStartup(cluster, 'demo.DemoStartup',
'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
}
// Generate loader for caches with configured store.
- const cachesToLoad = _.filter(cluster.caches, (cache) => !_.isNil(cache.cacheStoreFactory));
+ const cachesToLoad = _.filter(cluster.caches, (cache) => _.nonNil(cache.cacheStoreFactory));
+
+ if (_.nonEmpty(cachesToLoad))
+ zip.file(`${srcPath}/load/LoadCaches.java`, java.loadCaches(cachesToLoad, 'load', 'LoadCaches', `"${clientXml}"`));
- if (!_.isEmpty(cachesToLoad))
- zip.file(srcPath + 'load/LoadCaches.java', $generatorJava.loadCaches(cachesToLoad, 'load', 'LoadCaches', '"' + clientXml + '"'));
+ const startupPath = `${srcPath}/startup`;
- zip.file(srcPath + 'startup/ServerNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeSpringStartup', '"' + serverXml + '"'));
- zip.file(srcPath + 'startup/ClientNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeSpringStartup', '"' + clientXml + '"'));
+ zip.file(`${startupPath}/ServerNodeSpringStartup.java`, java.nodeStartup(cluster, 'startup.ServerNodeSpringStartup', `"${serverXml}"`));
+ zip.file(`${startupPath}/ClientNodeSpringStartup.java`, java.nodeStartup(cluster, 'startup.ClientNodeSpringStartup', `"${clientXml}"`));
- zip.file(srcPath + 'startup/ServerNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeCodeStartup',
+ zip.file(`${startupPath}/ServerNodeCodeStartup.java`, java.nodeStartup(cluster, 'startup.ServerNodeCodeStartup',
'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
- zip.file(srcPath + 'startup/ClientNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeCodeStartup',
- 'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCfg));
+ zip.file(`${startupPath}/ClientNodeCodeStartup.java`, java.nodeStartup(cluster, 'startup.ClientNodeCodeStartup',
+ 'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCaches));
- zip.file('pom.xml', pom.generate(cluster, Version.ignite).asString());
+ zip.file('pom.xml', pom.generate(cluster, Version.productVersion().ignite).asString());
- zip.file('README.txt', $generatorReadme.readme().asString());
- zip.file('jdbc-drivers/README.txt', $generatorReadme.readmeJdbc().asString());
+ zip.file('README.txt', readme.generate());
+ zip.file('jdbc-drivers/README.txt', readme.generateJDBC());
- if (!ctrl.data.pojos)
- ctrl.data.pojos = $generatorJava.pojos(cluster.caches);
+ if (_.isEmpty(ctrl.data.pojos))
+ ctrl.data.pojos = java.pojos(cluster.caches);
for (const pojo of ctrl.data.pojos) {
if (pojo.keyClass && JavaTypes.nonBuiltInClass(pojo.keyType))
- zip.file(srcPath + pojo.keyType.replace(/\./g, '/') + '.java', pojo.keyClass);
+ zip.file(`${srcPath}/${pojo.keyType.replace(/\./g, '/')}.java`, pojo.keyClass);
- zip.file(srcPath + pojo.valueType.replace(/\./g, '/') + '.java', pojo.valueClass);
+ zip.file(`${srcPath}/${pojo.valueType.replace(/\./g, '/')}.java`, pojo.valueClass);
}
$generatorOptional.optionalContent(zip, cluster);
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/services/ErrorPopover.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ErrorPopover.service.js b/modules/web-console/frontend/app/services/ErrorPopover.service.js
index 3130431..5132d50 100644
--- a/modules/web-console/frontend/app/services/ErrorPopover.service.js
+++ b/modules/web-console/frontend/app/services/ErrorPopover.service.js
@@ -108,7 +108,7 @@ export default class ErrorPopover {
if (this._popover)
this._popover.hide();
- if (ui) {
+ if (ui && ui.isPanelLoaded) {
this.FormUtils.ensureActivePanel(ui, panelId, id);
this.$timeout(() => this._show(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500);
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/services/FormUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/FormUtils.service.js b/modules/web-console/frontend/app/services/FormUtils.service.js
index 5e7943a..6ccc3c6 100644
--- a/modules/web-console/frontend/app/services/FormUtils.service.js
+++ b/modules/web-console/frontend/app/services/FormUtils.service.js
@@ -17,7 +17,7 @@
export default ['IgniteFormUtils', ['$window', 'IgniteFocus', ($window, Focus) => {
function ensureActivePanel(ui, pnl, focusId) {
- if (ui) {
+ if (ui && ui.loadPanel) {
const collapses = $('div.panel-collapse');
ui.loadPanel(pnl);
@@ -430,6 +430,10 @@ export default ['IgniteFormUtils', ['$window', 'IgniteFocus', ($window, Focus) =
return _.includes(this.loadedPanels, pnl);
}
};
+ },
+ markPristineInvalidAsDirty(ngModelCtrl) {
+ if (ngModelCtrl && ngModelCtrl.$invalid && ngModelCtrl.$pristine)
+ ngModelCtrl.$setDirty();
}
};
}]];
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/services/JavaTypes.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/JavaTypes.service.js b/modules/web-console/frontend/app/services/JavaTypes.service.js
index 8cb87be..679914f 100644
--- a/modules/web-console/frontend/app/services/JavaTypes.service.js
+++ b/modules/web-console/frontend/app/services/JavaTypes.service.js
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-import _ from 'lodash';
-
// Java built-in class names.
import JAVA_CLASSES from '../data/java-classes.json';
@@ -42,6 +40,42 @@ const VALID_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-
* Utility service for various check on java types.
*/
export default class JavaTypes {
+ static $inject = ['igniteClusterDefaults', 'igniteCacheDefaults', 'igniteIgfsDefaults'];
+
+ constructor(clusterDflts, cacheDflts, igfsDflts) {
+ this.enumClasses = _.uniq(this._enumClassesAcc(_.merge(clusterDflts, cacheDflts, igfsDflts), []));
+ this.shortEnumClasses = _.map(this.enumClasses, (cls) => this.shortClassName(cls));
+ }
+
+ /**
+ * Collects recursive enum classes.
+ *
+ * @param root Root object.
+ * @param classes Collected classes.
+ * @return {Array.<String>}
+ * @private
+ */
+ _enumClassesAcc(root, classes) {
+ return _.reduce(root, (acc, val, key) => {
+ if (key === 'clsName')
+ acc.push(val);
+ else if (_.isObject(val))
+ this._enumClassesAcc(val, acc);
+
+ return acc;
+ }, classes);
+ }
+
+ /**
+ * Check if class name is non enum class in Ignite configuration.
+ *
+ * @param clsName
+ * @return {boolean}
+ */
+ nonEnum(clsName) {
+ return !_.includes(this.shortEnumClasses, clsName) && !_.includes(this.enumClasses, clsName);
+ }
+
/**
* @param clsName {String} Class name to check.
* @returns {boolean} 'true' if provided class name is a not Java built in class.
@@ -52,7 +86,7 @@ export default class JavaTypes {
/**
* @param clsName Class name to check.
- * @returns Full class name for java build-in types or source class otherwise.
+ * @returns {String} Full class name for java build-in types or source class otherwise.
*/
fullClassName(clsName) {
const type = _.find(JAVA_CLASSES, (clazz) => clsName === clazz.short);
@@ -61,6 +95,23 @@ export default class JavaTypes {
}
/**
+ * Extract class name from full class name.
+ *
+ * @param clsName full class name.
+ * @return {String} Class name.
+ */
+ shortClassName(clsName) {
+ if (this.isJavaPrimitive(clsName))
+ return clsName;
+
+ const fullClsName = this.fullClassName(clsName);
+
+ const dotIdx = fullClsName.lastIndexOf('.');
+
+ return dotIdx > 0 ? fullClsName.substr(dotIdx + 1) : fullClsName;
+ }
+
+ /**
* @param value {String} Value text to check.
* @returns {boolean} 'true' if given text is valid Java class name.
*/
@@ -115,4 +166,17 @@ export default class JavaTypes {
isJavaPrimitive(clsName) {
return _.includes(JAVA_PRIMITIVES, clsName);
}
+
+ /**
+ * Convert some name to valid java name.
+ *
+ * @param prefix To append to java name.
+ * @param name to convert.
+ * @returns {string} Valid java name.
+ */
+ toJavaName(prefix, name) {
+ const javaName = name ? this.shortClassName(name).replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
+
+ return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/services/LegacyTable.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/LegacyTable.service.js b/modules/web-console/frontend/app/services/LegacyTable.service.js
index 5d9ec9d..a024a3b 100644
--- a/modules/web-console/frontend/app/services/LegacyTable.service.js
+++ b/modules/web-console/frontend/app/services/LegacyTable.service.js
@@ -19,7 +19,27 @@
export default ['IgniteLegacyTable',
['IgniteLegacyUtils', 'IgniteFocus', 'IgniteErrorPopover', (LegacyUtils, Focus, ErrorPopover) => {
function _model(item, field) {
- return LegacyUtils.getModel(item, field);
+ let path = field.path;
+
+ if (_.isNil(path) || _.isNil(item))
+ return item;
+
+ path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+ path = path.replace(/^\./, ''); // strip a leading dot
+
+ const segs = path.split('.');
+ let root = item;
+
+ while (segs.length > 0) {
+ const pathStep = segs.shift();
+
+ if (typeof root[pathStep] === 'undefined')
+ root[pathStep] = {};
+
+ root = root[pathStep];
+ }
+
+ return root;
}
const table = {name: 'none', editIndex: -1};
@@ -190,7 +210,7 @@ export default ['IgniteLegacyTable',
}
}
- return valid;
+ return valid || stopEdit;
},
tablePairSaveVisible(field, index) {
const pairValue = _tablePairValue(field, index);
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/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 dcf0bc8..e7c064b 100644
--- a/modules/web-console/frontend/app/services/LegacyUtils.service.js
+++ b/modules/web-console/frontend/app/services/LegacyUtils.service.js
@@ -182,43 +182,19 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
const VALID_JAVA_IDENTIFIER = new RegExp('^[a-zA-Z_$][a-zA-Z\\d_$]*$');
- function isValidJavaIdentifier(msg, ident, elemId, panels, panelId) {
+ function isValidJavaIdentifier(msg, ident, elemId, panels, panelId, stopEdit) {
if (isEmptyString(ident))
- return ErrorPopover.show(elemId, msg + ' is invalid!', panels, panelId);
+ return !stopEdit && 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);
+ return !stopEdit && 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 !stopEdit && ErrorPopover.show(elemId, msg + ' contains invalid identifier: "' + ident + '"!', panels, panelId);
return true;
}
- 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.
*
@@ -226,18 +202,26 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
* @returns {*} Datasource object or null if not set.
*/
function extractDataSource(object) {
+ let datasource = null;
+
// Extract from cluster object
if (_.get(object, 'discovery.kind') === 'Jdbc') {
- const datasource = object.discovery.Jdbc;
+ datasource = object.discovery.Jdbc;
+
+ if (datasource.dataSourceBean && datasource.dialect)
+ return datasource;
+ } // Extract from JDBC checkpoint configuration.
+ else if (_.get(object, 'kind') === 'JDBC') {
+ datasource = object.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];
+ datasource = object.cacheStoreFactory[object.cacheStoreFactory.kind];
- if (storeFactory.dialect || (storeFactory.connectVia === 'DataSource'))
- return storeFactory;
+ if (datasource.dialect || (datasource.connectVia === 'DataSource'))
+ return datasource;
}
return null;
@@ -268,10 +252,13 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
* Compare datasources of caches or clusters.
*
* @param firstObj First cache or cluster.
+ * @param firstType Type of first object to compare.
* @param secondObj Second cache or cluster.
+ * @param secondType Type of first object to compare.
+ * @param index Index of invalid object when check is failed.
* @returns {*} Check result object.
*/
- function compareDataSources(firstObj, secondObj) {
+ function compareDataSources(firstObj, firstType, secondObj, secondType, index) {
const firstDs = extractDataSource(firstObj);
const secondDs = extractDataSource(secondObj);
@@ -280,7 +267,7 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
const secondDB = secondDs.dialect;
if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB)
- return {checked: false, firstObj, firstDB, secondObj, secondDB};
+ return {checked: false, firstObj, firstDs, firstType, secondObj, secondDs, secondType, index};
}
return DS_CHECK_SUCCESS;
@@ -303,7 +290,6 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
}
return {
- getModel,
mkOptions(options) {
return _.map(options, (option) => {
return {value: option, label: isDefined(option) ? option : 'Not set'};
@@ -326,24 +312,24 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
javaBuiltInTypes,
isJavaBuiltInClass,
isValidJavaIdentifier,
- isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId) {
+ isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId, stopEdit = false) {
if (isEmptyString(ident))
- return ErrorPopover.show(elemId, msg + ' could not be empty!', panels, panelId);
+ return !stopEdit && ErrorPopover.show(elemId, msg + ' could not be empty!', panels, panelId);
const parts = ident.split('.');
const len = parts.length;
if (!allowBuiltInClass && isJavaBuiltInClass(ident))
- return ErrorPopover.show(elemId, msg + ' should not be the Java build-in class!', panels, panelId);
+ return !stopEdit && ErrorPopover.show(elemId, msg + ' should not be the Java build-in class!', panels, panelId);
if (len < 2 && !isJavaBuiltInClass(ident) && !packageOnly)
- return ErrorPopover.show(elemId, msg + ' does not have package specified!', panels, panelId);
+ return !stopEdit && ErrorPopover.show(elemId, msg + ' does not have package specified!', panels, panelId);
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
- if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId))
+ if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId, stopEdit))
return false;
}
@@ -394,14 +380,25 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
let res = DS_CHECK_SUCCESS;
_.find(caches, (curCache, curIx) => {
- res = compareDataSources(curCache, cluster);
+ // Check datasources of cluster JDBC ip finder and cache store factory datasource.
+ res = compareDataSources(curCache, 'cache', cluster, 'cluster');
+
+ if (!res.checked)
+ return true;
+
+ _.find(cluster.checkpointSpi, (spi, spiIx) => {
+ res = compareDataSources(curCache, 'cache', spi, 'checkpoint', spiIx);
+
+ return !res.checked;
+ });
if (!res.checked)
return true;
+ // Check datasource of current saved cache and datasource of other cache in cluster.
if (isDefined(checkCacheExt)) {
if (checkCacheExt._id !== curCache._id) {
- res = compareDataSources(checkCacheExt, curCache);
+ res = compareDataSources(checkCacheExt, 'cache', curCache, 'cache');
return !res.checked;
}
@@ -409,9 +406,10 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
return false;
}
+ // Check datasources of specified list of caches.
return _.find(caches, (checkCache, checkIx) => {
if (checkIx < curIx) {
- res = compareDataSources(checkCache, curCache);
+ res = compareDataSources(checkCache, 'cache', curCache, 'cache');
return !res.checked;
}
@@ -420,6 +418,26 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
});
});
+ if (res.checked) {
+ _.find(cluster.checkpointSpi, (curSpi, curIx) => {
+ // Check datasources of cluster JDBC ip finder and cache store factory datasource.
+ res = compareDataSources(cluster, 'cluster', curSpi, 'checkpoint', curIx);
+
+ if (!res.checked)
+ return true;
+
+ _.find(cluster.checkpointSpi, (spi, spiIx) => {
+ if (spiIx < curIx) {
+ res = compareDataSources(curSpi, 'checkpoint', spi, 'checkpoint', curIx);
+
+ return !res.checked;
+ }
+
+ return false;
+ });
+ });
+ }
+
return res;
},
checkCacheSQLSchemas(caches, checkCacheExt) {
@@ -469,14 +487,8 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
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;
+ return {};
},
randomString(len) {
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -498,7 +510,10 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
const firstErrorKey = errKeys[0];
const firstError = errors[firstErrorKey][0];
- const actualError = firstError.$error[firstErrorKey][0];
+
+ const err = firstError.$error[firstErrorKey];
+
+ const actualError = _.isArray(err) ? err[0] : firstError;
const errNameFull = actualError.$name;
const errNameShort = errNameFull.endsWith('TextInput') ? errNameFull.substring(0, errNameFull.length - 9) : errNameFull;
@@ -507,12 +522,17 @@ export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
try {
return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
}
- catch (ignored) {
+ catch (ignored1) {
try {
return form[firstError.$name].$errorMessages[errName][firstErrorKey];
}
- catch (ignited) {
- return false;
+ catch (ignored2) {
+ try {
+ return form.$errorMessages[errName][firstErrorKey];
+ }
+ catch (ignored3) {
+ return false;
+ }
}
}
};
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/services/SqlTypes.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/SqlTypes.service.js b/modules/web-console/frontend/app/services/SqlTypes.service.js
index 2a16e9d..e42d903 100644
--- a/modules/web-console/frontend/app/services/SqlTypes.service.js
+++ b/modules/web-console/frontend/app/services/SqlTypes.service.js
@@ -15,13 +15,11 @@
* limitations under the License.
*/
-import _ from 'lodash';
-
// List of H2 reserved SQL keywords.
-import H2_SQL_KEYWORDS from '../data/sql-keywords.json';
+import H2_SQL_KEYWORDS from 'app/data/sql-keywords.json';
// List of JDBC type descriptors.
-import JDBC_TYPES from '../data/jdbc-types.json';
+import JDBC_TYPES from 'app/data/jdbc-types.json';
// Regular expression to check H2 SQL identifier.
const VALID_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_$]*$/im;
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/vendor.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/vendor.js b/modules/web-console/frontend/app/vendor.js
index 0322887..a9e8844 100644
--- a/modules/web-console/frontend/app/vendor.js
+++ b/modules/web-console/frontend/app/vendor.js
@@ -38,6 +38,7 @@ import 'brace';
import 'brace/mode/xml';
import 'brace/mode/sql';
import 'brace/mode/java';
+import 'brace/mode/csharp';
import 'brace/mode/dockerfile';
import 'brace/mode/snippets';
import 'brace/theme/chrome';
@@ -46,7 +47,7 @@ import 'brace/ext/searchbox';
import 'file-saver';
import 'jszip';
import 'nvd3';
-import 'query-command-supported';
+import 'lodash';
import 'angular-gridster/dist/angular-gridster.min.css';
import 'angular-tree-control/css/tree-control-attribute.css';
import 'angular-tree-control/css/tree-control.css';
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/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 8c32906..8c01173 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', 'IgniteErrorPopover', 'IgniteFormUtils',
- function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, Resource, ErrorPopover, FormUtils) {
+ '$scope', '$http', '$state', '$filter', '$timeout', '$modal', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils', 'IgniteLegacyTable',
+ function($scope, $http, $state, $filter, $timeout, $modal, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, Resource, ErrorPopover, FormUtils, LegacyTable) {
UnsavedChangesGuard.install($scope);
const emptyCache = {empty: true};
@@ -96,6 +96,73 @@ export default ['cachesController', [
item.offHeapMaxMemory = item.offHeapMaxMemory > 0 ? item.offHeapMaxMemory : null;
};
+ $scope.tablePairSave = LegacyTable.tablePairSave;
+ $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+ $scope.tableNewItem = LegacyTable.tableNewItem;
+ $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
+
+ $scope.tableStartEdit = function(item, field, index) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
+ };
+
+ $scope.tableEditing = LegacyTable.tableEditing;
+
+ $scope.tableSave = function(field, index, stopEdit) {
+ if (LegacyTable.tablePairSaveVisible(field, index))
+ return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+ return true;
+ };
+
+ $scope.tableRemove = function(item, field, index) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableRemove(item, field, index);
+ };
+
+ $scope.tableReset = (trySave) => {
+ const field = LegacyTable.tableField();
+
+ if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
+ return false;
+
+ LegacyTable.tableReset();
+
+ return true;
+ };
+
+ $scope.hibernatePropsTbl = {
+ type: 'hibernate',
+ model: 'cacheStoreFactory.CacheHibernateBlobStoreFactory.hibernateProperties',
+ focusId: 'Property',
+ ui: 'table-pair',
+ keyName: 'name',
+ valueName: 'value',
+ save: $scope.tableSave
+ };
+
+ $scope.tablePairValid = function(item, field, index, stopEdit) {
+ const pairValue = LegacyTable.tablePairValue(field, index);
+
+ const model = _.get(item, field.model);
+
+ if (!_.isNil(model)) {
+ const idx = _.findIndex(model, (pair) => {
+ return pair.name === pairValue.key;
+ });
+
+ // Found duplicate by key.
+ if (idx >= 0 && idx !== index) {
+ if (stopEdit)
+ return false;
+
+ return ErrorPopover.show(LegacyTable.tableFieldId(index, 'KeyProperty'), 'Property with such name already exists!', $scope.ui, 'query');
+ }
+ }
+
+ return true;
+ };
+
Loading.start('loadingCachesScreen');
// When landing on the page, get caches and show them.
@@ -117,6 +184,7 @@ export default ['cachesController', [
value: cluster._id,
label: cluster.name,
discovery: cluster.discovery,
+ checkpointSpi: cluster.checkpointSpi,
caches: cluster.caches
}));
@@ -204,7 +272,7 @@ export default ['cachesController', [
else
$scope.backupItem = emptyCache;
- $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+ $scope.backupItem = _.merge({}, blank, $scope.backupItem);
if ($scope.ui.inputForm) {
$scope.ui.inputForm.$error = {};
@@ -258,6 +326,15 @@ export default ['cachesController', [
return caches;
}
+ const _objToString = (type, name, prefix = '') => {
+ if (type === 'checkpoint')
+ return `${prefix} checkpoint configuration in cluster "${name}"`;
+ if (type === 'cluster')
+ return `${prefix} discovery IP finder in cluster "${name}"`;
+
+ return `${prefix} ${type} "${name}"`;
+ };
+
function checkDataSources() {
const clusters = cacheClusters();
@@ -272,20 +349,11 @@ export default ['cachesController', [
});
if (!checkRes.checked) {
- if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
- return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialectInput' : 'blobDialectInput',
- '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',
- $scope.ui, 'store', 10000);
- }
-
return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialectInput' : 'blobDialectInput',
- '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',
+ 'Found ' + _objToString(checkRes.secondType, checkRes.secondObj.name || failCluster.label) + ' with the same data source bean name "' +
+ checkRes.firstDs.dataSourceBean + '" and different database: "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDs.dialect) + '" in ' + _objToString(checkRes.firstType, checkRes.firstObj.name, 'current') + ' and "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDs.dialect) + '" in ' + _objToString(checkRes.secondType, checkRes.secondObj.name || failCluster.label),
$scope.ui, 'store', 10000);
}
@@ -296,7 +364,7 @@ export default ['cachesController', [
if (evictionPlc && evictionPlc.kind) {
const plc = evictionPlc[evictionPlc.kind];
- if (plc.maxMemorySize === 0 && plc.maxSize === 0)
+ if (plc && !plc.maxMemorySize && !plc.maxSize)
return ErrorPopover.show('evictionPolicymaxMemorySizeInput', 'Either maximum memory size or maximum size should be great than 0!', $scope.ui, 'memory');
}
@@ -409,7 +477,7 @@ export default ['cachesController', [
});
if (idx >= 0)
- angular.merge($scope.caches[idx], item);
+ _.assign($scope.caches[idx], item);
else {
item._id = _id;
$scope.caches.push(item);
@@ -440,7 +508,7 @@ export default ['cachesController', [
$scope.saveItem = function() {
const item = $scope.backupItem;
- angular.extend(item, LegacyUtils.autoCacheStoreConfiguration(item, cacheDomains(item)));
+ _.merge(item, LegacyUtils.autoCacheStoreConfiguration(item, cacheDomains(item)));
if (validate(item))
save(item);
@@ -462,7 +530,20 @@ export default ['cachesController', [
item.name = newName;
- delete item.sqlSchema;
+ if (!_.isEmpty(item.clusters) && !_.isNil(item.sqlSchema)) {
+ delete item.sqlSchema;
+
+ const scope = $scope.$new();
+
+ scope.title = 'Info';
+ scope.content = [
+ 'Use the same SQL schema name in one cluster in not allowed',
+ 'SQL schema name will be reset'
+ ];
+
+ // Show a basic modal from a controller
+ $modal({scope, template: '/templates/message.html', placement: 'center', show: true});
+ }
save(item);
});
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/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 5a3c7e2..f9096f7 100644
--- a/modules/web-console/frontend/controllers/clusters-controller.js
+++ b/modules/web-console/frontend/controllers/clusters-controller.js
@@ -17,7 +17,7 @@
// Controller for Clusters screen.
export default ['clustersController', [
- '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+ '$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);
@@ -103,6 +103,46 @@ export default ['clustersController', [
else
$scope.backupItem.failoverSpi = {};
}
+ else if (field.type === 'loadBalancingSpi') {
+ const newLoadBalancing = {Adaptive: {
+ loadProbe: {
+ Job: {useAverage: true},
+ CPU: {
+ useAverage: true,
+ useProcessors: true
+ },
+ ProcessingTime: {useAverage: true}
+ }
+ }};
+
+ if (LegacyUtils.isDefined($scope.backupItem.loadBalancingSpi))
+ $scope.backupItem.loadBalancingSpi.push(newLoadBalancing);
+ else
+ $scope.backupItem.loadBalancingSpi = [newLoadBalancing];
+ }
+ else if (field.type === 'checkpointSpi') {
+ const newCheckpointCfg = {
+ FS: {
+ directoryPaths: []
+ },
+ S3: {
+ awsCredentials: {
+ kind: 'Basic'
+ },
+ clientConfiguration: {
+ retryPolicy: {
+ kind: 'Default'
+ },
+ useReaper: true
+ }
+ }
+ };
+
+ if (LegacyUtils.isDefined($scope.backupItem.checkpointSpi))
+ $scope.backupItem.checkpointSpi.push(newCheckpointCfg);
+ else
+ $scope.backupItem.checkpointSpi = [newCheckpointCfg];
+ }
else
LegacyTable.tableNewItem(field);
}
@@ -149,6 +189,8 @@ export default ['clustersController', [
$scope.backupItem.failoverSpi.splice(idx, 1);
};
+ $scope.supportedJdbcTypes = LegacyUtils.mkOptions(LegacyUtils.SUPPORTED_JDBC_TYPES);
+
// We need to initialize backupItem with empty object in order to properly used from angular directives.
$scope.backupItem = emptyCluster;
@@ -204,11 +246,20 @@ export default ['clustersController', [
// When landing on the page, get clusters and show them.
Resource.read()
- .then(({spaces, clusters, caches, igfss}) => {
+ .then(({spaces, clusters, caches, domains, igfss}) => {
$scope.spaces = spaces;
+
$scope.clusters = clusters;
- $scope.caches = _.map(caches, (cache) => ({value: cache._id, label: cache.name, cache}));
+ $scope.caches = _.map(caches, (cache) => {
+ cache.domains = _.filter(domains, ({_id}) => _.includes(cache.domains, _id));
+
+ if (_.get(cache, 'nodeFilter.kind') === 'IGFS')
+ cache.nodeFilter.IGFS.instance = _.find(igfss, {_id: cache.nodeFilter.IGFS.igfs});
+
+ return {value: cache._id, label: cache.name, cache};
+ });
+
$scope.igfss = _.map(igfss, (igfs) => ({value: igfs._id, label: igfs.name, igfs}));
_.forEach($scope.clusters, (cluster) => {
@@ -222,6 +273,9 @@ export default ['clustersController', [
if (!cluster.logger)
cluster.logger = {Log4j: { mode: 'Default'}};
+
+ if (!cluster.eventStorage)
+ cluster.eventStorage = { kind: 'Memory' };
});
if ($state.params.linkId)
@@ -259,6 +313,12 @@ export default ['clustersController', [
form.$setPristine();
else
form.$setDirty();
+
+ $scope.clusterCaches = _.filter($scope.caches,
+ (cache) => _.find($scope.backupItem.caches,
+ (selCache) => selCache === cache.value
+ )
+ );
}, true);
$scope.$watch('ui.activePanels.length', () => {
@@ -279,6 +339,8 @@ export default ['clustersController', [
Loading.finish('loadingClustersScreen');
});
+ $scope.clusterCaches = [];
+
$scope.selectItem = function(item, backup) {
function selectItem() {
$scope.selectedItem = item;
@@ -300,7 +362,7 @@ export default ['clustersController', [
else
$scope.backupItem = emptyCluster;
- $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+ $scope.backupItem = _.merge({}, blank, $scope.backupItem);
if ($scope.ui.inputForm) {
$scope.ui.inputForm.$error = {};
@@ -319,7 +381,7 @@ export default ['clustersController', [
$scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
function prepareNewItem(linkId) {
- return angular.merge({}, blank, {
+ return _.merge({}, blank, {
space: $scope.spaces[0]._id,
discovery: {
kind: 'Multicast',
@@ -331,6 +393,7 @@ export default ['clustersController', [
communication: {tcpNoDelay: true},
connector: {noDelay: true},
collision: {kind: 'Noop', JobStealing: {stealingEnabled: true}, PriorityQueue: {starvationPreventionEnabled: true}},
+ eventStorage: {kind: 'Memory'},
failoverSpi: [],
logger: {Log4j: { mode: 'Default'}},
caches: linkId && _.find($scope.caches, {value: linkId}) ? [linkId] : [],
@@ -354,27 +417,45 @@ export default ['clustersController', [
(cache) => _.includes(item.caches, cache._id));
}
+ const _objToString = (type, name, prefix = '') => {
+ if (type === 'checkpoint')
+ return prefix + ' checkpoint configuration';
+ if (type === 'cluster')
+ return prefix + ' discovery IP finder';
+
+ return `${prefix} ${type} "${name}"`;
+ };
+
function checkCacheDatasources(item) {
const caches = clusterCaches(item);
const checkRes = LegacyUtils.checkDataSources(item, caches);
if (!checkRes.checked) {
- if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
- return ErrorPopover.show('dialectInput',
- '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',
- $scope.ui, 'general', 10000);
+ let ids;
+
+ if (checkRes.secondType === 'cluster')
+ ids = { section: 'general', fieldId: 'dialectInput' };
+ else if (checkRes.secondType === 'cache')
+ ids = { section: 'general', fieldId: 'cachesInput' };
+ else if (checkRes.secondType === 'checkpoint')
+ ids = { section: 'checkpoint', fieldId: `checkpointJdbcDialect${checkRes.index}Input` };
+ else
+ return true;
+
+ if (checkRes.firstType === checkRes.secondType && checkRes.firstType === 'cache') {
+ return ErrorPopover.show(ids.fieldId, 'Found caches "' + checkRes.firstObj.name + '" and "' + checkRes.secondObj.name + '" with the same data source bean name "' +
+ checkRes.firstDs.dataSourceBean + '" and different database: "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDs.dialect) + '" in ' + _objToString(checkRes.secondType, checkRes.secondObj.name) + ' and "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDs.dialect) + '" in ' + _objToString(checkRes.firstType, checkRes.firstObj.name),
+ $scope.ui, ids.section, 10000);
}
- return ErrorPopover.show('cachesInput',
- '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',
- $scope.ui, 'general', 10000);
+ return ErrorPopover.show(ids.fieldId, 'Found ' + _objToString(checkRes.firstType, checkRes.firstObj.name) + ' with the same data source bean name "' +
+ checkRes.firstDs.dataSourceBean + '" and different database: "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDs.dialect) + '" in ' + _objToString(checkRes.secondType, checkRes.secondObj.name, 'current') + ' and "' +
+ LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDs.dialect) + '" in ' + _objToString(checkRes.firstType, checkRes.firstObj.name),
+ $scope.ui, ids.section, 10000);
}
return true;
@@ -434,6 +515,38 @@ export default ['clustersController', [
return true;
}
+ function checkCheckpointSpis(item) {
+ const cfgs = item.checkpointSpi;
+
+ if (_.isEmpty(cfgs))
+ return true;
+
+ return _.isNil(_.find(cfgs, (cfg, ix) => {
+ if (_.isNil(cfg.kind)) {
+ ErrorPopover.show('checkpointKind' + ix, 'Choose checkpoint implementation variant', $scope.ui, 'checkpoint');
+
+ return true;
+ }
+
+ switch (cfg.kind) {
+ case 'Cache':
+ const cache = _.get(cfg, 'Cache.cache');
+
+ if (_.isNil(cache) || !_.find($scope.backupItem.caches, (selCache) => cache === selCache)) {
+ ErrorPopover.show('checkpointCacheCache' + ix, 'Choose cache from configured cluster caches', $scope.ui, 'checkpoint');
+
+ return true;
+ }
+
+ break;
+
+ default: break;
+ }
+
+ return false;
+ }));
+ }
+
function checkCommunicationConfiguration(item) {
const c = item.communication;
@@ -467,6 +580,20 @@ export default ['clustersController', [
return true;
}
+ function checkLoadBalancingConfiguration(item) {
+ const balancingSpis = item.loadBalancingSpi;
+
+ return _.isNil(_.find(balancingSpis, (curSpi, curIx) => {
+ if (_.find(balancingSpis, (spi, ix) => curIx > ix && curSpi.kind === spi.kind)) {
+ ErrorPopover.show('loadBalancingKind' + curIx, 'Load balancing SPI of that type is already configured', $scope.ui, 'loadBalancing');
+
+ return true;
+ }
+
+ return false;
+ }));
+ }
+
function checkSwapConfiguration(item) {
const swapKind = item.swapSpaceSpi && item.swapSpaceSpi.kind;
@@ -535,12 +662,18 @@ export default ['clustersController', [
if (!checkCacheKeyConfiguration(item))
return false;
+ if (!checkCheckpointSpis(item))
+ return false;
+
if (!checkCommunicationConfiguration(item))
return false;
if (!checkDiscoveryConfiguration(item))
return false;
+ if (!checkLoadBalancingConfiguration(item))
+ return false;
+
if (!checkSwapConfiguration(item))
return false;
@@ -564,7 +697,7 @@ export default ['clustersController', [
const idx = _.findIndex($scope.clusters, (cluster) => cluster._id === _id);
if (idx >= 0)
- angular.merge($scope.clusters[idx], item);
+ _.assign($scope.clusters[idx], item);
else {
item._id = _id;
$scope.clusters.push(item);
@@ -595,10 +728,10 @@ export default ['clustersController', [
$scope.saveItem = function() {
const item = $scope.backupItem;
- const swapSpi = LegacyUtils.autoClusterSwapSpiConfiguration(item, clusterCaches(item));
+ const swapConfigured = item.swapSpaceSpi && item.swapSpaceSpi.kind;
- if (swapSpi)
- angular.extend(item, swapSpi);
+ if (!swapConfigured && _.find(clusterCaches(item), (cache) => cache.swapEnabled))
+ _.merge(item, {swapSpaceSpi: {kind: 'FileSwapSpaceSpi'}});
if (validate(item))
save(item);
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/domains-controller.js b/modules/web-console/frontend/controllers/domains-controller.js
index 2d450db..0a79d82 100644
--- a/modules/web-console/frontend/controllers/domains-controller.js
+++ b/modules/web-console/frontend/controllers/domains-controller.js
@@ -17,7 +17,7 @@
// Controller for Domain model screen.
export default ['domainsController', [
- '$rootScope', '$scope', '$http', '$state', '$filter', '$timeout', '$modal', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteAgentMonitor', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils', 'JavaTypes', 'SqlTypes',
+ '$rootScope', '$scope', '$http', '$state', '$filter', '$timeout', '$modal', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteAgentMonitor', 'IgniteLegacyTable', 'IgniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils', 'JavaTypes', 'SqlTypes',
function($root, $scope, $http, $state, $filter, $timeout, $modal, LegacyUtils, Messages, Focus, Confirm, ConfirmBatch, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, IgniteAgentMonitor, LegacyTable, Resource, ErrorPopover, FormUtils, JavaTypes, SqlTypes) {
UnsavedChangesGuard.install($scope);
@@ -58,6 +58,7 @@ export default ['domainsController', [
$scope.$on('$destroy', $root.$on('user', _packageNameUpdate));
+ $scope.ui.generatePojo = true;
$scope.ui.builtinKeys = true;
$scope.ui.usePrimitives = true;
$scope.ui.generateAliases = true;
@@ -75,7 +76,6 @@ export default ['domainsController', [
return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
};
- $scope.getModel = LegacyUtils.getModel;
$scope.javaBuiltInClasses = LegacyUtils.javaBuiltInClasses;
$scope.compactJavaName = FormUtils.compactJavaName;
$scope.widthIsSufficient = FormUtils.widthIsSufficient;
@@ -91,7 +91,7 @@ export default ['domainsController', [
case 'fields':
case 'aliases':
if (LegacyTable.tablePairSaveVisible(field, index))
- return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+ return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit) || stopEdit;
break;
@@ -140,11 +140,43 @@ export default ['domainsController', [
$scope.tableEditing = LegacyTable.tableEditing;
$scope.tableRemove = function(item, field, index) {
- if ($scope.tableReset(true))
+ if ($scope.tableReset(true)) {
+ // Remove field from indexes.
+ if (field.type === 'fields') {
+ _.forEach($scope.backupItem.indexes, (modelIndex) => {
+ modelIndex.fields = _.filter(modelIndex.fields, (indexField) => {
+ return indexField.name !== $scope.backupItem.fields[index].name;
+ });
+ });
+ }
+
LegacyTable.tableRemove(item, field, index);
+ }
+ };
+
+ $scope.tablePairSave = (pairValid, item, field, index, stopEdit) => {
+ // On change of field name update that field in index fields.
+ if (index >= 0 && field.type === 'fields') {
+ const newName = LegacyTable.tablePairValue(field, index).key;
+ const oldName = _.get(item, field.model)[index][field.keyName];
+
+ const saved = LegacyTable.tablePairSave(pairValid, item, field, index, stopEdit);
+
+ if (saved && oldName !== newName) {
+ _.forEach($scope.backupItem.indexes, (idx) => {
+ _.forEach(idx.fields, (fld) => {
+ if (fld.name === oldName)
+ fld.name = newName;
+ });
+ });
+ }
+
+ return saved;
+ }
+
+ return LegacyTable.tablePairSave(pairValid, item, field, index, stopEdit);
};
- $scope.tablePairSave = LegacyTable.tablePairSave;
$scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
$scope.queryFieldsTbl = {
@@ -169,6 +201,19 @@ export default ['domainsController', [
$scope.queryMetadataVariants = LegacyUtils.mkOptions(['Annotations', 'Configuration']);
+ // Create list of fields to show in index fields dropdown.
+ $scope.fields = (prefix, cur) => {
+ const fields = _.map($scope.backupItem.fields, (field) => ({value: field.name, label: field.name}));
+
+ if (prefix === 'new')
+ return fields;
+
+ if (cur && !_.find(fields, {value: cur}))
+ fields.push({value: cur, label: cur + ' (Unknown field)'});
+
+ return fields;
+ };
+
const INFO_CONNECT_TO_DB = 'Configure connection to database';
const INFO_SELECT_SCHEMAS = 'Select schemas to load tables from';
const INFO_SELECT_TABLES = 'Select tables to import as domain model';
@@ -215,6 +260,12 @@ export default ['domainsController', [
user: 'root'
},
{
+ db: 'MySQL',
+ jdbcDriverClass: 'org.mariadb.jdbc.Driver',
+ jdbcUrl: 'jdbc:mariadb://[host]:[port]/[database]',
+ user: 'root'
+ },
+ {
db: 'H2',
jdbcDriverClass: 'org.h2.Driver',
jdbcUrl: 'jdbc:h2:tcp://[host]/[database]',
@@ -223,7 +274,7 @@ export default ['domainsController', [
];
$scope.selectedPreset = {
- db: 'General',
+ db: 'Generic',
jdbcDriverJar: '',
jdbcDriverClass: '',
jdbcUrl: 'jdbc:[database]',
@@ -266,7 +317,7 @@ export default ['domainsController', [
const oldPreset = _.find(_dbPresets, {jdbcDriverClass: preset.jdbcDriverClass});
if (oldPreset)
- angular.extend(oldPreset, preset);
+ _.assign(oldPreset, preset);
else
_dbPresets.push(preset);
@@ -283,7 +334,7 @@ export default ['domainsController', [
});
if (!result)
- result = {db: 'General', jdbcUrl: 'jdbc:[database]', user: 'admin'};
+ result = {db: 'Generic', jdbcUrl: 'jdbc:[database]', user: 'admin'};
result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
@@ -373,6 +424,7 @@ export default ['domainsController', [
function prepareNewItem(cacheId) {
return {
space: $scope.spaces[0]._id,
+ generatePojo: true,
caches: cacheId && _.find($scope.caches, {value: cacheId}) ? [cacheId] : // eslint-disable-line no-nested-ternary
(_.isEmpty($scope.caches) ? [] : [$scope.caches[0].value]),
queryMetadata: 'Configuration'
@@ -751,20 +803,12 @@ export default ['domainsController', [
importDomainModal.hide();
}
- function _saveDomainModel() {
- if (LegacyUtils.isEmptyString($scope.ui.packageName)) {
- ErrorPopover.show('domainPackageNameInput', 'Package could not be empty');
-
- Focus.move('domainPackageNameInput');
-
- return false;
- }
-
- if (!LegacyUtils.isValidJavaClass('Package', $scope.ui.packageName, false, 'domainPackageNameInput', true)) {
- Focus.move('domainPackageNameInput');
+ function _saveDomainModel(optionsForm) {
+ const generatePojo = $scope.ui.generatePojo;
+ const packageName = $scope.ui.packageName;
+ if (generatePojo && !LegacyUtils.checkFieldValidators({inputForm: optionsForm}))
return false;
- }
const batch = [];
const checkedCaches = [];
@@ -803,7 +847,7 @@ export default ['domainsController', [
containDup = true;
}
- const valType = _toJavaPackage($scope.ui.packageName) + '.' + typeName;
+ const valType = generatePojo ? _toJavaPackage(packageName) + '.' + typeName : tableName;
let _containKey = false;
@@ -852,7 +896,8 @@ export default ['domainsController', [
confirm: false,
skip: false,
space: $scope.spaces[0],
- caches: []
+ caches: [],
+ generatePojo
};
if (LegacyUtils.isDefined(domainFound)) {
@@ -985,7 +1030,7 @@ export default ['domainsController', [
}
}
- $scope.importDomainNext = function() {
+ $scope.importDomainNext = function(form) {
if (!$scope.importDomainNextAvailable())
return;
@@ -1000,7 +1045,7 @@ export default ['domainsController', [
else if (act === 'tables')
_selectOptions();
else if (act === 'options')
- _saveDomainModel();
+ _saveDomainModel(form);
};
$scope.nextTooltipText = function() {
@@ -1101,11 +1146,14 @@ export default ['domainsController', [
Resource.read()
.then(({spaces, clusters, caches, domains}) => {
$scope.spaces = spaces;
+
$scope.clusters = _.map(clusters, (cluster) => ({
label: cluster.name,
value: cluster._id
}));
+
$scope.caches = _mapCaches(caches);
+
$scope.domains = _.sortBy(domains, 'valueType');
_.forEach($scope.clusters, (cluster) => $scope.ui.generatedCachesClusters.push(cluster.value));
@@ -1157,8 +1205,14 @@ export default ['domainsController', [
if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
form.$setPristine();
- else
+ else {
form.$setDirty();
+
+ const general = form.general;
+
+ FormUtils.markPristineInvalidAsDirty(general.keyType);
+ FormUtils.markPristineInvalidAsDirty(general.valueType);
+ }
}, true);
$scope.$watch('ui.activePanels.length', () => {
@@ -1210,7 +1264,7 @@ export default ['domainsController', [
else
$scope.backupItem = emptyDomain;
- $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+ $scope.backupItem = _.merge({}, blank, $scope.backupItem);
if ($scope.ui.inputForm) {
$scope.ui.inputForm.$error = {};
@@ -1252,9 +1306,12 @@ export default ['domainsController', [
const indexes = item.indexes;
if (indexes && indexes.length > 0) {
- if (_.find(indexes, function(index, i) {
+ if (_.find(indexes, function(index, idx) {
if (_.isEmpty(index.fields))
- return !ErrorPopover.show('indexes' + i, 'Index fields are not specified', $scope.ui, 'query');
+ return !ErrorPopover.show('indexes' + idx, 'Index fields are not specified', $scope.ui, 'query');
+
+ if (_.find(index.fields, (field) => !_.find(item.fields, (configuredField) => configuredField.name === field.name)))
+ return !ErrorPopover.show('indexes' + idx, 'Index contains not configured fields', $scope.ui, 'query');
}))
return false;
}
@@ -1332,7 +1389,7 @@ export default ['domainsController', [
});
if (idx >= 0)
- angular.extend($scope.domains[idx], savedMeta);
+ _.assign($scope.domains[idx], savedMeta);
else
$scope.domains.push(savedMeta);
@@ -1503,15 +1560,11 @@ export default ['domainsController', [
});
// Found duplicate by key.
- if (idx >= 0 && idx !== index) {
- if (stopEdit)
- return false;
-
- return ErrorPopover.show(LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!', $scope.ui, 'query');
- }
+ if (idx >= 0 && idx !== index)
+ return !stopEdit && ErrorPopover.show(LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!', $scope.ui, 'query');
}
- if (pairField.classValidation && !LegacyUtils.isValidJavaClass(pairField.msg, pairValue.value, true, LegacyTable.tableFieldId(index, 'Value' + pairField.id), false, $scope.ui, 'query')) {
+ if (pairField.classValidation && !LegacyUtils.isValidJavaClass(pairField.msg, pairValue.value, true, LegacyTable.tableFieldId(index, 'Value' + pairField.id), false, $scope.ui, 'query', stopEdit)) {
if (stopEdit)
return false;
@@ -1560,8 +1613,8 @@ export default ['domainsController', [
let model = item[field.model];
- if (!LegacyUtils.isValidJavaIdentifier(dbFieldTable.msg + ' java name', dbFieldValue.javaFieldName, LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id)))
- return false;
+ if (!LegacyUtils.isValidJavaIdentifier(dbFieldTable.msg + ' java name', dbFieldValue.javaFieldName, LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), $scope.ui, 'store', stopEdit))
+ return stopEdit;
if (LegacyUtils.isDefined(model)) {
let idx = _.findIndex(model, function(dbMeta) {
@@ -1570,7 +1623,7 @@ export default ['domainsController', [
// Found duplicate.
if (idx >= 0 && index !== idx)
- return ErrorPopover.show(LegacyTable.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!', $scope.ui, 'store');
+ return stopEdit || ErrorPopover.show(LegacyTable.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!', $scope.ui, 'store');
idx = _.findIndex(model, function(dbMeta) {
return dbMeta.javaFieldName === dbFieldValue.javaFieldName;
@@ -1578,7 +1631,7 @@ export default ['domainsController', [
// Found duplicate.
if (idx >= 0 && index !== idx)
- return ErrorPopover.show(LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!', $scope.ui, 'store');
+ return stopEdit || ErrorPopover.show(LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!', $scope.ui, 'store');
if (index < 0)
model.push(dbFieldValue);
@@ -1639,7 +1692,7 @@ export default ['domainsController', [
// Found duplicate.
if (idx >= 0 && idx !== curIdx)
- return ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!', $scope.ui, 'query');
+ return !stopEdit && ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!', $scope.ui, 'query');
}
LegacyTable.tableReset();
@@ -1675,10 +1728,8 @@ export default ['domainsController', [
$scope.tableIndexNewItem = function(field, indexIdx) {
if ($scope.tableReset(true)) {
- const index = $scope.backupItem.indexes[indexIdx];
-
LegacyTable.tableState(field, -1, 'table-index-fields');
- LegacyTable.tableFocusInvalidField(-1, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx);
+ LegacyTable.tableFocusInvalidField(-1, 'FieldName' + indexIdx);
field.newFieldName = null;
field.newDirection = true;
@@ -1734,7 +1785,7 @@ export default ['domainsController', [
field.curDirection = indexItem.direction;
field.indexIdx = indexIdx;
- Focus.move('curFieldName' + (index.indexType === 'SORTED' ? 'S' : '') + field.indexIdx + '-' + curIdx);
+ Focus.move('curFieldName' + field.indexIdx + '-' + curIdx);
}
};
@@ -1753,8 +1804,11 @@ export default ['domainsController', [
const idx = _.findIndex(fields, (fld) => fld.name === indexItemValue.name);
// Found duplicate.
- if (idx >= 0 && idx !== curIdx)
- return ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx + (curIdx >= 0 ? '-' : '')), 'Field with such name already exists in index!', $scope.ui, 'query');
+ if (idx >= 0 && idx !== curIdx) {
+ return !stopEdit && ErrorPopover.show(LegacyTable.tableFieldId(curIdx,
+ 'FieldName' + indexIdx + (curIdx >= 0 ? '-' : '')),
+ 'Field with such name already exists in index!', $scope.ui, 'query');
+ }
}
LegacyTable.tableReset();
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/controllers/igfs-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/igfs-controller.js b/modules/web-console/frontend/controllers/igfs-controller.js
index 7617712..e505f1c 100644
--- a/modules/web-console/frontend/controllers/igfs-controller.js
+++ b/modules/web-console/frontend/controllers/igfs-controller.js
@@ -17,7 +17,7 @@
// Controller for IGFS screen.
export default ['igfsController', [
- '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+ '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteLegacyTable', 'IgniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, LegacyTable, Resource, ErrorPopover, FormUtils) {
UnsavedChangesGuard.install($scope);
@@ -231,7 +231,7 @@ export default ['igfsController', [
else
$scope.backupItem = emptyIgfs;
- $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+ $scope.backupItem = _.merge({}, blank, $scope.backupItem);
if ($scope.ui.inputForm) {
$scope.ui.inputForm.$error = {};
@@ -304,7 +304,7 @@ export default ['igfsController', [
});
if (idx >= 0)
- angular.merge($scope.igfss[idx], item);
+ _.assign($scope.igfss[idx], item);
else {
item._id = _id;
$scope.igfss.push(item);