IGNITE-9151 Web Console: Fixed logic of removing cluster items: caches, models, igfss.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1cdf7ef9 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1cdf7ef9 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1cdf7ef9 Branch: refs/heads/ignite-8446 Commit: 1cdf7ef992c36a1b8f52021dd91705c51257d1c1 Parents: 5fc18e6 Author: Alexey Kuznetsov <[email protected]> Authored: Thu Aug 2 17:18:50 2018 +0700 Committer: Alexey Kuznetsov <[email protected]> Committed: Thu Aug 2 17:18:50 2018 +0700 ---------------------------------------------------------------------- .../form-field/showValidationError.directive.js | 6 +- .../grid-column-selector/controller.js | 8 +- .../list-editable-save-on-changes/directives.js | 14 ++- .../list-editable-transclude/directive.js | 12 +- .../app/components/list-editable/controller.js | 6 +- .../components/cluster-edit-form/controller.js | 2 - .../components/model-edit-form/controller.js | 10 +- .../page-configure-basic/controller.js | 13 ++- .../pco-grid-column-categories/directive.js | 4 +- .../components/formUICanExitGuard.js | 12 +- .../components/modal-import-models/component.js | 23 ++-- .../tables-action-cell/component.js | 14 ++- .../modal-preview-project/controller.js | 10 +- .../components/pc-form-field-size/controller.js | 8 +- .../components/pc-items-table/controller.js | 26 ++++- .../components/pc-ui-grid-filters/directive.js | 4 +- .../components/pc-ui-grid-filters/index.js | 5 +- .../components/pcIsInCollection.js | 4 +- .../page-configure/components/pcValidation.js | 8 +- .../app/components/page-configure/index.js | 14 ++- .../app/components/page-configure/reducer.js | 90 ++++++++++++++- .../page-configure/services/ConfigureState.js | 5 + .../app/components/page-configure/states.js | 88 ++++++++------ .../components/page-configure/store/effects.js | 114 +++++++++++-------- .../page-configure/store/selectors.js | 50 +++++++- .../transitionHooks/errorState.js | 5 +- .../frontend/app/components/page-signin/run.js | 5 +- .../components/panel-collapsible/controller.js | 19 +++- .../app/components/ui-grid-filters/directive.js | 3 +- .../app/components/ui-grid-filters/index.js | 4 +- .../generator/ConfigurationGenerator.js | 3 +- .../field/bs-select-placeholder.directive.js | 4 +- .../modules/form/validator/unique.directive.js | 6 +- .../web-console/frontend/app/services/Caches.js | 10 +- .../frontend/app/services/Clusters.js | 32 ++++-- .../frontend/app/services/FormUtils.service.js | 13 ++- .../web-console/frontend/app/services/IGFSs.js | 8 +- .../web-console/frontend/app/services/Models.js | 17 ++- .../frontend/app/services/exceptionHandler.js | 4 +- 39 files changed, 509 insertions(+), 174 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js b/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js index 32123cc..8720c56 100644 --- a/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js +++ b/modules/web-console/frontend/app/components/form-field/showValidationError.directive.js @@ -24,10 +24,14 @@ export function directive($timeout) { require: ['ngModel', '?^^bsCollapseTarget', '?^^igniteFormField', '?^^panelCollapsible'], link(scope, el, attr, [ngModel, bsCollapseTarget, igniteFormField, panelCollapsible]) { const off = scope.$on('$showValidationError', (e, target) => { - if (target !== ngModel) return; + if (target !== ngModel) + return; + ngModel.$setTouched(); + bsCollapseTarget && bsCollapseTarget.open(); panelCollapsible && panelCollapsible.open(); + $timeout(() => { if (el[0].scrollIntoViewIfNeeded) el[0].scrollIntoViewIfNeeded(); http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/grid-column-selector/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/grid-column-selector/controller.js b/modules/web-console/frontend/app/components/grid-column-selector/controller.js index 1f04861..2f5554e 100644 --- a/modules/web-console/frontend/app/components/grid-column-selector/controller.js +++ b/modules/web-console/frontend/app/components/grid-column-selector/controller.js @@ -77,9 +77,13 @@ export default class GridColumnSelectorController { } findScrollToNext(columns, prevColumns) { - if (!prevColumns) return; + if (!prevColumns) + return; + const diff = difference(columns, prevColumns); - if (diff.length === 1 && columns.includes(diff[0])) return diff[0]; + + if (diff.length === 1 && columns.includes(diff[0])) + return diff[0]; } setSelectedColumns() { http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js index 4b6e785..f408647 100644 --- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js +++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js @@ -30,7 +30,9 @@ export function ngModel() { * @param {ng.INgModelController} ngModel */ link(scope, el, attr, {ngModel, list}) { - if (!list) return; + if (!list) + return; + ngModel.$viewChangeListeners.push(() => { el[0].dispatchEvent(new CustomEvent(CUSTOM_EVENT_TYPE, {bubbles: true, cancelable: true})); }); @@ -54,15 +56,21 @@ export function listEditableTransclude() { * @param {ListEditableController} list */ link(scope, el, attr, {list, transclude}) { - if (attr.listEditableTransclude !== 'itemEdit') return; - if (!list) return; + if (attr.listEditableTransclude !== 'itemEdit') + return; + + if (!list) + return; + let listener = (e) => { e.stopPropagation(); scope.$evalAsync(() => { if (scope.form.$valid) list.save(scope.item, transclude.$index); }); }; + el[0].addEventListener(CUSTOM_EVENT_TYPE, listener); + scope.$on('$destroy', () => { el[0].removeEventListener(CUSTOM_EVENT_TYPE, listener); listener = null; http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js index 55b4724..36750ae 100644 --- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js +++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js @@ -63,7 +63,9 @@ export class ListEditableTransclude { [itemName]: { get: () => { // Scope might get destroyed - if (!this.$scope) return; + if (!this.$scope) + return; + return this.$scope.item; }, set: (value) => { @@ -80,7 +82,9 @@ export class ListEditableTransclude { $form: { get: () => { // Scope might get destroyed - if (!this.$scope) return; + if (!this.$scope) + return; + return this.$scope.form; }, // Allows to delete property later @@ -98,7 +102,9 @@ export class ListEditableTransclude { * @returns {number} */ get $index() { - if (!this.$scope) return; + if (!this.$scope) + return; + return this.$scope.$index; } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/list-editable/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/list-editable/controller.js b/modules/web-console/frontend/app/components/list-editable/controller.js index 586743e..d1b8900 100644 --- a/modules/web-console/frontend/app/components/list-editable/controller.js +++ b/modules/web-console/frontend/app/components/list-editable/controller.js @@ -102,10 +102,12 @@ export default class { // ng-model-option, then it will always save. Be careful and pay extra attention to validation // when doing so, it's an easy way to miss invalid values this way. - // Dont close if form is invalid and allowInvalid is turned off (which is default value) - if (!form.$valid && !this.ngModel.$options.getOption('allowInvalid')) return; + // Don't close if form is invalid and allowInvalid is turned off (which is default value) + if (!form.$valid && !this.ngModel.$options.getOption('allowInvalid')) + return; delete this._cache[idx]; + this.save(data, idx); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js index cd8d3e4..881e543 100644 --- a/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js +++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/cluster-edit-form/controller.js @@ -44,8 +44,6 @@ export default class ClusterEditFormController { $onInit() { this.available = this.IgniteVersion.available.bind(this.IgniteVersion); - let __original_value; - const rebuildDropdowns = () => { this.eventStorage = [ {value: 'Memory', label: 'Memory'}, http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js index 60cb95f..b7d4ebe 100644 --- a/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js +++ b/modules/web-console/frontend/app/components/page-configure-advanced/components/model-edit-form/controller.js @@ -171,22 +171,30 @@ export default class ModelEditFormController { if ('caches' in changes) this.cachesMenu = (changes.caches.currentValue || []).map((c) => ({label: c.name, value: c._id})); } + /** * @param {ig.config.model.DomainModel} model */ onQueryFieldsChange(model) { this.$scope.backupItem = this.Models.removeInvalidFields(model); } + getValuesToCompare() { return [this.model, this.$scope.backupItem].map(this.Models.normalize); } + save(download) { if (this.$scope.ui.inputForm.$invalid) return this.IgniteFormUtils.triggerValidation(this.$scope.ui.inputForm, this.$scope); - if (!this.validate(this.$scope.backupItem)) return; + + if (!this.validate(this.$scope.backupItem)) + return; + this.onSave({$event: {model: cloneDeep(this.$scope.backupItem), download}}); } + reset = (forReal) => forReal ? this.$scope.backupItem = cloneDeep(this.model) : void 0; + confirmAndReset() { return this.Confirm.confirm('Are you sure you want to undo all changes for current model?').then(() => true) .then(this.reset) http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure-basic/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure-basic/controller.js b/modules/web-console/frontend/app/components/page-configure-basic/controller.js index 255bbe5..105765a 100644 --- a/modules/web-console/frontend/app/components/page-configure-basic/controller.js +++ b/modules/web-console/frontend/app/components/page-configure-basic/controller.js @@ -81,8 +81,11 @@ export default class PageConfigureBasicController { } _uiCanExit($transition$) { - if ($transition$.options().custom.justIDUpdate) return true; + if ($transition$.options().custom.justIDUpdate) + return true; + $transition$.onSuccess({}, () => this.reset()); + return Observable.forkJoin( this.ConfigureState.state$.pluck('edit', 'changes').take(1), this.clusterID$.switchMap((id) => this.ConfigureState.state$.let(this.ConfigSelectors.selectClusterShortCaches(id))).take(1), @@ -178,7 +181,9 @@ export default class PageConfigureBasicController { } save(download = false) { - if (this.form.$invalid) return this.IgniteFormUtils.triggerValidation(this.form, this.$scope); + if (this.form.$invalid) + return this.IgniteFormUtils.triggerValidation(this.form, this.$scope); + this.ConfigureState.dispatchAction((download ? basicSaveAndDownload : basicSave)(cloneDeep(this.clonedCluster))); } @@ -189,7 +194,7 @@ export default class PageConfigureBasicController { confirmAndReset() { return this.Confirm.confirm('Are you sure you want to undo all changes for current cluster?') - .then(() => this.reset()) - .catch(() => {}); + .then(() => this.reset()) + .catch(() => {}); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure-overview/components/pco-grid-column-categories/directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure-overview/components/pco-grid-column-categories/directive.js b/modules/web-console/frontend/app/components/page-configure-overview/components/pco-grid-column-categories/directive.js index 27d00dc..ff03e7f 100644 --- a/modules/web-console/frontend/app/components/page-configure-overview/components/pco-grid-column-categories/directive.js +++ b/modules/web-console/frontend/app/components/page-configure-overview/components/pco-grid-column-categories/directive.js @@ -38,7 +38,9 @@ export default function directive(uiGridConstants) { require: '^uiGrid', link: { pre(scope, el, attr, grid) { - if (!grid.grid.options.enableColumnCategories) return; + if (!grid.grid.options.enableColumnCategories) + return; + grid.grid.api.core.registerColumnsProcessor((cp) => { const oldCategories = grid.grid.options.categories; const newCategories = uniqBy(cp.filter(notSelectionColumn).map(({colDef: cd}) => { http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js b/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js index 0225c5f..c962161 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js +++ b/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js @@ -19,6 +19,7 @@ import {default as ConfigChangesGuard} from '../services/ConfigChangesGuard'; class FormUICanExitGuardController { static $inject = ['$element', ConfigChangesGuard.name]; + /** * @param {JQLite} $element * @param {ConfigChangesGuard} ConfigChangesGuard @@ -27,23 +28,30 @@ class FormUICanExitGuardController { this.$element = $element; this.ConfigChangesGuard = ConfigChangesGuard; } + $onDestroy() { this.$element = null; } + $onInit() { const data = this.$element.data(); const controller = Object.keys(data) .map((key) => data[key]) .find(this._itQuacks); - if (!controller) return; + if (!controller) + return; controller.uiCanExit = ($transition$) => { - if ($transition$.options().custom.justIDUpdate) return true; + if ($transition$.options().custom.justIDUpdate) + return true; + $transition$.onSuccess({}, controller.reset); + return this.ConfigChangesGuard.guard(...controller.getValuesToCompare()); }; } + _itQuacks(controller) { return controller.reset instanceof Function && controller.getValuesToCompare instanceof Function && http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js index 813c998..1d4ba7c 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js +++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js @@ -123,11 +123,12 @@ export class ModalImportModels { this.ActivitiesData = ActivitiesData; Object.assign(this, {Confirm, Focus, Messages, Loading, FormUtils, LegacyUtils}); } + loadData() { return Observable.of(this.clusterID) - .switchMap((id = 'new') => { - return this.ConfigureState.state$.let(this.ConfigSelectors.selectClusterToEdit(id, defaultNames.importedCluster)); - }) + .switchMap((id = 'new') => { + return this.ConfigureState.state$.let(this.ConfigSelectors.selectClusterToEdit(id, defaultNames.importedCluster)); + }) .switchMap((cluster) => { return (!(cluster.caches || []).length && !(cluster.models || []).length) ? Observable.of({ @@ -154,7 +155,9 @@ export class ModalImportModels { .take(1); } saveBatch(batch) { - if (!batch.length) return; + if (!batch.length) + return; + this.Loading.start('importDomainFromDb'); this.ConfigureState.dispatchAction({ type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION', @@ -212,8 +215,12 @@ export class ModalImportModels { return this.visibleTables = rows.map((r) => r.entity); } onCacheSelect(cacheID) { - if (cacheID < 0) return; - if (this.loadedCaches[cacheID]) return; + if (cacheID < 0) + return; + + if (this.loadedCaches[cacheID]) + return; + return this.onCacheSelectSubcription = Observable.merge( Observable.timer(0, 1).take(1) .do(() => this.ConfigureState.dispatchAction({type: 'LOAD_CACHE', cacheID})), @@ -290,10 +297,10 @@ export class ModalImportModels { }).subscribe(); // New - this.loadedCaches = { ...CACHE_TEMPLATES.reduce((a, c) => ({...a, [c.value]: c.cache}), {}) }; + this.actions = [ {value: 'connect', label: this.$root.IgniteDemoMode ? 'Description' : 'Connection'}, {value: 'schemas', label: 'Schemas'}, @@ -302,7 +309,6 @@ export class ModalImportModels { ]; // Legacy - $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'; @@ -591,7 +597,6 @@ export class ModalImportModels { if ($scope._curDbTable.actionWatch) { $scope._curDbTable.actionWatch(); - $scope._curDbTable.actionWatch = null; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js index 072a497..7fde5ba 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js +++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js @@ -22,23 +22,33 @@ const IMPORT_DM_NEW_CACHE = 1; export class TablesActionCell { static $inject = ['$element']; + constructor($element) { Object.assign(this, {$element}); } + onClick(e) { e.stopPropagation(); } + $postLink() { this.$element.on('click', this.onClick); } + $onDestroy() { this.$element.off('click', this.onClick); this.$element = null; } + tableActionView(table) { - if (!this.caches) return; + if (!this.caches) + return; + const cache = this.caches.find((c) => c.value === table.cacheOrTemplate); - if (!cache) return; + + if (!cache) + return; + const cacheName = cache.label; if (table.action === IMPORT_DM_NEW_CACHE) http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/modal-preview-project/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-preview-project/controller.js b/modules/web-console/frontend/app/components/page-configure/components/modal-preview-project/controller.js index e67ed25..1480fc1 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/modal-preview-project/controller.js +++ b/modules/web-console/frontend/app/components/page-configure/components/modal-preview-project/controller.js @@ -47,9 +47,15 @@ export default class ModalPreviewProjectController { showPreview(node) { this.fileText = ''; - if (!node) return; + + if (!node) + return; + this.fileExt = node.file.name.split('.').reverse()[0].toLowerCase(); - if (node.file.dir) return; + + if (node.file.dir) + return; + node.file.async('string').then((text) => { this.fileText = text; this.$scope.$applyAsync(); http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pc-form-field-size/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pc-form-field-size/controller.js b/modules/web-console/frontend/app/components/page-configure/components/pc-form-field-size/controller.js index 3253fe4..0d751e8 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pc-form-field-size/controller.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pc-form-field-size/controller.js @@ -115,12 +115,16 @@ export default class PCFormFieldSizeController { } _defaultLabel() { - if (!this.sizesMenu) return; + if (!this.sizesMenu) + return; + return this.sizesMenu[1].label; } chooseSizeScale(label = this._defaultLabel()) { - if (!label) return; + if (!label) + return; + return this.sizesMenu.find((option) => option.label.toLowerCase() === label.toLowerCase()); } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pc-items-table/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pc-items-table/controller.js b/modules/web-console/frontend/app/components/page-configure/components/pc-items-table/controller.js index f4d1f47..c97e50f 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pc-items-table/controller.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pc-items-table/controller.js @@ -44,23 +44,28 @@ export default class ItemsTableController { }, onRegisterApi: (api) => { this.gridAPI = api; + api.selection.on.rowSelectionChanged(this.$scope, (row, e) => { this.onRowsSelectionChange([row], e); }); + api.selection.on.rowSelectionChangedBatch(this.$scope, (rows, e) => { this.onRowsSelectionChange(rows, e); }); + api.core.on.rowsVisibleChanged(this.$scope, () => { const visibleRows = api.core.getVisibleRows(); if (this.onVisibleRowsChange) this.onVisibleRowsChange({$event: visibleRows}); this.adjustHeight(api, visibleRows.length); this.showFilterNotification = this.grid.data.length && visibleRows.length === 0; }); + if (this.onFilterChanged) { api.core.on.filterChanged(this.$scope, () => { this.onFilterChanged(); }); } + this.$timeout(() => { if (this.selectedRowId) this.applyIncomingSelection(this.selectedRowId); }); @@ -73,10 +78,16 @@ export default class ItemsTableController { oneWaySelection = false; onRowsSelectionChange = debounce((rows, e = {}) => { - if (e.ignore) return; + if (e.ignore) + return; + const selected = this.gridAPI.selection.legacyGetSelectedRows(); - if (this.oneWaySelection) rows.forEach((r) => r.isSelected = false); - if (this.onSelectionChange) this.onSelectionChange({$event: selected}); + + if (this.oneWaySelection) + rows.forEach((r) => r.isSelected = false); + + if (this.onSelectionChange) + this.onSelectionChange({$event: selected}); }); makeActionsMenu(incomingActionsMenu = []) { @@ -85,17 +96,22 @@ export default class ItemsTableController { $onChanges(changes) { const hasChanged = (binding) => binding in changes && changes[binding].currentValue !== changes[binding].previousValue; + if (hasChanged('items') && this.grid) { this.grid.data = changes.items.currentValue; this.gridAPI.grid.modifyRows(this.grid.data); this.adjustHeight(this.gridAPI, this.grid.data.length); + // Without property existence check non-set selectedRowId binding might cause // unwanted behavior, like unchecking rows during any items change, even if // nothing really changed. - if ('selectedRowId' in this) this.applyIncomingSelection(this.selectedRowId); + if ('selectedRowId' in this) + this.applyIncomingSelection(this.selectedRowId); } + if (hasChanged('selectedRowId') && this.grid && this.grid.data) this.applyIncomingSelection(changes.selectedRowId.currentValue); + if ('incomingActionsMenu' in changes) this.actionsMenu = this.makeActionsMenu(changes.incomingActionsMenu.currentValue); } @@ -103,9 +119,11 @@ export default class ItemsTableController { applyIncomingSelection(selected = []) { this.gridAPI.selection.clearSelectedRows({ignore: true}); const rows = this.grid.data.filter((r) => selected.includes(r[this.rowIdentityKey])); + rows.forEach((r) => { this.gridAPI.selection.selectRow(r, {ignore: true}); }); + if (rows.length === 1) { this.$timeout(() => { this.gridAPI.grid.scrollToIfNecessary(this.gridAPI.grid.getRow(rows[0]), null); http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/directive.js b/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/directive.js index ccbdb8d..3d4617c 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/directive.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/directive.js @@ -23,7 +23,9 @@ export default function pcUiGridFilters(uiGridConstants) { require: 'uiGrid', link: { pre(scope, el, attr, grid) { - if (!grid.grid.options.enableFiltering) return; + if (!grid.grid.options.enableFiltering) + return; + grid.grid.options.columnDefs.filter((cd) => cd.multiselectFilterOptions).forEach((cd) => { cd.headerCellTemplate = template; cd.filter = { http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/index.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/index.js b/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/index.js index 4ec96e2..a34a78a 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/index.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pc-ui-grid-filters/index.js @@ -27,9 +27,12 @@ export default angular instance.$referenceElement = el; instance.destroy = flow(instance.destroy, () => instance.$referenceElement = null); instance.$applyPlacement = flow(instance.$applyPlacement, () => { - if (!instance.$element) return; + if (!instance.$element) + return; + const refWidth = instance.$referenceElement[0].getBoundingClientRect().width; const elWidth = instance.$element[0].getBoundingClientRect().width; + if (refWidth > elWidth) { instance.$element.css({ width: refWidth, http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pcIsInCollection.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pcIsInCollection.js b/modules/web-console/frontend/app/components/page-configure/components/pcIsInCollection.js index d2a9ae8..50ea4a4 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pcIsInCollection.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pcIsInCollection.js @@ -18,7 +18,9 @@ class Controller { $onInit() { this.ngModel.$validators.isInCollection = (item) => { - if (!item || !this.items) return true; + if (!item || !this.items) + return true; + return this.items.includes(item); }; } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js index e4c7314..1702c35 100644 --- a/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js +++ b/modules/web-console/frontend/app/components/page-configure/components/pcValidation.js @@ -56,7 +56,9 @@ export default angular.module('ignite-console.page-configure.validation', []) $onInit() { this.ngModel.$validators.notInCollection = (item) => { - if (!this.items) return true; + if (!this.items) + return true; + return !this.items.includes(item); }; } @@ -87,7 +89,9 @@ export default angular.module('ignite-console.page-configure.validation', []) $onInit() { this.ngModel.$validators.inCollection = (item) => { - if (!this.items) return false; + if (!this.items) + return false; + const items = this.pluck ? this.items.map((i) => i[this.pluck]) : this.items; return Array.isArray(item) ? item.every((i) => items.includes(i)) http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/index.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/index.js b/modules/web-console/frontend/app/components/page-configure/index.js index 0b254a0..9beea7a 100644 --- a/modules/web-console/frontend/app/components/page-configure/index.js +++ b/modules/web-console/frontend/app/components/page-configure/index.js @@ -61,6 +61,7 @@ Observable.prototype.debug = function(l) { import { editReducer2, + shortObjectsReducer, reducer, editReducer, loadingReducer, @@ -124,16 +125,18 @@ export default angular }); ConfigureState.actions$ - .filter((e) => e.type !== 'DISPATCH') - .withLatestFrom(ConfigureState.state$.skip(1)) - .subscribe(([action, state]) => devTools.send(action, state)); + .filter((e) => e.type !== 'DISPATCH') + .withLatestFrom(ConfigureState.state$.skip(1)) + .subscribe(([action, state]) => devTools.send(action, state)); ConfigureState.addReducer(reduxDevtoolsReducer); } + ConfigureState.addReducer(refsReducer({ models: {at: 'domains', store: 'caches'}, caches: {at: 'caches', store: 'models'} })); + ConfigureState.addReducer((state, action) => Object.assign({}, state, { clusterConfiguration: editReducer(state.clusterConfiguration, action), configurationLoading: loadingReducer(state.configurationLoading, action), @@ -148,14 +151,19 @@ export default angular shortIgfss: mapCacheReducerFactory(shortIGFSsActionTypes)(state.shortIgfss, action), edit: editReducer2(state.edit, action) })); + + ConfigureState.addReducer(shortObjectsReducer); + ConfigureState.addReducer((state, action) => { switch (action.type) { case 'APPLY_ACTIONS_UNDO': return action.state; + default: return state; } }); + const la = ConfigureState.actions$.scan((acc, action) => [...acc, action], []); ConfigureState.actions$ http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/reducer.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/reducer.js b/modules/web-console/frontend/app/components/page-configure/reducer.js index f959b0a..0f24bfa 100644 --- a/modules/web-console/frontend/app/components/page-configure/reducer.js +++ b/modules/web-console/frontend/app/components/page-configure/reducer.js @@ -16,6 +16,7 @@ */ import difference from 'lodash/difference'; +import capitalize from 'lodash/capitalize'; export const LOAD_LIST = Symbol('LOAD_LIST'); export const ADD_CLUSTER = Symbol('ADD_CLUSTER'); @@ -33,6 +34,7 @@ import { } from './store/actionTypes'; const defaults = {clusters: new Map(), caches: new Map(), spaces: new Map()}; + const mapByID = (items) => { return Array.isArray(items) ? new Map(items.map((item) => [item._id, item])) : new Map(items); }; @@ -48,21 +50,25 @@ export const reducer = (state = defaults, action) => { plugins: mapByID(action.list.plugins) }; } + case ADD_CLUSTER: { return Object.assign({}, state, { clusters: new Map([...state.clusters.entries(), [action.cluster._id, action.cluster]]) }); } + case ADD_CLUSTERS: { return Object.assign({}, state, { clusters: new Map([...state.clusters.entries(), ...action.clusters.map((c) => [c._id, c])]) }); } + case REMOVE_CLUSTERS: { return Object.assign({}, state, { clusters: new Map([...state.clusters.entries()].filter(([id, value]) => !action.clusterIDs.includes(id))) }); } + case UPDATE_CLUSTER: { const id = action._id || action.cluster._id; return Object.assign({}, state, { @@ -74,31 +80,38 @@ export const reducer = (state = defaults, action) => { })) }); } + case UPSERT_CLUSTERS: { return action.clusters.reduce((state, cluster) => reducer(state, { type: state.clusters.has(cluster._id) ? UPDATE_CLUSTER : ADD_CLUSTER, cluster }), state); } + case ADD_CACHE: { return Object.assign({}, state, { caches: new Map([...state.caches.entries(), [action.cache._id, action.cache]]) }); } + case UPDATE_CACHE: { const id = action.cache._id; + return Object.assign({}, state, { caches: new Map(state.caches).set(id, Object.assign({}, state.caches.get(id), action.cache)) }); } + case UPSERT_CACHES: { return action.caches.reduce((state, cache) => reducer(state, { type: state.caches.has(cache._id) ? UPDATE_CACHE : ADD_CACHE, cache }), state); } + case REMOVE_CACHE: return state; + default: return state; } @@ -119,34 +132,40 @@ export const editReducer = (state = {originalCluster: null}, action) => { ...state, originalCluster: action.cluster }; + case RECEIVE_CACHE_EDIT: { return { ...state, originalCache: action.cache }; } + case RECEIVE_IGFSS_EDIT: return { ...state, originalIGFSs: action.igfss }; + case RECEIVE_IGFS_EDIT: { return { ...state, originalIGFS: action.igfs }; } + case RECEIVE_MODELS_EDIT: return { ...state, originalModels: action.models }; + case RECEIVE_MODEL_EDIT: { return { ...state, originalModel: action.model }; } + default: return state; } @@ -160,8 +179,10 @@ export const loadingReducer = (state = loadingDefaults, action) => { switch (action.type) { case SHOW_CONFIG_LOADING: return {...state, isLoading: true, loadingText: action.loadingText}; + case HIDE_CONFIG_LOADING: return {...state, isLoading: false}; + default: return state; } @@ -171,12 +192,16 @@ export const setStoreReducerFactory = (actionTypes) => (state = new Set(), actio switch (action.type) { case actionTypes.SET: return new Set(action.items.map((i) => i._id)); + case actionTypes.RESET: return new Set(); + case actionTypes.UPSERT: return action.items.reduce((acc, item) => {acc.add(item._id); return acc;}, new Set(state)); + case actionTypes.REMOVE: return action.items.reduce((acc, item) => {acc.delete(item); return acc;}, new Set(state)); + default: return state; } @@ -186,14 +211,22 @@ export const mapStoreReducerFactory = (actionTypes) => (state = new Map(), actio switch (action.type) { case actionTypes.SET: return new Map(action.items.map((i) => [i._id, i])); + case actionTypes.RESET: return new Map(); + case actionTypes.UPSERT: - if (!action.items.length) return state; + if (!action.items.length) + return state; + return action.items.reduce((acc, item) => {acc.set(item._id, item); return acc;}, new Map(state)); + case actionTypes.REMOVE: - if (!action.ids.length) return state; + if (!action.ids.length) + return state; + return action.ids.reduce((acc, id) => {acc.delete(id); return acc;}, new Map(state)); + default: return state; } @@ -201,6 +234,7 @@ export const mapStoreReducerFactory = (actionTypes) => (state = new Map(), actio export const mapCacheReducerFactory = (actionTypes) => { const mapStoreReducer = mapStoreReducerFactory(actionTypes); + return (state = {value: mapStoreReducer(), pristine: true}, action) => { switch (action.type) { case actionTypes.SET: @@ -210,11 +244,13 @@ export const mapCacheReducerFactory = (actionTypes) => { value: mapStoreReducer(state.value, action), pristine: false }; + case actionTypes.RESET: return { value: mapStoreReducer(state.value, action), pristine: true }; + default: return state; } @@ -248,26 +284,31 @@ export const shortIGFSsActionTypes = mapStoreActionTypesFactory('SHORT_IGFSS'); export const itemsEditReducerFactory = (actionTypes) => { const setStoreReducer = setStoreReducerFactory(actionTypes); const mapStoreReducer = mapStoreReducerFactory(actionTypes); + return (state = {ids: setStoreReducer(), changedItems: mapStoreReducer()}, action) => { switch (action.type) { case actionTypes.SET: return action.state; + case actionTypes.LOAD: return { ...state, ids: setStoreReducer(state.ids, {...action, type: actionTypes.UPSERT}) }; + case actionTypes.RESET: case actionTypes.UPSERT: return { ids: setStoreReducer(state.ids, action), changedItems: mapStoreReducer(state.changedItems, action) }; + case actionTypes.REMOVE: return { ids: setStoreReducer(state.ids, {type: action.type, items: action.ids}), changedItems: mapStoreReducer(state.changedItems, action) }; + default: return state; } @@ -278,6 +319,7 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { switch (action.type) { case 'SET_EDIT': return action.state; + case 'EDIT_CLUSTER': { return { ...state, @@ -293,6 +335,7 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { } }; } + case 'RESET_EDIT_CHANGES': { return { ...state, @@ -308,6 +351,7 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { } }; } + case 'UPSERT_CLUSTER': { return { ...state, @@ -317,6 +361,7 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { } }; } + case 'UPSERT_CLUSTER_ITEM': { const {itemType, item} = action; return { @@ -330,8 +375,10 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { } }; } + case REMOVE_CLUSTER_ITEMS_CONFIRMED: { const {itemType, itemIDs} = action; + return { ...state, changes: { @@ -343,9 +390,11 @@ export const editReducer2 = (state = editReducer2.getDefaults(), action) => { } }; } + default: return state; } }; + editReducer2.getDefaults = () => ({ changes: ['caches', 'models', 'igfss'].reduce((a, t) => ({...a, [t]: {ids: [], changedItems: []}}), {cluster: null}) }); @@ -356,15 +405,19 @@ export const refsReducer = (refs) => (state, action) => { const newCluster = action.changedItems.cluster; const oldCluster = state.clusters.get(newCluster._id) || {}; const val = Object.keys(refs).reduce((state, ref) => { - if (!state || !state[refs[ref].store].size) return state; + if (!state || !state[refs[ref].store].size) + return state; const addedSources = new Set(difference(newCluster[ref], oldCluster[ref] || [])); const removedSources = new Set(difference(oldCluster[ref] || [], newCluster[ref])); const changedSources = new Map(action.changedItems[ref].map((m) => [m._id, m])); const targets = new Map(); + const maybeTarget = (id) => { - if (!targets.has(id)) targets.set(id, {[refs[ref].at]: {add: new Set(), remove: new Set()}}); + if (!targets.has(id)) + targets.set(id, {[refs[ref].at]: {add: new Set(), remove: new Set()}}); + return targets.get(id); }; @@ -373,11 +426,13 @@ export const refsReducer = (refs) => (state, action) => { .filter((sourceID) => removedSources.has(sourceID)) .forEach((sourceID) => maybeTarget(target._id)[refs[ref].at].remove.add(sourceID)); }); + [...addedSources.values()].forEach((sourceID) => { (changedSources.get(sourceID)[refs[ref].store] || []).forEach((targetID) => { maybeTarget(targetID)[refs[ref].at].add.add(sourceID); }); }); + action.changedItems[ref].filter((s) => !addedSources.has(s._id)).forEach((source) => { const newSource = source; const oldSource = state[ref].get(source._id); @@ -412,8 +467,35 @@ export const refsReducer = (refs) => (state, action) => { } : state; }, state); + return val; } + + default: + return state; + } +}; + +export const shortObjectsReducer = (state, action) => { + switch (action.type) { + case REMOVE_CLUSTER_ITEMS_CONFIRMED: { + const {itemType, itemIDs} = action; + + const target = 'short' + capitalize(itemType); + + const oldItems = state[target]; + + const newItems = { + value: itemIDs.reduce((acc, id) => {acc.delete(id); return acc;}, oldItems.value), + pristine: oldItems.pristine + }; + + return { + ...state, + [target]: newItems + }; + } + default: return state; } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/services/ConfigureState.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/services/ConfigureState.js b/modules/web-console/frontend/app/components/page-configure/services/ConfigureState.js index ea7f527..27e227d 100644 --- a/modules/web-console/frontend/app/components/page-configure/services/ConfigureState.js +++ b/modules/web-console/frontend/app/components/page-configure/services/ConfigureState.js @@ -32,15 +32,19 @@ export default class ConfigureState { return this._combinedReducer(state, action); } catch (e) { console.error(e); + return state; } }; + this.actions$.scan(reducer, {}).do((v) => this.state$.next(v)).subscribe(); } addReducer(combineFn) { const old = this._combinedReducer; + this._combinedReducer = (state, action) => combineFn(old(state, action), action); + return this; } @@ -49,6 +53,7 @@ export default class ConfigureState { return action((a) => this.actions$.next(a), () => this.state$.getValue()); this.actions$.next(action); + return action; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/states.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/states.js b/modules/web-console/frontend/app/components/page-configure/states.js index e76b18e..ed43f48 100644 --- a/modules/web-console/frontend/app/components/page-configure/states.js +++ b/modules/web-console/frontend/app/components/page-configure/states.js @@ -25,13 +25,15 @@ import {Observable} from 'rxjs/Observable'; const idRegex = `new|[a-z0-9]+`; const shortCachesResolve = ['ConfigSelectors', 'ConfigureState', 'ConfigEffects', '$transition$', (ConfigSelectors, ConfigureState, {etp}, $transition$) => { - if ($transition$.params().clusterID === 'new') return Promise.resolve(); + if ($transition$.params().clusterID === 'new') + return Promise.resolve(); + return Observable.fromPromise($transition$.injector().getAsync('_cluster')) - .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) - .switchMap((cluster) => { - return etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}); - }) - .toPromise(); + .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) + .switchMap((cluster) => { + return etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}); + }) + .toPromise(); }]; function registerStates($stateProvider) { @@ -134,17 +136,19 @@ function registerStates($stateProvider) { component: pageConfigureAdvancedCachesComponent.name, resolve: { _shortCachesAndModels: ['ConfigSelectors', 'ConfigureState', 'ConfigEffects', '$transition$', (ConfigSelectors, ConfigureState, {etp}, $transition$) => { - if ($transition$.params().clusterID === 'new') return Promise.resolve(); + if ($transition$.params().clusterID === 'new') + return Promise.resolve(); + return Observable.fromPromise($transition$.injector().getAsync('_cluster')) - .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) - .map((cluster) => { - return Promise.all([ - etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}), - etp('LOAD_SHORT_MODELS', {ids: cluster.models, clusterID: cluster._id}), - etp('LOAD_SHORT_IGFSS', {ids: cluster.igfss, clusterID: cluster._id}) - ]); - }) - .toPromise(); + .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) + .map((cluster) => { + return Promise.all([ + etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}), + etp('LOAD_SHORT_MODELS', {ids: cluster.models, clusterID: cluster._id}), + etp('LOAD_SHORT_IGFSS', {ids: cluster.igfss, clusterID: cluster._id}) + ]); + }) + .toPromise(); }] }, resolvePolicy: { @@ -160,7 +164,9 @@ function registerStates($stateProvider) { resolve: { _cache: ['ConfigEffects', '$transition$', ({etp}, $transition$) => { const {clusterID, cacheID} = $transition$.params(); - if (cacheID === 'new') return Promise.resolve(); + if (cacheID === 'new') + return Promise.resolve(); + return etp('LOAD_CACHE', {cacheID}); }] }, @@ -180,16 +186,18 @@ function registerStates($stateProvider) { permission: 'configuration', resolve: { _shortCachesAndModels: ['ConfigSelectors', 'ConfigureState', 'ConfigEffects', '$transition$', (ConfigSelectors, ConfigureState, {etp}, $transition$) => { - if ($transition$.params().clusterID === 'new') return Promise.resolve(); + if ($transition$.params().clusterID === 'new') + return Promise.resolve(); + return Observable.fromPromise($transition$.injector().getAsync('_cluster')) - .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) - .map((cluster) => { - return Promise.all([ - etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}), - etp('LOAD_SHORT_MODELS', {ids: cluster.models, clusterID: cluster._id}) - ]); - }) - .toPromise(); + .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) + .map((cluster) => { + return Promise.all([ + etp('LOAD_SHORT_CACHES', {ids: cluster.caches, clusterID: cluster._id}), + etp('LOAD_SHORT_MODELS', {ids: cluster.models, clusterID: cluster._id}) + ]); + }) + .toPromise(); }] }, resolvePolicy: { @@ -204,7 +212,10 @@ function registerStates($stateProvider) { resolve: { _cache: ['ConfigEffects', '$transition$', ({etp}, $transition$) => { const {clusterID, modelID} = $transition$.params(); - if (modelID === 'new') return Promise.resolve(); + + if (modelID === 'new') + return Promise.resolve(); + return etp('LOAD_MODEL', {modelID}); }] }, @@ -222,15 +233,17 @@ function registerStates($stateProvider) { permission: 'configuration', resolve: { _shortIGFSs: ['ConfigSelectors', 'ConfigureState', 'ConfigEffects', '$transition$', (ConfigSelectors, ConfigureState, {etp}, $transition$) => { - if ($transition$.params().clusterID === 'new') return Promise.resolve(); + if ($transition$.params().clusterID === 'new') + return Promise.resolve(); + return Observable.fromPromise($transition$.injector().getAsync('_cluster')) - .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) - .map((cluster) => { - return Promise.all([ - etp('LOAD_SHORT_IGFSS', {ids: cluster.igfss, clusterID: cluster._id}) - ]); - }) - .toPromise(); + .switchMap(() => ConfigureState.state$.let(ConfigSelectors.selectCluster($transition$.params().clusterID)).take(1)) + .map((cluster) => { + return Promise.all([ + etp('LOAD_SHORT_IGFSS', {ids: cluster.igfss, clusterID: cluster._id}) + ]); + }) + .toPromise(); }] }, resolvePolicy: { @@ -246,7 +259,10 @@ function registerStates($stateProvider) { resolve: { _igfs: ['ConfigEffects', '$transition$', ({etp}, $transition$) => { const {clusterID, igfsID} = $transition$.params(); - if (igfsID === 'new') return Promise.resolve(); + + if (igfsID === 'new') + return Promise.resolve(); + return etp('LOAD_IGFS', {igfsID}); }] }, http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/store/effects.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/store/effects.js b/modules/web-console/frontend/app/components/page-configure/store/effects.js index 42c4023..072701a 100644 --- a/modules/web-console/frontend/app/components/page-configure/store/effects.js +++ b/modules/web-console/frontend/app/components/page-configure/store/effects.js @@ -26,41 +26,39 @@ import {fromPromise} from 'rxjs/observable/fromPromise'; import uniq from 'lodash/uniq'; import { - clustersActionTypes, cachesActionTypes, - shortClustersActionTypes, + clustersActionTypes, + igfssActionTypes, + modelsActionTypes, shortCachesActionTypes, - shortModelsActionTypes, + shortClustersActionTypes, shortIGFSsActionTypes, - modelsActionTypes, - igfssActionTypes + shortModelsActionTypes } from '../reducer'; import { - REMOVE_CLUSTER_ITEMS, - REMOVE_CLUSTER_ITEMS_CONFIRMED, - CONFIRM_CLUSTERS_REMOVAL, - CONFIRM_CLUSTERS_REMOVAL_OK, - COMPLETE_CONFIGURATION, - ADVANCED_SAVE_COMPLETE_CONFIGURATION, - ADVANCED_SAVE_CLUSTER, ADVANCED_SAVE_CACHE, + ADVANCED_SAVE_CLUSTER, + ADVANCED_SAVE_COMPLETE_CONFIGURATION, ADVANCED_SAVE_IGFS, ADVANCED_SAVE_MODEL, BASIC_SAVE, BASIC_SAVE_AND_DOWNLOAD, - BASIC_SAVE_OK + BASIC_SAVE_OK, + COMPLETE_CONFIGURATION, + CONFIRM_CLUSTERS_REMOVAL, + CONFIRM_CLUSTERS_REMOVAL_OK, + REMOVE_CLUSTER_ITEMS, + REMOVE_CLUSTER_ITEMS_CONFIRMED } from './actionTypes'; import { - removeClusterItemsConfirmed, advancedSaveCompleteConfiguration, - confirmClustersRemoval, - confirmClustersRemovalOK, - completeConfiguration, - basicSave, + basicSaveErr, basicSaveOK, - basicSaveErr + completeConfiguration, + confirmClustersRemovalOK, + removeClusterItemsConfirmed } from './actionCreators'; import ConfigureState from 'app/components/page-configure/services/ConfigureState'; @@ -267,12 +265,14 @@ export default class ConfigEffects { .exhaustMap((a) => { return this.ConfigureState.state$.let(this.ConfigSelectors.selectCache(a.cacheID)).take(1) .switchMap((cache) => { - if (cache) return of({type: `${a.type}_OK`, cache}); + if (cache) + return of({type: `${a.type}_OK`, cache}); + return fromPromise(this.Caches.getCache(a.cacheID)) - .switchMap(({data}) => of( - {type: 'CACHE', cache: data}, - {type: `${a.type}_OK`, cache: data} - )); + .switchMap(({data}) => of( + {type: 'CACHE', cache: data}, + {type: `${a.type}_OK`, cache: data} + )); }) .catch((error) => of({ type: `${a.type}_ERR`, @@ -289,7 +289,9 @@ export default class ConfigEffects { this.loadShortCachesEffect$ = ConfigureState.actions$ .let(ofType('LOAD_SHORT_CACHES')) .exhaustMap((a) => { - if (!(a.ids || []).length) return of({type: `${a.type}_OK`}); + if (!(a.ids || []).length) + return of({type: `${a.type}_OK`}); + return this.ConfigureState.state$.let(this.ConfigSelectors.selectShortCaches()).take(1) .switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) @@ -315,12 +317,14 @@ export default class ConfigEffects { .exhaustMap((a) => { return this.ConfigureState.state$.let(this.ConfigSelectors.selectIGFS(a.igfsID)).take(1) .switchMap((igfs) => { - if (igfs) return of({type: `${a.type}_OK`, igfs}); + if (igfs) + return of({type: `${a.type}_OK`, igfs}); + return fromPromise(this.IGFSs.getIGFS(a.igfsID)) - .switchMap(({data}) => of( - {type: 'IGFS', igfs: data}, - {type: `${a.type}_OK`, igfs: data} - )); + .switchMap(({data}) => of( + {type: 'IGFS', igfs: data}, + {type: `${a.type}_OK`, igfs: data} + )); }) .catch((error) => of({ type: `${a.type}_ERR`, @@ -368,12 +372,14 @@ export default class ConfigEffects { .exhaustMap((a) => { return this.ConfigureState.state$.let(this.ConfigSelectors.selectModel(a.modelID)).take(1) .switchMap((model) => { - if (model) return of({type: `${a.type}_OK`, model}); + if (model) + return of({type: `${a.type}_OK`, model}); + return fromPromise(this.Models.getModel(a.modelID)) - .switchMap(({data}) => of( - {type: 'MODEL', model: data}, - {type: `${a.type}_OK`, model: data} - )); + .switchMap(({data}) => of( + {type: 'MODEL', model: data}, + {type: `${a.type}_OK`, model: data} + )); }) .catch((error) => of({ type: `${a.type}_ERR`, @@ -454,39 +460,48 @@ export default class ConfigEffects { const go = (state, params = {}) => this.$state.go( state, {...params, clusterID: cluster._id}, {location: 'replace', custom: {justIDUpdate: true}} ); + switch (type) { case 'models': { const state = 'base.configuration.edit.advanced.models.model'; this.IgniteMessages.showInfo(`Model "${value.valueType}" saved`); - if ( - this.$state.is(state) && this.$state.params.modelID !== value._id - ) return go(state, {modelID: value._id}); + + if (this.$state.is(state) && this.$state.params.modelID !== value._id) + return go(state, {modelID: value._id}); + break; } + case 'caches': { const state = 'base.configuration.edit.advanced.caches.cache'; this.IgniteMessages.showInfo(`Cache "${value.name}" saved`); - if ( - this.$state.is(state) && this.$state.params.cacheID !== value._id - ) return go(state, {cacheID: value._id}); + + if (this.$state.is(state) && this.$state.params.cacheID !== value._id) + return go(state, {cacheID: value._id}); + break; } + case 'igfss': { const state = 'base.configuration.edit.advanced.igfs.igfs'; this.IgniteMessages.showInfo(`IGFS "${value.name}" saved`); - if ( - this.$state.is(state) && this.$state.params.igfsID !== value._id - ) return go(state, {igfsID: value._id}); + + if (this.$state.is(state) && this.$state.params.igfsID !== value._id) + return go(state, {igfsID: value._id}); + break; } + case 'cluster': { const state = 'base.configuration.edit.advanced.cluster'; this.IgniteMessages.showInfo(`Cluster "${value.name}" saved`); - if ( - this.$state.is(state) && this.$state.params.clusterID !== value._id - ) return go(state); + + if (this.$state.is(state) && this.$state.params.clusterID !== value._id) + return go(state); + break; } + default: break; } }) @@ -497,7 +512,7 @@ export default class ConfigEffects { .exhaustMap((a) => { return a.confirm // TODO: list items to remove in confirmation - ? fromPromise(this.Confirm.confirm('Are you sure want to remove these items?')) + ? fromPromise(this.Confirm.confirm('Are you sure you want to remove these items?')) .mapTo(a) .catch(() => empty()) : of(a); @@ -522,7 +537,7 @@ export default class ConfigEffects { .switchMap((ids) => this.ConfigureState.state$.let(this.ConfigSelectors.selectClusterNames(ids)).take(1)) .exhaustMap((names) => { return fromPromise(this.Confirm.confirm(` - <p>Are you sure want to remove these clusters?</p> + <p>Are you sure you want to remove these clusters?</p> <ul>${names.map((name) => `<li>${name}</li>`).join('')}</ul> `)) .map(confirmClustersRemovalOK) @@ -656,6 +671,7 @@ export default class ConfigEffects { const err = `${action.type}_ERR`; setTimeout(() => this.ConfigureState.dispatchAction(action)); + return this.ConfigureState.actions$ .filter((a) => a.type === ok || a.type === err) .take(1) http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/store/selectors.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/store/selectors.js b/modules/web-console/frontend/app/components/page-configure/store/selectors.js index 0f60214..4996ba9 100644 --- a/modules/web-console/frontend/app/components/page-configure/store/selectors.js +++ b/modules/web-console/frontend/app/components/page-configure/store/selectors.js @@ -30,23 +30,37 @@ import {default as IGFSs} from 'app/services/IGFSs'; import {default as Models} from 'app/services/Models'; const isDefined = (s) => s.filter((v) => v); + const selectItems = (path) => (s) => s.filter((s) => s).pluck(path).filter((v) => v); + const selectValues = (s) => s.map((v) => v && [...v.value.values()]); + export const selectMapItem = (mapPath, key) => (s) => s.pluck(mapPath).map((v) => v && v.get(key)); + const selectMapItems = (mapPath, keys) => (s) => s.pluck(mapPath).map((v) => v && keys.map((key) => v.get(key))); + const selectItemToEdit = ({items, itemFactory, defaultName = '', itemID}) => (s) => s.switchMap((item) => { - if (item) return of(Object.assign(itemFactory(), item)); - if (itemID === 'new') return items.take(1).map((items) => Object.assign(itemFactory(), {name: uniqueName(defaultName, items)})); - if (!itemID) return of(null); + if (item) + return of(Object.assign(itemFactory(), item)); + + if (itemID === 'new') + return items.take(1).map((items) => Object.assign(itemFactory(), {name: uniqueName(defaultName, items)})); + + if (!itemID) + return of(null); + return empty(); }); + const currentShortItems = ({changesKey, shortKey}) => (state$) => { return Observable.combineLatest( state$.pluck('edit', 'changes', changesKey).let(isDefined).distinctUntilChanged(), state$.pluck(shortKey, 'value').let(isDefined).distinctUntilChanged() ) .map(([{ids = [], changedItems}, shortItems]) => { - if (!ids.length || !shortItems) return []; + if (!ids.length || !shortItems) + return []; + return ids.map((id) => changedItems.find(({_id}) => _id === id) || shortItems.get(id)); }) .map((v) => v.filter((v) => v)); @@ -58,6 +72,7 @@ const selectNames = (itemIDs, nameAt = 'name') => (items) => items export default class ConfigSelectors { static $inject = ['Caches', 'Clusters', 'IGFSs', 'Models']; + /** * @param {Caches} Caches * @param {Clusters} Clusters @@ -91,15 +106,25 @@ export default class ConfigSelectors { .let(this.selectShortClusters()) .let(selectNames(clusterIDs)); } + selectCluster = (id) => selectMapItem('clusters', id); + selectShortClusters = () => selectItems('shortClusters'); + selectCache = (id) => selectMapItem('caches', id); + selectIGFS = (id) => selectMapItem('igfss', id); + selectShortCaches = () => selectItems('shortCaches'); + selectShortCachesValue = () => (state$) => state$.let(this.selectShortCaches()).let(selectValues); + selectShortIGFSs = () => selectItems('shortIgfss'); + selectShortIGFSsValue = () => (state$) => state$.let(this.selectShortIGFSs()).let(selectValues); + selectShortModelsValue = () => (state$) => state$.let(this.selectShortModels()).let(selectValues); + selectCacheToEdit = (cacheID) => (state$) => state$ .let(this.selectCache(cacheID)) .distinctUntilChanged() @@ -109,6 +134,7 @@ export default class ConfigSelectors { defaultName: defaultNames.cache, itemID: cacheID })); + selectIGFSToEdit = (itemID) => (state$) => state$ .let(this.selectIGFS(itemID)) .distinctUntilChanged() @@ -118,6 +144,7 @@ export default class ConfigSelectors { defaultName: defaultNames.igfs, itemID })); + selectModelToEdit = (itemID) => (state$) => state$ .let(this.selectModel(itemID)) .distinctUntilChanged() @@ -126,6 +153,7 @@ export default class ConfigSelectors { itemFactory: () => this.Models.getBlankModel(), itemID })); + selectClusterToEdit = (clusterID, defaultName = defaultNames.cluster) => (state$) => state$ .let(this.selectCluster(clusterID)) .distinctUntilChanged() @@ -135,23 +163,33 @@ export default class ConfigSelectors { defaultName, itemID: clusterID })); + selectCurrentShortCaches = currentShortItems({changesKey: 'caches', shortKey: 'shortCaches'}); + selectCurrentShortIGFSs = currentShortItems({changesKey: 'igfss', shortKey: 'shortIgfss'}); + selectCurrentShortModels = currentShortItems({changesKey: 'models', shortKey: 'shortModels'}); + selectClusterShortCaches = (clusterID) => (state$) => { - if (clusterID === 'new') return of([]); + if (clusterID === 'new') + return of([]); + return combineLatest( state$.let(this.selectCluster(clusterID)).pluck('caches'), state$.let(this.selectShortCaches()).pluck('value'), (ids, items) => ids.map((id) => items.get(id)) ); }; + selectCompleteClusterConfiguration = ({clusterID, isDemo}) => (state$) => { const hasValues = (array) => !array.some((v) => !v); return state$.let(this.selectCluster(clusterID)) .exhaustMap((cluster) => { - if (!cluster) return of({__isComplete: false}); + if (!cluster) + return of({__isComplete: false}); + const withSpace = (array) => array.map((c) => ({...c, space: cluster.space})); + return Observable.forkJoin( state$.let(selectMapItems('caches', cluster.caches || [])).take(1), state$.let(selectMapItems('models', cluster.models || [])).take(1), http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-configure/transitionHooks/errorState.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-configure/transitionHooks/errorState.js b/modules/web-console/frontend/app/components/page-configure/transitionHooks/errorState.js index f36a931..fd9ca9b 100644 --- a/modules/web-console/frontend/app/components/page-configure/transitionHooks/errorState.js +++ b/modules/web-console/frontend/app/components/page-configure/transitionHooks/errorState.js @@ -44,9 +44,12 @@ const getResolvePromises = ($transition) => $transition.getResolveTokens() */ export const errorState = ($uiRouter) => { $uiRouter.transitionService.onError(match, ($transition) => { - if ($transition.error().type !== RejectType.ERROR) return; + if ($transition.error().type !== RejectType.ERROR) + return; + go($transition); }); + $uiRouter.transitionService.onStart(match, ($transition) => { Promise.all(getResolvePromises($transition)).catch((e) => go($transition)); }); http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/page-signin/run.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-signin/run.js b/modules/web-console/frontend/app/components/page-signin/run.js index 7ac3bf8..457e488 100644 --- a/modules/web-console/frontend/app/components/page-signin/run.js +++ b/modules/web-console/frontend/app/components/page-signin/run.js @@ -27,7 +27,10 @@ export function registerState($uiRouter) { unsaved: true, redirectTo: (trans) => { const skipStates = new Set(['signup', 'forgotPassword', 'landing']); - if (skipStates.has(trans.from().name)) return; + + if (skipStates.has(trans.from().name)) + return; + return trans.injector().get('User').read() .then(() => { try { http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/panel-collapsible/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/panel-collapsible/controller.js b/modules/web-console/frontend/app/components/panel-collapsible/controller.js index 0b8b4da..65ec06a 100644 --- a/modules/web-console/frontend/app/components/panel-collapsible/controller.js +++ b/modules/web-console/frontend/app/components/panel-collapsible/controller.js @@ -33,20 +33,31 @@ export default class PanelCollapsible { constructor($transclude) { this.$transclude = $transclude; } + toggle() { if (this.opened) this.close(); else this.open(); } + open() { - if (this.disabled) return; + if (this.disabled) + return; + this.opened = true; - if (this.onOpen && this.opened) this.onOpen({}); + + if (this.onOpen && this.opened) + this.onOpen({}); } + close() { - if (this.disabled) return; + if (this.disabled) + return; + this.opened = false; - if (this.onClose && !this.opened) this.onClose({}); + + if (this.onClose && !this.opened) + this.onClose({}); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/ui-grid-filters/directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/ui-grid-filters/directive.js b/modules/web-console/frontend/app/components/ui-grid-filters/directive.js index 6602c11..c9b84af 100644 --- a/modules/web-console/frontend/app/components/ui-grid-filters/directive.js +++ b/modules/web-console/frontend/app/components/ui-grid-filters/directive.js @@ -23,7 +23,8 @@ export default function uiGridFilters(uiGridConstants) { require: 'uiGrid', link: { pre(scope, el, attr, gridApi) { - if (!gridApi.grid.options.enableFiltering) return; + if (!gridApi.grid.options.enableFiltering) + return; const applyMultiselectFilter = (cd) => { cd.headerCellTemplate = template; http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/components/ui-grid-filters/index.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/ui-grid-filters/index.js b/modules/web-console/frontend/app/components/ui-grid-filters/index.js index 0f05b77..2c60d89 100644 --- a/modules/web-console/frontend/app/components/ui-grid-filters/index.js +++ b/modules/web-console/frontend/app/components/ui-grid-filters/index.js @@ -27,7 +27,9 @@ export default angular instance.$referenceElement = el; instance.destroy = flow(instance.destroy, () => instance.$referenceElement = null); instance.$applyPlacement = flow(instance.$applyPlacement, () => { - if (!instance.$element) return; + if (!instance.$element) + return; + const refWidth = instance.$referenceElement[0].getBoundingClientRect().width; const elWidth = instance.$element[0].getBoundingClientRect().width; if (refWidth > elWidth) { http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js b/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js index 95b7ce4..c3efea5 100644 --- a/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js +++ b/modules/web-console/frontend/app/modules/configuration/generator/ConfigurationGenerator.js @@ -1394,7 +1394,8 @@ export default class IgniteConfigurationGenerator { .longProperty('rateTimeInterval'); } - if (plcBean.isEmpty()) return; + if (plcBean.isEmpty()) + return; policies.push(plcBean); }); http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js b/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js index 56aa82a..cecb49c 100644 --- a/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js +++ b/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js @@ -24,7 +24,9 @@ export default ['bsSelect', [() => { const $render = ngModel.$render; ngModel.$render = () => { - if (scope.$destroyed) return; + if (scope.$destroyed) + return; + scope.$applyAsync(() => { $render(); const value = ngModel.$viewValue; http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/modules/form/validator/unique.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/form/validator/unique.directive.js b/modules/web-console/frontend/app/modules/form/validator/unique.directive.js index d32c565..318b8b6 100644 --- a/modules/web-console/frontend/app/modules/form/validator/unique.directive.js +++ b/modules/web-console/frontend/app/modules/form/validator/unique.directive.js @@ -42,12 +42,14 @@ class Controller { if (!this.skip) { // Return true in case if array not exist, array empty. - if (!this.items || !this.items.length) return true; + if (!this.items || !this.items.length) + return true; const idx = this.items.findIndex(matches); // In case of new element check all items. - if (isNew) return idx < 0; + if (isNew) + return idx < 0; // Case for new component list editable. const $index = this.listEditableTransclude http://git-wip-us.apache.org/repos/asf/ignite/blob/1cdf7ef9/modules/web-console/frontend/app/services/Caches.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Caches.js b/modules/web-console/frontend/app/services/Caches.js index add63f8..7df4bb6 100644 --- a/modules/web-console/frontend/app/services/Caches.js +++ b/modules/web-console/frontend/app/services/Caches.js @@ -165,7 +165,10 @@ export default class Caches { maxMemorySize: { min: (evictionPolicy) => { const policy = evictionPolicy[evictionPolicy.kind]; - if (!policy) return true; + + if (!policy) + return true; + const maxSize = policy.maxSize === null || policy.maxSize === void 0 ? this.evictionPolicy.maxSize.default : policy.maxSize; @@ -177,7 +180,10 @@ export default class Caches { maxSize: { min: (evictionPolicy) => { const policy = evictionPolicy[evictionPolicy.kind]; - if (!policy) return true; + + if (!policy) + return true; + const maxMemorySize = policy.maxMemorySize === null || policy.maxMemorySize === void 0 ? this.evictionPolicy.maxMemorySize.default : policy.maxMemorySize;
