You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2016/09/09 03:26:57 UTC
[29/52] ignite git commit: Web Console beta-3.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/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
new file mode 100644
index 0000000..e520494
--- /dev/null
+++ b/modules/web-console/frontend/controllers/domains-controller.js
@@ -0,0 +1,1790 @@
+/*
+ * 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.
+ */
+
+// 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',
+ function($root, $scope, $http, $state, $filter, $timeout, $modal, LegacyUtils, Messages, Focus, Confirm, ConfirmBatch, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, IgniteAgentMonitor, LegacyTable, Resource, ErrorPopover, FormUtils) {
+ UnsavedChangesGuard.install($scope);
+
+ const emptyDomain = {empty: true};
+
+ let __original_value;
+
+ const blank = {};
+
+ // We need to initialize backupItem with empty object in order to properly used from angular directives.
+ $scope.backupItem = emptyDomain;
+
+ $scope.ui = FormUtils.formUI();
+ $scope.ui.activePanels = [0, 1];
+ $scope.ui.topPanels = [0, 1, 2];
+
+ const IMPORT_DM_NEW_CACHE = 1;
+ const IMPORT_DM_ASSOCIATE_CACHE = 2;
+
+ /**
+ * Convert some name to valid java package name.
+ *
+ * @param name to convert.
+ * @returns {string} Valid java package name.
+ */
+ const _toJavaPackage = (name) => {
+ return name ? name.replace(/[^A-Za-z_0-9/.]+/g, '_') : 'org';
+ };
+
+ const _packageNameUpdate = (event, user) => {
+ if (_.isNil(user))
+ return;
+
+ $scope.ui.packageNameUserInput = _toJavaPackage(user.email.replace('@', '.').split('.').reverse().join('.') + '.model');
+ };
+
+ _packageNameUpdate(null, $root.user);
+
+ $scope.$on('$destroy', $root.$on('user', _packageNameUpdate));
+
+ $scope.ui.builtinKeys = true;
+ $scope.ui.usePrimitives = true;
+ $scope.ui.generateAliases = true;
+ $scope.ui.generatedCachesClusters = [];
+
+ function _mapCaches(caches) {
+ return _.map(caches, (cache) => {
+ return {label: cache.name, value: cache._id, cache};
+ });
+ }
+
+ $scope.contentVisible = function() {
+ const item = $scope.backupItem;
+
+ 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;
+ $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+
+ $scope.tableSave = function(field, index, stopEdit) {
+ if (LegacyTable.tableEditing({model: 'table-index-fields'}, LegacyTable.tableEditedRowIndex())) {
+ if ($scope.tableIndexItemSaveVisible(field, index))
+ return $scope.tableIndexItemSave(field, field.indexIdx, index, stopEdit);
+ }
+ else {
+ switch (field.type) {
+ case 'fields':
+ case 'aliases':
+ if (LegacyTable.tablePairSaveVisible(field, index))
+ return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+ break;
+
+ case 'indexes':
+ if ($scope.tableIndexSaveVisible(field, index))
+ return $scope.tableIndexSave(field, index, stopEdit);
+
+ break;
+
+ case 'table-db-fields':
+ if ($scope.tableDbFieldSaveVisible(field, index))
+ return $scope.tableDbFieldSave(field, index, stopEdit);
+
+ break;
+
+ default:
+ }
+ }
+
+ return true;
+ };
+
+ $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.tableNewItem = function(field) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableNewItem(field);
+ };
+
+ $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.tableRemove = function(item, field, index) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableRemove(item, field, index);
+ };
+
+ $scope.tablePairSave = LegacyTable.tablePairSave;
+ $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+
+ $scope.queryFieldsTbl = {
+ type: 'fields',
+ model: 'fields',
+ focusId: 'QryField',
+ ui: 'table-pair',
+ keyName: 'name',
+ valueName: 'className',
+ save: $scope.tableSave
+ };
+
+ $scope.aliasesTbl = {
+ type: 'aliases',
+ model: 'aliases',
+ focusId: 'Alias',
+ ui: 'table-pair',
+ keyName: 'field',
+ valueName: 'alias',
+ save: $scope.tableSave
+ };
+
+ $scope.queryMetadataVariants = LegacyUtils.mkOptions(['Annotations', 'Configuration']);
+
+ 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';
+ const INFO_SELECT_OPTIONS = 'Select import domain model options';
+ const LOADING_JDBC_DRIVERS = {text: 'Loading JDBC drivers...'};
+ const LOADING_SCHEMAS = {text: 'Loading schemas...'};
+ const LOADING_TABLES = {text: 'Loading tables...'};
+ const SAVING_DOMAINS = {text: 'Saving domain model...'};
+
+ $scope.ui.invalidKeyFieldsTooltip = 'Found key types without configured key fields<br/>' +
+ 'It may be a result of import tables from database without primary keys<br/>' +
+ 'Key field for such key types should be configured manually';
+
+ $scope.indexType = LegacyUtils.mkOptions(['SORTED', 'FULLTEXT', 'GEOSPATIAL']);
+
+ const _dbPresets = [
+ {
+ db: 'Oracle',
+ jdbcDriverClass: 'oracle.jdbc.OracleDriver',
+ jdbcUrl: 'jdbc:oracle:thin:@[host]:[port]:[database]',
+ user: 'system'
+ },
+ {
+ db: 'DB2',
+ jdbcDriverClass: 'com.ibm.db2.jcc.DB2Driver',
+ jdbcUrl: 'jdbc:db2://[host]:[port]/[database]',
+ user: 'db2admin'
+ },
+ {
+ db: 'SQLServer',
+ jdbcDriverClass: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
+ jdbcUrl: 'jdbc:sqlserver://[host]:[port][;databaseName=database]'
+ },
+ {
+ db: 'PostgreSQL',
+ jdbcDriverClass: 'org.postgresql.Driver',
+ jdbcUrl: 'jdbc:postgresql://[host]:[port]/[database]',
+ user: 'sa'
+ },
+ {
+ db: 'MySQL',
+ jdbcDriverClass: 'com.mysql.jdbc.Driver',
+ jdbcUrl: 'jdbc:mysql://[host]:[port]/[database]',
+ user: 'root'
+ },
+ {
+ db: 'H2',
+ jdbcDriverClass: 'org.h2.Driver',
+ jdbcUrl: 'jdbc:h2:tcp://[host]/[database]',
+ user: 'sa'
+ }
+ ];
+
+ $scope.selectedPreset = {
+ db: 'General',
+ jdbcDriverJar: '',
+ jdbcDriverClass: '',
+ jdbcUrl: 'jdbc:[database]',
+ user: 'sa',
+ password: '',
+ tablesOnly: true
+ };
+
+ $scope.demoConnection = {
+ db: 'H2',
+ jdbcDriverClass: 'org.h2.Driver',
+ jdbcUrl: 'jdbc:h2:mem:demo-db',
+ user: 'sa',
+ password: '',
+ tablesOnly: true
+ };
+
+ function _loadPresets() {
+ try {
+ const restoredPresets = JSON.parse(localStorage.dbPresets);
+
+ _.forEach(restoredPresets, (restoredPreset) => {
+ const preset = _.find(_dbPresets, {jdbcDriverClass: restoredPreset.jdbcDriverClass});
+
+ if (preset) {
+ preset.jdbcUrl = restoredPreset.jdbcUrl;
+ preset.user = restoredPreset.user;
+ }
+ });
+ }
+ catch (ignore) {
+ // No-op.
+ }
+ }
+
+ _loadPresets();
+
+ function _savePreset(preset) {
+ try {
+ const oldPreset = _.find(_dbPresets, {jdbcDriverClass: preset.jdbcDriverClass});
+
+ if (oldPreset)
+ angular.extend(oldPreset, preset);
+ else
+ _dbPresets.push(preset);
+
+ localStorage.dbPresets = JSON.stringify(_dbPresets);
+ }
+ catch (err) {
+ Messages.showError(err);
+ }
+ }
+
+ function _findPreset(selectedJdbcJar) {
+ let result = _.find(_dbPresets, function(preset) {
+ return preset.jdbcDriverClass === selectedJdbcJar.jdbcDriverClass;
+ });
+
+ if (!result)
+ result = {db: 'General', jdbcUrl: 'jdbc:[database]', user: 'admin'};
+
+ result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
+ result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
+
+ return result;
+ }
+
+ $scope.$watch('ui.selectedJdbcDriverJar', function(val) {
+ if (val && !$scope.importDomain.demo) {
+ const foundPreset = _findPreset(val);
+
+ const selectedPreset = $scope.selectedPreset;
+
+ selectedPreset.db = foundPreset.db;
+ selectedPreset.jdbcDriverJar = foundPreset.jdbcDriverJar;
+ selectedPreset.jdbcDriverClass = foundPreset.jdbcDriverClass;
+ selectedPreset.jdbcUrl = foundPreset.jdbcUrl;
+ selectedPreset.user = foundPreset.user;
+ }
+ }, true);
+
+ $scope.ui.showValid = true;
+
+ $scope.supportedJdbcTypes = LegacyUtils.mkOptions(LegacyUtils.SUPPORTED_JDBC_TYPES);
+
+ $scope.supportedJavaTypes = LegacyUtils.mkOptions(LegacyUtils.javaBuiltInTypes);
+
+ $scope.sortDirections = [
+ {value: true, label: 'ASC'},
+ {value: false, label: 'DESC'}
+ ];
+
+ $scope.domains = [];
+
+ $scope.isJavaBuiltInClass = function() {
+ const item = $scope.backupItem;
+
+ if (item && item.keyType)
+ return LegacyUtils.isJavaBuiltInClass(item.keyType);
+
+ return false;
+ };
+
+ $scope.selectAllSchemas = function() {
+ const allSelected = $scope.importDomain.allSchemasSelected;
+
+ _.forEach($scope.importDomain.displayedSchemas, (schema) => {
+ schema.use = allSelected;
+ });
+ };
+
+ $scope.selectSchema = function() {
+ if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedSchemas))
+ $scope.importDomain.allSchemasSelected = $scope.importDomain.displayedSchemas.length > 0 && _.every($scope.importDomain.displayedSchemas, 'use', true);
+ };
+
+ $scope.selectAllTables = function() {
+ const allSelected = $scope.importDomain.allTablesSelected;
+
+ _.forEach($scope.importDomain.displayedTables, function(table) {
+ table.use = allSelected;
+ });
+ };
+
+ $scope.selectTable = function() {
+ if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedTables))
+ $scope.importDomain.allTablesSelected = $scope.importDomain.displayedTables.length > 0 && _.every($scope.importDomain.displayedTables, 'use', true);
+ };
+
+ $scope.$watch('importDomain.displayedSchemas', $scope.selectSchema);
+
+ $scope.$watch('importDomain.displayedTables', $scope.selectTable);
+
+ // Pre-fetch modal dialogs.
+ const importDomainModal = $modal({scope: $scope, templateUrl: '/configuration/domains-import.html', show: false});
+
+ const hideImportDomain = importDomainModal.hide;
+
+ importDomainModal.hide = function() {
+ IgniteAgentMonitor.stopWatch();
+
+ hideImportDomain();
+ };
+
+ $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+ function prepareNewItem(cacheId) {
+ return {
+ space: $scope.spaces[0]._id,
+ caches: cacheId && _.find($scope.caches, {value: cacheId}) ? [cacheId] : // eslint-disable-line no-nested-ternary
+ (_.isEmpty($scope.caches) ? [] : [$scope.caches[0].value]),
+ queryMetadata: 'Configuration'
+ };
+ }
+
+ /**
+ * Show import domain models modal.
+ */
+ $scope.showImportDomainModal = function() {
+ LegacyTable.tableReset();
+
+ FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, function() {
+ if ($scope.ui.inputForm.$dirty)
+ $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+
+ const demo = $root.IgniteDemoMode;
+
+ $scope.importDomain = {
+ demo,
+ action: demo ? 'connect' : 'drivers',
+ jdbcDriversNotFound: demo,
+ schemas: [],
+ allSchemasSelected: false,
+ tables: [],
+ allTablesSelected: false,
+ button: 'Next',
+ info: ''
+ };
+
+ $scope.importDomain.loadingOptions = LOADING_JDBC_DRIVERS;
+
+ IgniteAgentMonitor.startWatch({text: 'Back to Domain models', goal: 'import domain model from database'})
+ .then(importDomainModal.$promise)
+ .then(importDomainModal.show)
+ .then(() => {
+ if (demo) {
+ $scope.ui.packageNameUserInput = $scope.ui.packageName;
+ $scope.ui.packageName = 'model';
+
+ return;
+ }
+
+ // Get available JDBC drivers via agent.
+ Loading.start('importDomainFromDb');
+
+ $scope.jdbcDriverJars = [];
+ $scope.ui.selectedJdbcDriverJar = {};
+
+ return IgniteAgentMonitor.drivers()
+ .then((drivers) => {
+ $scope.ui.packageName = $scope.ui.packageNameUserInput;
+
+ if (drivers && drivers.length > 0) {
+ drivers = _.sortBy(drivers, 'jdbcDriverJar');
+
+ _.forEach(drivers, (drv) => {
+ $scope.jdbcDriverJars.push({
+ label: drv.jdbcDriverJar,
+ value: {
+ jdbcDriverJar: drv.jdbcDriverJar,
+ jdbcDriverClass: drv.jdbcDriverCls
+ }
+ });
+ });
+
+ $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
+
+ FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, () => {
+ $scope.importDomain.action = 'connect';
+ $scope.importDomain.tables = [];
+
+ Focus.move('jdbcUrl');
+ });
+ }
+ else {
+ $scope.importDomain.jdbcDriversNotFound = true;
+ $scope.importDomain.button = 'Cancel';
+ }
+ })
+ .then(() => {
+ $scope.importDomain.info = INFO_CONNECT_TO_DB;
+
+ Loading.finish('importDomainFromDb');
+ });
+ });
+ });
+ };
+
+ /**
+ * Load list of database schemas.
+ */
+ function _loadSchemas() {
+ IgniteAgentMonitor.awaitAgent()
+ .then(function() {
+ $scope.importDomain.loadingOptions = LOADING_SCHEMAS;
+ Loading.start('importDomainFromDb');
+
+ if ($root.IgniteDemoMode)
+ return IgniteAgentMonitor.schemas($scope.demoConnection);
+
+ const preset = $scope.selectedPreset;
+
+ _savePreset(preset);
+
+ return IgniteAgentMonitor.schemas(preset);
+ })
+ .then(function(schemas) {
+ $scope.importDomain.schemas = _.map(schemas, function(schema) {
+ return {use: true, name: schema};
+ });
+
+ $scope.importDomain.action = 'schemas';
+
+ if ($scope.importDomain.schemas.length === 0)
+ $scope.importDomainNext();
+
+ $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+ })
+ .catch(Messages.showError)
+ .then(() => Loading.finish('importDomainFromDb'));
+ }
+
+ const DFLT_PARTITIONED_CACHE = {
+ label: 'PARTITIONED',
+ value: -1,
+ cache: {
+ name: 'PARTITIONED',
+ cacheMode: 'PARTITIONED',
+ atomicityMode: 'ATOMIC',
+ readThrough: true,
+ writeThrough: true
+ }
+ };
+
+ const DFLT_REPLICATED_CACHE = {
+ label: 'REPLICATED',
+ value: -2,
+ cache: {
+ name: 'REPLICATED',
+ cacheMode: 'REPLICATED',
+ atomicityMode: 'ATOMIC',
+ readThrough: true,
+ writeThrough: true
+ }
+ };
+
+ let _importCachesOrTemplates = [];
+
+ $scope.tableActionView = function(tbl) {
+ const cacheName = _.find(_importCachesOrTemplates, {value: tbl.cacheOrTemplate}).label;
+
+ if (tbl.action === IMPORT_DM_NEW_CACHE)
+ return 'Create ' + tbl.generatedCacheName + ' (' + cacheName + ')';
+
+ return 'Associate with ' + cacheName;
+ };
+
+ function toJavaClassName(name) {
+ const len = name.length;
+
+ let buf = '';
+
+ let capitalizeNext = true;
+
+ for (let i = 0; i < len; i++) {
+ const ch = name.charAt(i);
+
+ if (ch === ' ' || ch === '_')
+ capitalizeNext = true;
+ else if (capitalizeNext) {
+ buf += ch.toLocaleUpperCase();
+
+ capitalizeNext = false;
+ }
+ else
+ buf += ch.toLocaleLowerCase();
+ }
+
+ return buf;
+ }
+
+ function toJavaName(dbName) {
+ const javaName = toJavaClassName(dbName);
+
+ return javaName.charAt(0).toLocaleLowerCase() + javaName.slice(1);
+ }
+
+ function _fillCommonCachesOrTemplates(item) {
+ return function(action) {
+ if (item.cachesOrTemplates)
+ item.cachesOrTemplates.length = 0;
+ else
+ item.cachesOrTemplates = [];
+
+ if (action === IMPORT_DM_NEW_CACHE) {
+ item.cachesOrTemplates.push(DFLT_PARTITIONED_CACHE);
+ item.cachesOrTemplates.push(DFLT_REPLICATED_CACHE);
+ }
+
+ if (!_.isEmpty($scope.caches)) {
+ if (item.cachesOrTemplates.length > 0)
+ item.cachesOrTemplates.push(null);
+
+ _.forEach($scope.caches, function(cache) {
+ item.cachesOrTemplates.push(cache);
+ });
+ }
+
+ if (!_.find(item.cachesOrTemplates, {value: item.cacheOrTemplate}))
+ item.cacheOrTemplate = item.cachesOrTemplates[0].value;
+ };
+ }
+ /**
+ * Load list of database tables.
+ */
+ function _loadTables() {
+ IgniteAgentMonitor.awaitAgent()
+ .then(function() {
+ $scope.importDomain.loadingOptions = LOADING_TABLES;
+ Loading.start('importDomainFromDb');
+
+ $scope.importDomain.allTablesSelected = false;
+
+ const preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
+
+ preset.schemas = [];
+
+ _.forEach($scope.importDomain.schemas, function(schema) {
+ if (schema.use)
+ preset.schemas.push(schema.name);
+ });
+
+ return IgniteAgentMonitor.tables(preset);
+ })
+ .then(function(tables) {
+ _importCachesOrTemplates = [DFLT_PARTITIONED_CACHE, DFLT_REPLICATED_CACHE].concat($scope.caches);
+
+ _fillCommonCachesOrTemplates($scope.importCommon)($scope.importCommon.action);
+
+ _.forEach(tables, function(tbl, idx) {
+ tbl.id = idx;
+ tbl.action = IMPORT_DM_NEW_CACHE;
+ tbl.generatedCacheName = toJavaClassName(tbl.tbl) + 'Cache';
+ tbl.cacheOrTemplate = DFLT_PARTITIONED_CACHE.value;
+ tbl.label = tbl.schema + '.' + tbl.tbl;
+ tbl.edit = false;
+ tbl.use = LegacyUtils.isDefined(_.find(tbl.cols, function(col) {
+ return col.key;
+ }));
+ });
+
+ $scope.importDomain.action = 'tables';
+ $scope.importDomain.tables = tables;
+ $scope.importDomain.info = INFO_SELECT_TABLES;
+ })
+ .catch(Messages.showError)
+ .then(() => Loading.finish('importDomainFromDb'));
+ }
+
+ $scope.applyDefaults = function() {
+ _.forEach($scope.importDomain.displayedTables, function(table) {
+ table.edit = false;
+ table.action = $scope.importCommon.action;
+ table.cacheOrTemplate = $scope.importCommon.cacheOrTemplate;
+ });
+ };
+
+ $scope._curDbTable = null;
+
+ $scope.startEditDbTableCache = function(tbl) {
+ if ($scope._curDbTable) {
+ $scope._curDbTable.edit = false;
+
+ if ($scope._curDbTable.actionWatch) {
+ $scope._curDbTable.actionWatch();
+
+ $scope._curDbTable.actionWatch = null;
+ }
+ }
+
+ $scope._curDbTable = tbl;
+
+ const _fillFn = _fillCommonCachesOrTemplates($scope._curDbTable);
+
+ _fillFn($scope._curDbTable.action);
+
+ $scope._curDbTable.actionWatch = $scope.$watch('_curDbTable.action', _fillFn, true);
+
+ $scope._curDbTable.edit = true;
+ };
+
+ /**
+ * Show page with import domain models options.
+ */
+ function _selectOptions() {
+ $scope.importDomain.action = 'options';
+ $scope.importDomain.button = 'Save';
+ $scope.importDomain.info = INFO_SELECT_OPTIONS;
+
+ Focus.move('domainPackageName');
+ }
+
+ function _saveBatch(batch) {
+ if (batch && batch.length > 0) {
+ $scope.importDomain.loadingOptions = SAVING_DOMAINS;
+ Loading.start('importDomainFromDb');
+
+ $http.post('/api/v1/configuration/domains/save/batch', batch)
+ .success(function(savedBatch) {
+ let lastItem;
+ const newItems = [];
+
+ _.forEach(_mapCaches(savedBatch.generatedCaches), function(cache) {
+ $scope.caches.push(cache);
+ });
+
+ _.forEach(savedBatch.savedDomains, function(savedItem) {
+ const idx = _.findIndex($scope.domains, function(domain) {
+ return domain._id === savedItem._id;
+ });
+
+ if (idx >= 0)
+ $scope.domains[idx] = savedItem;
+ else
+ newItems.push(savedItem);
+
+ lastItem = savedItem;
+ });
+
+ _.forEach(newItems, function(item) {
+ $scope.domains.push(item);
+ });
+
+ if (!lastItem && $scope.domains.length > 0)
+ lastItem = $scope.domains[0];
+
+ $scope.selectItem(lastItem);
+
+ Messages.showInfo('Domain models imported from database.');
+
+ $scope.ui.activePanels = [0, 1, 2];
+
+ $scope.ui.showValid = true;
+ })
+ .error(Messages.showError)
+ .finally(() => {
+ Loading.finish('importDomainFromDb');
+
+ importDomainModal.hide();
+ });
+ }
+ else
+ 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');
+
+ return false;
+ }
+
+ const batch = [];
+ const checkedCaches = [];
+
+ let containKey = true;
+ let containDup = false;
+
+ function queryField(name, jdbcType) {
+ return {name: toJavaName(name), className: jdbcType.javaType};
+ }
+
+ function dbField(name, jdbcType, nullable) {
+ return {
+ jdbcType,
+ databaseFieldName: name,
+ databaseFieldType: jdbcType.dbName,
+ javaFieldName: toJavaName(name),
+ javaFieldType: nullable ? jdbcType.javaType :
+ ($scope.ui.usePrimitives && jdbcType.primitiveType ? jdbcType.primitiveType : jdbcType.javaType)
+ };
+ }
+
+ _.forEach($scope.importDomain.tables, function(table, curIx) {
+ if (table.use) {
+ const qryFields = [];
+ const indexes = [];
+ const keyFields = [];
+ const valFields = [];
+ const aliases = [];
+
+ const tableName = table.tbl;
+ let typeName = toJavaClassName(tableName);
+
+ if (_.find($scope.importDomain.tables,
+ (tbl, ix) => tbl.use && ix !== curIx && tableName === tbl.tbl)) {
+ typeName = typeName + '_' + toJavaClassName(table.schema);
+
+ containDup = true;
+ }
+
+ const valType = _toJavaPackage($scope.ui.packageName) + '.' + typeName;
+
+ let _containKey = false;
+
+ _.forEach(table.cols, function(col) {
+ const colName = col.name;
+ const jdbcType = LegacyUtils.findJdbcType(col.type);
+ const nullable = col.nullable;
+
+ qryFields.push(queryField(colName, jdbcType));
+
+ const fld = dbField(colName, jdbcType, nullable);
+
+ if ($scope.ui.generateAliases && !_.find(aliases, {field: fld.javaFieldName}) &&
+ fld.javaFieldName.toUpperCase() !== fld.databaseFieldName.toUpperCase())
+ aliases.push({field: fld.javaFieldName, alias: fld.databaseFieldName});
+
+ if (col.key) {
+ keyFields.push(fld);
+
+ _containKey = true;
+ }
+ else
+ valFields.push(fld);
+ });
+
+ containKey &= _containKey;
+
+ if (table.idxs) {
+ _.forEach(table.idxs, function(idx) {
+ const fields = Object.keys(idx.fields);
+
+ indexes.push({
+ name: idx.name, indexType: 'SORTED', fields: _.map(fields, function(fieldName) {
+ return {
+ name: toJavaName(fieldName),
+ direction: idx.fields[fieldName]
+ };
+ })
+ });
+ });
+ }
+
+ const domainFound = _.find($scope.domains, function(domain) {
+ return domain.valueType === valType;
+ });
+
+ const newDomain = {
+ confirm: false,
+ skip: false,
+ space: $scope.spaces[0],
+ caches: []
+ };
+
+ if (LegacyUtils.isDefined(domainFound)) {
+ newDomain._id = domainFound._id;
+ newDomain.caches = domainFound.caches;
+ newDomain.confirm = true;
+ }
+
+ newDomain.keyType = valType + 'Key';
+ newDomain.valueType = valType;
+ newDomain.queryMetadata = 'Configuration';
+ newDomain.databaseSchema = table.schema;
+ newDomain.databaseTable = tableName;
+ newDomain.fields = qryFields;
+ newDomain.indexes = indexes;
+ newDomain.keyFields = keyFields;
+ newDomain.aliases = aliases;
+ newDomain.valueFields = valFields;
+
+ // If value fields not found - copy key fields.
+ if (_.isEmpty(valFields))
+ newDomain.valueFields = keyFields.slice();
+
+ // Use Java built-in type for key.
+ if ($scope.ui.builtinKeys && newDomain.keyFields.length === 1) {
+ const keyField = newDomain.keyFields[0];
+
+ newDomain.keyType = keyField.jdbcType.javaType;
+
+ // Exclude key column from query fields and indexes.
+ newDomain.fields = _.filter(newDomain.fields, function(field) {
+ return field.name !== keyField.javaFieldName;
+ });
+
+ _.forEach(newDomain.indexes, function(index) {
+ index.fields = _.filter(index.fields, function(field) {
+ return field.name !== keyField.javaFieldName;
+ });
+ });
+
+ newDomain.indexes = _.filter(newDomain.indexes, (index) => !_.isEmpty(index.fields));
+ }
+
+ // Prepare caches for generation.
+ if (table.action === IMPORT_DM_NEW_CACHE) {
+ const template = _.find(_importCachesOrTemplates, {value: table.cacheOrTemplate});
+
+ const newCache = angular.copy(template.cache);
+
+ newDomain.newCache = newCache;
+
+ delete newCache._id;
+ newCache.name = typeName + 'Cache';
+ newCache.clusters = $scope.ui.generatedCachesClusters;
+
+ // POJO store factory is not defined in template.
+ if (!newCache.cacheStoreFactory || newCache.cacheStoreFactory.kind !== 'CacheJdbcPojoStoreFactory') {
+ const dialect = $scope.importDomain.demo ? 'H2' : $scope.selectedPreset.db;
+
+ newCache.cacheStoreFactory = {
+ kind: 'CacheJdbcPojoStoreFactory',
+ CacheJdbcPojoStoreFactory: {dataSourceBean: 'ds' + dialect, dialect},
+ CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
+ };
+ }
+
+ if (!newCache.readThrough && !newCache.writeThrough) {
+ newCache.readThrough = true;
+ newCache.writeThrough = true;
+ }
+ }
+ else {
+ const cacheId = table.cacheOrTemplate;
+
+ newDomain.caches = [cacheId];
+
+ if (!_.includes(checkedCaches, cacheId)) {
+ const cache = _.find($scope.caches, {value: cacheId}).cache;
+
+ const change = LegacyUtils.autoCacheStoreConfiguration(cache, [newDomain]);
+
+ if (change)
+ newDomain.cacheStoreChanges = [{cacheId, change}];
+
+ checkedCaches.push(cacheId);
+ }
+ }
+
+ batch.push(newDomain);
+ }
+ });
+
+ /**
+ * Generate message to show on confirm dialog.
+ *
+ * @param meta Object to confirm.
+ * @returns {string} Generated message.
+ */
+ function overwriteMessage(meta) {
+ return '<span>' +
+ 'Domain model with name "' + meta.databaseTable + '" already exist.<br/><br/>' +
+ 'Are you sure you want to overwrite it?' +
+ '</span>';
+ }
+
+ const itemsToConfirm = _.filter(batch, (item) => item.confirm);
+
+ function checkOverwrite() {
+ if (itemsToConfirm.length > 0) {
+ ConfirmBatch.confirm(overwriteMessage, itemsToConfirm)
+ .then(() => _saveBatch(_.filter(batch, (item) => !item.skip)))
+ .catch(() => Messages.showError('Importing of domain models interrupted by user.'));
+ }
+ else
+ _saveBatch(batch);
+ }
+
+ function checkDuplicate() {
+ if (containDup) {
+ Confirm.confirm('Some tables have the same name.<br/>' +
+ 'Name of types for that tables will contain schema name too.')
+ .then(() => checkOverwrite());
+ }
+ else
+ checkOverwrite();
+ }
+
+ if (containKey)
+ checkDuplicate();
+ else {
+ Confirm.confirm('Some tables have no primary key.<br/>' +
+ 'You will need to configure key type and key fields for such tables after import complete.')
+ .then(() => checkDuplicate());
+ }
+ }
+
+ $scope.importDomainNext = function() {
+ if (!$scope.importDomainNextAvailable())
+ return;
+
+ const act = $scope.importDomain.action;
+
+ if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+ importDomainModal.hide();
+ else if (act === 'connect')
+ _loadSchemas();
+ else if (act === 'schemas')
+ _loadTables();
+ else if (act === 'tables')
+ _selectOptions();
+ else if (act === 'options')
+ _saveDomainModel();
+ };
+
+ $scope.nextTooltipText = function() {
+ const importDomainNextAvailable = $scope.importDomainNextAvailable();
+
+ const act = $scope.importDomain.action;
+
+ if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+ return 'Resolve issue with JDBC drivers<br>Close this dialog and try again';
+
+ if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcDriverClass))
+ return 'Input valid JDBC driver class name';
+
+ if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcUrl))
+ return 'Input valid JDBC URL';
+
+ if (act === 'connect' || act === 'drivers')
+ return 'Click to load list of schemas from database';
+
+ if (act === 'schemas')
+ return importDomainNextAvailable ? 'Click to load list of tables from database' : 'Select schemas to continue';
+
+ if (act === 'tables')
+ return importDomainNextAvailable ? 'Click to show import options' : 'Select tables to continue';
+
+ if (act === 'options')
+ return 'Click to import domain model for selected tables';
+
+ return 'Click to continue';
+ };
+
+ $scope.prevTooltipText = function() {
+ const act = $scope.importDomain.action;
+
+ if (act === 'schemas')
+ return $scope.importDomain.demo ? 'Click to return on demo description step' : 'Click to return on connection configuration step';
+
+ if (act === 'tables')
+ return 'Click to return on schemas selection step';
+
+ if (act === 'options')
+ return 'Click to return on tables selection step';
+ };
+
+ $scope.importDomainNextAvailable = function() {
+ switch ($scope.importDomain.action) {
+ case 'connect':
+ return !_.isNil($scope.selectedPreset.jdbcDriverClass) && !_.isNil($scope.selectedPreset.jdbcUrl);
+
+ case 'schemas':
+ return _.isEmpty($scope.importDomain.schemas) || _.find($scope.importDomain.schemas, {use: true});
+
+ case 'tables':
+ return _.find($scope.importDomain.tables, {use: true});
+
+ default:
+ return true;
+ }
+ };
+
+ $scope.importDomainPrev = function() {
+ $scope.importDomain.button = 'Next';
+
+ if ($scope.importDomain.action === 'options') {
+ $scope.importDomain.action = 'tables';
+ $scope.importDomain.info = INFO_SELECT_TABLES;
+ }
+ else if ($scope.importDomain.action === 'tables' && $scope.importDomain.schemas.length > 0) {
+ $scope.importDomain.action = 'schemas';
+ $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+ }
+ else {
+ $scope.importDomain.action = 'connect';
+ $scope.importDomain.info = INFO_CONNECT_TO_DB;
+ }
+ };
+
+ $scope.domainModelTitle = function() {
+ return $scope.ui.showValid ? 'Domain model types:' : 'Domain model types without key fields:';
+ };
+
+ function selectFirstItem() {
+ if ($scope.domains.length > 0)
+ $scope.selectItem($scope.domains[0]);
+ }
+
+ $scope.importActions = [{
+ label: 'Create new cache by template',
+ shortLabel: 'Create',
+ value: IMPORT_DM_NEW_CACHE
+ }];
+
+ $scope.importCommon = {};
+
+ // When landing on the page, get domain models and show them.
+ Loading.start('loadingDomainModelsScreen');
+
+ 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));
+
+ if (!_.isEmpty($scope.caches)) {
+ $scope.importActions.push({
+ label: 'Associate with existing cache',
+ shortLabel: 'Associate',
+ value: IMPORT_DM_ASSOCIATE_CACHE
+ });
+ }
+
+ $scope.$watch('importCommon.action', _fillCommonCachesOrTemplates($scope.importCommon), true);
+
+ $scope.importCommon.action = IMPORT_DM_NEW_CACHE;
+
+ if ($state.params.linkId)
+ $scope.createItem($state.params.linkId);
+ else {
+ const lastSelectedDomain = angular.fromJson(sessionStorage.lastSelectedDomain);
+
+ if (lastSelectedDomain) {
+ const idx = _.findIndex($scope.domains, function(domain) {
+ return domain._id === lastSelectedDomain;
+ });
+
+ if (idx >= 0)
+ $scope.selectItem($scope.domains[idx]);
+ else {
+ sessionStorage.removeItem('lastSelectedDomain');
+
+ selectFirstItem();
+ }
+ }
+ else
+ selectFirstItem();
+ }
+
+ $scope.$watch('ui.inputForm.$valid', function(valid) {
+ if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+ $scope.ui.inputForm.$dirty = false;
+ });
+
+ $scope.$watch('backupItem', function(val) {
+ if (!$scope.ui.inputForm)
+ return;
+
+ const form = $scope.ui.inputForm;
+
+ if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+ form.$setPristine();
+ else
+ form.$setDirty();
+ }, true);
+
+ $scope.$watch('ui.activePanels.length', () => {
+ ErrorPopover.hide();
+ });
+ })
+ .catch(Messages.showError)
+ .then(() => {
+ $scope.ui.ready = true;
+ $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+ Loading.finish('loadingDomainModelsScreen');
+ });
+
+ const clearFormDefaults = (ngFormCtrl) => {
+ if (!ngFormCtrl)
+ return;
+
+ ngFormCtrl.$defaults = {};
+
+ _.forOwn(ngFormCtrl, (value, key) => {
+ if (value && key !== '$$parentForm' && value.constructor.name === 'FormController')
+ clearFormDefaults(value);
+ });
+ };
+
+ $scope.selectItem = function(item, backup) {
+ function selectItem() {
+ clearFormDefaults($scope.ui.inputForm);
+
+ LegacyTable.tableReset();
+
+ $scope.selectedItem = item;
+
+ try {
+ if (item && item._id)
+ sessionStorage.lastSelectedDomain = angular.toJson(item._id);
+ else
+ sessionStorage.removeItem('lastSelectedDomain');
+ }
+ catch (ignored) {
+ // Ignore possible errors when read from storage.
+ }
+
+ if (backup)
+ $scope.backupItem = backup;
+ else if (item)
+ $scope.backupItem = angular.copy(item);
+ else
+ $scope.backupItem = emptyDomain;
+
+ $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+ if ($scope.ui.inputForm) {
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ }
+
+ __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+ if (LegacyUtils.isDefined($scope.backupItem) && !LegacyUtils.isDefined($scope.backupItem.queryMetadata))
+ $scope.backupItem.queryMetadata = 'Configuration';
+
+ if (LegacyUtils.isDefined($scope.selectedItem) && !LegacyUtils.isDefined($scope.selectedItem.queryMetadata))
+ $scope.selectedItem.queryMetadata = 'Configuration';
+
+ if (LegacyUtils.getQueryVariable('new'))
+ $state.go('base.configuration.domains');
+ }
+
+ FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+ };
+
+ // Add new domain model.
+ $scope.createItem = function(cacheId) {
+ if ($scope.tableReset(true)) {
+ $timeout(() => {
+ FormUtils.ensureActivePanel($scope.ui, 'query');
+ FormUtils.ensureActivePanel($scope.ui, 'general', 'keyTypeInput');
+ });
+
+ $scope.selectItem(null, prepareNewItem(cacheId));
+ }
+ };
+
+ function checkQueryConfiguration(item) {
+ if (item.queryMetadata === 'Configuration' && LegacyUtils.domainForQueryConfigured(item)) {
+ if (_.isEmpty(item.fields))
+ return ErrorPopover.show('queryFields', 'Query fields should not be empty', $scope.ui, 'query');
+
+ const indexes = item.indexes;
+
+ if (indexes && indexes.length > 0) {
+ if (_.find(indexes, function(index, i) {
+ if (_.isEmpty(index.fields))
+ return !ErrorPopover.show('indexes' + i, 'Index fields are not specified', $scope.ui, 'query');
+ }))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function checkStoreConfiguration(item) {
+ if (LegacyUtils.domainForStoreConfigured(item)) {
+ if (LegacyUtils.isEmptyString(item.databaseSchema))
+ return ErrorPopover.show('databaseSchemaInput', 'Database schema should not be empty', $scope.ui, 'store');
+
+ if (LegacyUtils.isEmptyString(item.databaseTable))
+ return ErrorPopover.show('databaseTableInput', 'Database table should not be empty', $scope.ui, 'store');
+
+ if (_.isEmpty(item.keyFields))
+ return ErrorPopover.show('keyFields', 'Key fields are not specified', $scope.ui, 'store');
+
+ if (LegacyUtils.isJavaBuiltInClass(item.keyType) && item.keyFields.length !== 1)
+ return ErrorPopover.show('keyFields', 'Only one field should be specified in case when key type is a Java built-in type', $scope.ui, 'store');
+
+ if (_.isEmpty(item.valueFields))
+ return ErrorPopover.show('valueFields', 'Value fields are not specified', $scope.ui, 'store');
+ }
+
+ return true;
+ }
+
+ // Check domain model logical consistency.
+ function validate(item) {
+ if (!LegacyUtils.checkFieldValidators($scope.ui))
+ return false;
+
+ if (!checkQueryConfiguration(item))
+ return false;
+
+ if (!checkStoreConfiguration(item))
+ return false;
+
+ if (!LegacyUtils.domainForStoreConfigured(item) && !LegacyUtils.domainForQueryConfigured(item) && item.queryMetadata === 'Configuration')
+ return ErrorPopover.show('query-title', 'SQL query domain model should be configured', $scope.ui, 'query');
+
+ return true;
+ }
+
+ function _checkShowValidPresentation() {
+ if (!$scope.ui.showValid) {
+ const validFilter = $filter('domainsValidation');
+
+ $scope.ui.showValid = validFilter($scope.domains, false, true).length === 0;
+ }
+ }
+
+ // Save domain models into database.
+ function save(item) {
+ const qry = LegacyUtils.domainForQueryConfigured(item);
+ const str = LegacyUtils.domainForStoreConfigured(item);
+
+ item.kind = 'query';
+
+ if (qry && str)
+ item.kind = 'both';
+ else if (str)
+ item.kind = 'store';
+
+ $http.post('/api/v1/configuration/domains/save', item)
+ .success(function(res) {
+ $scope.ui.inputForm.$setPristine();
+
+ const savedMeta = res.savedDomains[0];
+
+ const idx = _.findIndex($scope.domains, function(domain) {
+ return domain._id === savedMeta._id;
+ });
+
+ if (idx >= 0)
+ angular.extend($scope.domains[idx], savedMeta);
+ else
+ $scope.domains.push(savedMeta);
+
+ _.forEach($scope.caches, (cache) => {
+ if (_.includes(item.caches, cache.value))
+ cache.cache.domains = _.union(cache.cache.domains, [savedMeta._id]);
+ else
+ _.remove(cache.cache.domains, (id) => id === savedMeta._id);
+ });
+
+ $scope.selectItem(savedMeta);
+
+ Messages.showInfo('Domain model "' + item.valueType + '" saved.');
+
+ _checkShowValidPresentation();
+ })
+ .error(Messages.showError);
+ }
+
+ // Save domain model.
+ $scope.saveItem = function() {
+ if ($scope.tableReset(true)) {
+ const item = $scope.backupItem;
+
+ item.cacheStoreChanges = [];
+
+ _.forEach(item.caches, function(cacheId) {
+ const cache = _.find($scope.caches, {value: cacheId}).cache;
+
+ const change = LegacyUtils.autoCacheStoreConfiguration(cache, [item]);
+
+ if (change)
+ item.cacheStoreChanges.push({cacheId, change});
+ });
+
+ if (validate(item))
+ save(item);
+ }
+ };
+
+ function _domainNames() {
+ return _.map($scope.domains, function(domain) {
+ return domain.valueType;
+ });
+ }
+
+ function _newNameIsValidJavaClass(newName) {
+ return LegacyUtils.isValidJavaClass('New name for value type', newName, false, 'copy-new-nameInput');
+ }
+
+ // Save domain model with new name.
+ $scope.cloneItem = function() {
+ if ($scope.tableReset(true) && validate($scope.backupItem)) {
+ Clone.confirm($scope.backupItem.valueType, _domainNames(), _newNameIsValidJavaClass).then(function(newName) {
+ const item = angular.copy($scope.backupItem);
+
+ delete item._id;
+ item.valueType = newName;
+
+ save(item);
+ });
+ }
+ };
+
+ // Remove domain model from db.
+ $scope.removeItem = function() {
+ LegacyTable.tableReset();
+
+ const selectedItem = $scope.selectedItem;
+
+ Confirm.confirm('Are you sure you want to remove domain model: "' + selectedItem.valueType + '"?')
+ .then(function() {
+ const _id = selectedItem._id;
+
+ $http.post('/api/v1/configuration/domains/remove', {_id})
+ .success(function() {
+ Messages.showInfo('Domain model has been removed: ' + selectedItem.valueType);
+
+ const domains = $scope.domains;
+
+ const idx = _.findIndex(domains, function(domain) {
+ return domain._id === _id;
+ });
+
+ if (idx >= 0) {
+ domains.splice(idx, 1);
+
+ $scope.ui.inputForm.$setPristine();
+
+ if (domains.length > 0)
+ $scope.selectItem(domains[0]);
+ else
+ $scope.backupItem = emptyDomain;
+
+ _.forEach($scope.caches, (cache) => _.remove(cache.cache.domains, (id) => id === _id));
+ }
+
+ _checkShowValidPresentation();
+ })
+ .error(Messages.showError);
+ });
+ };
+
+ // Remove all domain models from db.
+ $scope.removeAllItems = function() {
+ LegacyTable.tableReset();
+
+ Confirm.confirm('Are you sure you want to remove all domain models?')
+ .then(function() {
+ $http.post('/api/v1/configuration/domains/remove/all')
+ .success(function() {
+ Messages.showInfo('All domain models have been removed');
+
+ $scope.domains = [];
+
+ _.forEach($scope.caches, (cache) => cache.cache.domains = []);
+
+ $scope.backupItem = emptyDomain;
+ $scope.ui.showValid = true;
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ })
+ .error(Messages.showError);
+ });
+ };
+
+ $scope.toggleValid = function() {
+ $scope.ui.showValid = !$scope.ui.showValid;
+
+ const validFilter = $filter('domainsValidation');
+
+ let idx = -1;
+
+ if (LegacyUtils.isDefined($scope.selectedItem)) {
+ idx = _.findIndex(validFilter($scope.domains, $scope.ui.showValid, true), function(domain) {
+ return domain._id === $scope.selectedItem._id;
+ });
+ }
+
+ if (idx === -1)
+ $scope.backupItem = emptyDomain;
+ };
+
+ const pairFields = {
+ fields: {
+ msg: 'Query field class',
+ id: 'QryField',
+ idPrefix: 'Key',
+ searchCol: 'name',
+ valueCol: 'key',
+ classValidation: true,
+ dupObjName: 'name'
+ },
+ aliases: {id: 'Alias', idPrefix: 'Value', searchCol: 'alias', valueCol: 'value', dupObjName: 'alias'}
+ };
+
+ $scope.tablePairValid = function(item, field, index, stopEdit) {
+ const pairField = pairFields[field.model];
+
+ const pairValue = LegacyTable.tablePairValue(field, index);
+
+ if (pairField) {
+ const model = item[field.model];
+
+ if (LegacyUtils.isDefined(model)) {
+ const idx = _.findIndex(model, function(pair) {
+ return pair[pairField.searchCol] === pairValue[pairField.valueCol];
+ });
+
+ // 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 (pairField.classValidation && !LegacyUtils.isValidJavaClass(pairField.msg, pairValue.value, true, LegacyTable.tableFieldId(index, 'Value' + pairField.id), false, $scope.ui, 'query')) {
+ if (stopEdit)
+ return false;
+
+ return LegacyTable.tableFocusInvalidField(index, 'Value' + pairField.id);
+ }
+ }
+
+ return true;
+ };
+
+ function tableDbFieldValue(field, index) {
+ return (index < 0) ? {
+ databaseFieldName: field.newDatabaseFieldName,
+ databaseFieldType: field.newDatabaseFieldType,
+ javaFieldName: field.newJavaFieldName,
+ javaFieldType: field.newJavaFieldType
+ } : {
+ databaseFieldName: field.curDatabaseFieldName,
+ databaseFieldType: field.curDatabaseFieldType,
+ javaFieldName: field.curJavaFieldName,
+ javaFieldType: field.curJavaFieldType
+ };
+ }
+
+ $scope.tableDbFieldSaveVisible = function(field, index) {
+ const dbFieldValue = tableDbFieldValue(field, index);
+
+ return LegacyUtils.isDefined(dbFieldValue.databaseFieldType) &&
+ LegacyUtils.isDefined(dbFieldValue.javaFieldType) &&
+ !LegacyUtils.isEmptyString(dbFieldValue.databaseFieldName) &&
+ !LegacyUtils.isEmptyString(dbFieldValue.javaFieldName);
+ };
+
+ const dbFieldTables = {
+ keyFields: {msg: 'Key field', id: 'KeyField'},
+ valueFields: {msg: 'Value field', id: 'ValueField'}
+ };
+
+ $scope.tableDbFieldSave = function(field, index, stopEdit) {
+ const dbFieldTable = dbFieldTables[field.model];
+
+ if (dbFieldTable) {
+ const dbFieldValue = tableDbFieldValue(field, index);
+
+ const item = $scope.backupItem;
+
+ let model = item[field.model];
+
+ if (!LegacyUtils.isValidJavaIdentifier(dbFieldTable.msg + ' java name', dbFieldValue.javaFieldName, LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id)))
+ return false;
+
+ if (LegacyUtils.isDefined(model)) {
+ let idx = _.findIndex(model, function(dbMeta) {
+ return dbMeta.databaseFieldName === dbFieldValue.databaseFieldName;
+ });
+
+ // 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');
+
+ idx = _.findIndex(model, function(dbMeta) {
+ return dbMeta.javaFieldName === dbFieldValue.javaFieldName;
+ });
+
+ // 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');
+
+ if (index < 0)
+ model.push(dbFieldValue);
+ else {
+ const dbField = model[index];
+
+ dbField.databaseFieldName = dbFieldValue.databaseFieldName;
+ dbField.databaseFieldType = dbFieldValue.databaseFieldType;
+ dbField.javaFieldName = dbFieldValue.javaFieldName;
+ dbField.javaFieldType = dbFieldValue.javaFieldType;
+ }
+ }
+ else {
+ model = [dbFieldValue];
+
+ item[field.model] = model;
+ }
+
+ if (!stopEdit) {
+ if (index < 0)
+ LegacyTable.tableNewItem(field);
+ else if (index < model.length - 1)
+ LegacyTable.tableStartEdit(item, field, index + 1);
+ else
+ LegacyTable.tableNewItem(field);
+ }
+
+ return true;
+ }
+
+ return false;
+ };
+
+ function tableIndexName(field, index) {
+ return index < 0 ? field.newIndexName : field.curIndexName;
+ }
+
+ function tableIndexType(field, index) {
+ return index < 0 ? field.newIndexType : field.curIndexType;
+ }
+
+ $scope.tableIndexSaveVisible = function(field, index) {
+ return !LegacyUtils.isEmptyString(tableIndexName(field, index)) && LegacyUtils.isDefined(tableIndexType(field, index));
+ };
+
+ $scope.tableIndexSave = function(field, curIdx, stopEdit) {
+ const indexName = tableIndexName(field, curIdx);
+ const indexType = tableIndexType(field, curIdx);
+
+ const item = $scope.backupItem;
+
+ const indexes = item.indexes;
+
+ if (LegacyUtils.isDefined(indexes)) {
+ const idx = _.findIndex(indexes, function(index) {
+ return index.name === indexName;
+ });
+
+ // Found duplicate.
+ if (idx >= 0 && idx !== curIdx)
+ return ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!', $scope.ui, 'query');
+ }
+
+ LegacyTable.tableReset();
+
+ if (curIdx < 0) {
+ const newIndex = {name: indexName, indexType};
+
+ if (item.indexes)
+ item.indexes.push(newIndex);
+ else
+ item.indexes = [newIndex];
+ }
+ else {
+ item.indexes[curIdx].name = indexName;
+ item.indexes[curIdx].indexType = indexType;
+ }
+
+ if (!stopEdit) {
+ if (curIdx < 0)
+ $scope.tableIndexNewItem(field, item.indexes.length - 1);
+ else {
+ const index = item.indexes[curIdx];
+
+ if (index.fields && index.fields.length > 0)
+ $scope.tableIndexItemStartEdit(field, curIdx, 0);
+ else
+ $scope.tableIndexNewItem(field, curIdx);
+ }
+ }
+
+ return true;
+ };
+
+ $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);
+
+ field.newFieldName = null;
+ field.newDirection = true;
+ field.indexIdx = indexIdx;
+ }
+ };
+
+ $scope.tableIndexNewItemActive = function(field, itemIndex) {
+ const indexes = $scope.backupItem.indexes;
+
+ if (indexes) {
+ const index = indexes[itemIndex];
+
+ if (index)
+ return LegacyTable.tableNewItemActive({model: 'table-index-fields'}) && field.indexIdx === itemIndex;
+ }
+
+ return false;
+ };
+
+ $scope.tableIndexItemEditing = function(field, itemIndex, curIdx) {
+ const indexes = $scope.backupItem.indexes;
+
+ if (indexes) {
+ const index = indexes[itemIndex];
+
+ if (index)
+ return LegacyTable.tableEditing({model: 'table-index-fields'}, curIdx) && field.indexIdx === itemIndex;
+ }
+
+ return false;
+ };
+
+ function tableIndexItemValue(field, index) {
+ return index < 0 ? {
+ name: field.newFieldName,
+ direction: field.newDirection
+ } : {
+ name: field.curFieldName,
+ direction: field.curDirection
+ };
+ }
+
+ $scope.tableIndexItemStartEdit = function(field, indexIdx, curIdx) {
+ if ($scope.tableReset(true)) {
+ const index = $scope.backupItem.indexes[indexIdx];
+
+ LegacyTable.tableState(field, curIdx, 'table-index-fields');
+
+ const indexItem = index.fields[curIdx];
+
+ field.curFieldName = indexItem.name;
+ field.curDirection = indexItem.direction;
+ field.indexIdx = indexIdx;
+
+ Focus.move('curFieldName' + (index.indexType === 'SORTED' ? 'S' : '') + field.indexIdx + '-' + curIdx);
+ }
+ };
+
+ $scope.tableIndexItemSaveVisible = function(field, index) {
+ return !LegacyUtils.isEmptyString(tableIndexItemValue(field, index).name);
+ };
+
+ $scope.tableIndexItemSave = function(field, indexIdx, curIdx, stopEdit) {
+ const indexItemValue = tableIndexItemValue(field, curIdx);
+
+ const index = $scope.backupItem.indexes[indexIdx];
+
+ const fields = index.fields;
+
+ if (LegacyUtils.isDefined(fields)) {
+ 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');
+ }
+
+ LegacyTable.tableReset();
+
+ field.indexIdx = -1;
+
+ if (curIdx < 0) {
+ if (index.fields)
+ index.fields.push(indexItemValue);
+ else
+ index.fields = [indexItemValue];
+
+ if (!stopEdit)
+ $scope.tableIndexNewItem(field, indexIdx);
+ }
+ else {
+ index.fields[curIdx] = indexItemValue;
+
+ if (!stopEdit) {
+ if (curIdx < index.fields.length - 1)
+ $scope.tableIndexItemStartEdit(field, indexIdx, curIdx + 1);
+ else
+ $scope.tableIndexNewItem(field, indexIdx);
+ }
+ }
+
+ return true;
+ };
+
+ $scope.tableRemoveIndexItem = function(index, curIdx) {
+ LegacyTable.tableReset();
+
+ index.fields.splice(curIdx, 1);
+ };
+
+ $scope.resetAll = function() {
+ LegacyTable.tableReset();
+
+ Confirm.confirm('Are you sure you want to undo all changes for current domain model?')
+ .then(function() {
+ $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ });
+ };
+ }
+]];
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/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
new file mode 100644
index 0000000..7617712
--- /dev/null
+++ b/modules/web-console/frontend/controllers/igfs-controller.js
@@ -0,0 +1,416 @@
+/*
+ * 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.
+ */
+
+// Controller for IGFS screen.
+export default ['igfsController', [
+ '$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);
+
+ const emptyIgfs = {empty: true};
+
+ let __original_value;
+
+ const blank = {
+ ipcEndpointConfiguration: {},
+ secondaryFileSystem: {}
+ };
+
+ // We need to initialize backupItem with empty object in order to properly used from angular directives.
+ $scope.backupItem = emptyIgfs;
+
+ $scope.ui = FormUtils.formUI();
+ $scope.ui.activePanels = [0];
+ $scope.ui.topPanels = [0];
+
+ $scope.compactJavaName = FormUtils.compactJavaName;
+ $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+ $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+
+ $scope.tableSave = function(field, index, stopEdit) {
+ if (field.type === 'pathModes' && LegacyTable.tablePairSaveVisible(field, index))
+ return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+ return true;
+ };
+
+ $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.tableNewItem = function(field) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableNewItem(field);
+ };
+
+ $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.tablePairSave = LegacyTable.tablePairSave;
+ $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+
+ $scope.tableRemove = function(item, field, index) {
+ if ($scope.tableReset(true))
+ LegacyTable.tableRemove(item, field, index);
+ };
+
+ $scope.tablePairValid = function(item, field, index, stopEdit) {
+ const pairValue = LegacyTable.tablePairValue(field, index);
+
+ const model = item[field.model];
+
+ if (LegacyUtils.isDefined(model)) {
+ const idx = _.findIndex(model, function(pair) {
+ return pair.path === pairValue.key;
+ });
+
+ // Found duplicate.
+ if (idx >= 0 && idx !== index) {
+ if (stopEdit)
+ return false;
+
+ return ErrorPopover.show(LegacyTable.tableFieldId(index, 'KeyPathMode'), 'Such path already exists!', $scope.ui, 'misc');
+ }
+ }
+
+ return true;
+ };
+
+ $scope.tblPathModes = {
+ type: 'pathModes',
+ model: 'pathModes',
+ focusId: 'PathMode',
+ ui: 'table-pair',
+ keyName: 'path',
+ valueName: 'mode',
+ save: $scope.tableSave
+ };
+
+ $scope.igfsModes = LegacyUtils.mkOptions(['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']);
+
+ $scope.contentVisible = function() {
+ const item = $scope.backupItem;
+
+ return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
+ };
+
+ $scope.toggleExpanded = function() {
+ $scope.ui.expanded = !$scope.ui.expanded;
+
+ ErrorPopover.hide();
+ };
+
+ $scope.igfss = [];
+ $scope.clusters = [];
+
+ function selectFirstItem() {
+ if ($scope.igfss.length > 0)
+ $scope.selectItem($scope.igfss[0]);
+ }
+
+ Loading.start('loadingIgfsScreen');
+
+ // When landing on the page, get IGFSs and show them.
+ Resource.read()
+ .then(({spaces, clusters, igfss}) => {
+ $scope.spaces = spaces;
+
+ $scope.igfss = igfss || [];
+
+ // For backward compatibility set colocateMetadata and relaxedConsistency default values.
+ _.forEach($scope.igfss, (igfs) => {
+ if (_.isUndefined(igfs.colocateMetadata))
+ igfs.colocateMetadata = true;
+
+ if (_.isUndefined(igfs.relaxedConsistency))
+ igfs.relaxedConsistency = true;
+ });
+
+ $scope.clusters = _.map(clusters || [], (cluster) => ({
+ label: cluster.name,
+ value: cluster._id
+ }));
+
+ if ($state.params.linkId)
+ $scope.createItem($state.params.linkId);
+ else {
+ const lastSelectedIgfs = angular.fromJson(sessionStorage.lastSelectedIgfs);
+
+ if (lastSelectedIgfs) {
+ const idx = _.findIndex($scope.igfss, function(igfs) {
+ return igfs._id === lastSelectedIgfs;
+ });
+
+ if (idx >= 0)
+ $scope.selectItem($scope.igfss[idx]);
+ else {
+ sessionStorage.removeItem('lastSelectedIgfs');
+
+ selectFirstItem();
+ }
+ }
+ else
+ selectFirstItem();
+ }
+
+ $scope.$watch('ui.inputForm.$valid', function(valid) {
+ if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+ $scope.ui.inputForm.$dirty = false;
+ });
+
+ $scope.$watch('backupItem', function(val) {
+ if (!$scope.ui.inputForm)
+ return;
+
+ const form = $scope.ui.inputForm;
+
+ if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+ form.$setPristine();
+ else
+ form.$setDirty();
+ }, true);
+
+ $scope.$watch('ui.activePanels.length', () => {
+ ErrorPopover.hide();
+ });
+ })
+ .catch(Messages.showError)
+ .then(() => {
+ $scope.ui.ready = true;
+ $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+ Loading.finish('loadingIgfsScreen');
+ });
+
+ $scope.selectItem = function(item, backup) {
+ function selectItem() {
+ LegacyTable.tableReset();
+
+ $scope.selectedItem = item;
+
+ try {
+ if (item && item._id)
+ sessionStorage.lastSelectedIgfs = angular.toJson(item._id);
+ else
+ sessionStorage.removeItem('lastSelectedIgfs');
+ }
+ catch (ignored) {
+ // No-op.
+ }
+
+ if (backup)
+ $scope.backupItem = backup;
+ else if (item)
+ $scope.backupItem = angular.copy(item);
+ else
+ $scope.backupItem = emptyIgfs;
+
+ $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+ if ($scope.ui.inputForm) {
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ }
+
+ __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+ if (LegacyUtils.getQueryVariable('new'))
+ $state.go('base.configuration.igfs');
+ }
+
+ FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+ };
+
+ $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+ function prepareNewItem(linkId) {
+ return {
+ space: $scope.spaces[0]._id,
+ ipcEndpointEnabled: true,
+ fragmentizerEnabled: true,
+ colocateMetadata: true,
+ relaxedConsistency: true,
+ clusters: linkId && _.find($scope.clusters, {value: linkId}) ? [linkId] :
+ (_.isEmpty($scope.clusters) ? [] : [$scope.clusters[0].value])
+ };
+ }
+
+ // Add new IGFS.
+ $scope.createItem = function(linkId) {
+ if ($scope.tableReset(true)) {
+ $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'igfsNameInput'));
+
+ $scope.selectItem(null, prepareNewItem(linkId));
+ }
+ };
+
+ // Check IGFS logical consistency.
+ function validate(item) {
+ ErrorPopover.hide();
+
+ if (LegacyUtils.isEmptyString(item.name))
+ return ErrorPopover.show('igfsNameInput', 'IGFS name should not be empty!', $scope.ui, 'general');
+
+ if (!LegacyUtils.checkFieldValidators($scope.ui))
+ return false;
+
+ if (!item.secondaryFileSystemEnabled && (item.defaultMode === 'PROXY'))
+ return ErrorPopover.show('secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" IGFS mode!', $scope.ui, 'secondaryFileSystem');
+
+ if (item.pathModes) {
+ for (let pathIx = 0; pathIx < item.pathModes.length; pathIx++) {
+ if (!item.secondaryFileSystemEnabled && item.pathModes[pathIx].mode === 'PROXY')
+ return ErrorPopover.show('secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" path mode!', $scope.ui, 'secondaryFileSystem');
+ }
+ }
+
+ return true;
+ }
+
+ // Save IGFS in database.
+ function save(item) {
+ $http.post('/api/v1/configuration/igfs/save', item)
+ .success(function(_id) {
+ $scope.ui.inputForm.$setPristine();
+
+ const idx = _.findIndex($scope.igfss, function(igfs) {
+ return igfs._id === _id;
+ });
+
+ if (idx >= 0)
+ angular.merge($scope.igfss[idx], item);
+ else {
+ item._id = _id;
+ $scope.igfss.push(item);
+ }
+
+ $scope.selectItem(item);
+
+ Messages.showInfo('IGFS "' + item.name + '" saved.');
+ })
+ .error(Messages.showError);
+ }
+
+ // Save IGFS.
+ $scope.saveItem = function() {
+ if ($scope.tableReset(true)) {
+ const item = $scope.backupItem;
+
+ if (validate(item))
+ save(item);
+ }
+ };
+
+ function _igfsNames() {
+ return _.map($scope.igfss, function(igfs) {
+ return igfs.name;
+ });
+ }
+
+ // Clone IGFS with new name.
+ $scope.cloneItem = function() {
+ if ($scope.tableReset(true) && validate($scope.backupItem)) {
+ Clone.confirm($scope.backupItem.name, _igfsNames()).then(function(newName) {
+ const item = angular.copy($scope.backupItem);
+
+ delete item._id;
+
+ item.name = newName;
+
+ save(item);
+ });
+ }
+ };
+
+ // Remove IGFS from db.
+ $scope.removeItem = function() {
+ LegacyTable.tableReset();
+
+ const selectedItem = $scope.selectedItem;
+
+ Confirm.confirm('Are you sure you want to remove IGFS: "' + selectedItem.name + '"?')
+ .then(function() {
+ const _id = selectedItem._id;
+
+ $http.post('/api/v1/configuration/igfs/remove', {_id})
+ .success(function() {
+ Messages.showInfo('IGFS has been removed: ' + selectedItem.name);
+
+ const igfss = $scope.igfss;
+
+ const idx = _.findIndex(igfss, function(igfs) {
+ return igfs._id === _id;
+ });
+
+ if (idx >= 0) {
+ igfss.splice(idx, 1);
+
+ $scope.ui.inputForm.$setPristine();
+
+ if (igfss.length > 0)
+ $scope.selectItem(igfss[0]);
+ else
+ $scope.backupItem = emptyIgfs;
+ }
+ })
+ .error(Messages.showError);
+ });
+ };
+
+ // Remove all IGFS from db.
+ $scope.removeAllItems = function() {
+ LegacyTable.tableReset();
+
+ Confirm.confirm('Are you sure you want to remove all IGFS?')
+ .then(function() {
+ $http.post('/api/v1/configuration/igfs/remove/all')
+ .success(function() {
+ Messages.showInfo('All IGFS have been removed');
+
+ $scope.igfss = [];
+ $scope.backupItem = emptyIgfs;
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ })
+ .error(Messages.showError);
+ });
+ };
+
+ $scope.resetAll = function() {
+ LegacyTable.tableReset();
+
+ Confirm.confirm('Are you sure you want to undo all changes for current IGFS?')
+ .then(function() {
+ $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+ $scope.ui.inputForm.$error = {};
+ $scope.ui.inputForm.$setPristine();
+ });
+ };
+ }
+]];