modules/frontend/app/configuration/components/page-configure-basic/controller.ts (158 lines of code) (raw):

/* * 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. */ import {forkJoin, merge} from 'rxjs'; import {distinctUntilChanged, filter, map, pluck, publishReplay, refCount, switchMap, take, tap} from 'rxjs/operators'; import cloneDeep from 'lodash/cloneDeep'; import get from 'lodash/get'; import naturalCompare from 'natural-compare-lite'; import {basicSave, basicSaveAndDownload, changeItem, removeClusterItems} from '../../store/actionCreators'; import {Confirm} from 'app/services/Confirm.service'; import ConfigureState from '../../services/ConfigureState'; import ConfigSelectors from '../../store/selectors'; import Caches from '../../services/Caches'; import Clusters from '../../services/Clusters'; import IgniteVersion from 'app/services/Version.service'; import {default as ConfigChangesGuard} from '../../services/ConfigChangesGuard'; import {UIRouter} from '@uirouter/angularjs'; import FormUtils from 'app/services/FormUtils.service'; export default class PageConfigureBasicController { form: ng.IFormController; static $inject = [ 'Confirm', '$uiRouter', 'ConfigureState', 'ConfigSelectors', 'Clusters', 'Caches', 'IgniteVersion', '$element', 'ConfigChangesGuard', 'IgniteFormUtils', '$scope' ]; constructor( private Confirm: Confirm, private $uiRouter: UIRouter, private ConfigureState: ConfigureState, private ConfigSelectors: ConfigSelectors, private Clusters: Clusters, private Caches: Caches, private IgniteVersion: IgniteVersion, private $element: JQLite, private ConfigChangesGuard: ReturnType<typeof ConfigChangesGuard>, private IgniteFormUtils: ReturnType<typeof FormUtils>, private $scope: ng.IScope ) {} $onDestroy() { this.subscription.unsubscribe(); if (this.onBeforeTransition) this.onBeforeTransition(); this.$element = null; } $postLink() { this.$element.addClass('panel--ignite'); } _uiCanExit($transition$) { const options = $transition$.options(); if (options.custom.justIDUpdate || options.redirectedFrom) return true; $transition$.onSuccess({}, () => this.reset()); return forkJoin( this.ConfigureState.state$.pipe(pluck('edit', 'changes'), take(1)), this.clusterID$.pipe( switchMap((id) => this.ConfigureState.state$.pipe(this.ConfigSelectors.selectClusterShortCaches(id))), take(1) ), this.shortCaches$.pipe(take(1)) ) .toPromise() .then(([changes, originalShortCaches, currentCaches]) => { return this.ConfigChangesGuard.guard( { cluster: this.Clusters.normalize(this.originalCluster), caches: originalShortCaches.map(this.Caches.normalize) }, { cluster: {...this.Clusters.normalize(this.clonedCluster), caches: changes.caches.ids}, caches: currentCaches.map(this.Caches.normalize) } ); }); } $onInit() { this.onBeforeTransition = this.$uiRouter.transitionService.onBefore({}, (t) => this._uiCanExit(t)); this.memorySizeInputVisible$ = this.IgniteVersion.currentSbj.pipe( map((version) => this.IgniteVersion.since(version.ignite, '2.0.0')) ); const clusterID$ = this.$uiRouter.globals.params$.pipe( take(1), pluck('clusterID'), filter((v) => v), take(1) ); this.clusterID$ = clusterID$; this.isNew$ = this.$uiRouter.globals.params$.pipe(pluck('clusterID'), map((id) => id === 'new')); this.shortCaches$ = this.ConfigureState.state$.pipe(this.ConfigSelectors.selectCurrentShortCaches); this.shortClusters$ = this.ConfigureState.state$.pipe(this.ConfigSelectors.selectShortClustersValue()); this.originalCluster$ = clusterID$.pipe( distinctUntilChanged(), switchMap((id) => { return this.ConfigureState.state$.pipe(this.ConfigSelectors.selectClusterToEdit(id)); }), distinctUntilChanged(), publishReplay(1), refCount() ); this.subscription = merge( this.shortCaches$.pipe( map((caches) => caches.sort((a, b) => naturalCompare(a.name, b.name))), tap((v) => this.shortCaches = v) ), this.shortClusters$.pipe(tap((v) => this.shortClusters = v)), this.originalCluster$.pipe(tap((v) => { this.originalCluster = v; // clonedCluster should be set only when particular cluster edit starts. // // Stored cluster changes should not propagate to clonedCluster because it's assumed // that last saved copy has same shape to what's already loaded. If stored cluster would overwrite // clonedCluster every time, then data rollback on server errors would undo all changes // made by user and we don't want that. Advanced configuration forms do the same too. if (get(v, '_id') !== get(this.clonedCluster, '_id')) this.clonedCluster = cloneDeep(v); this.defaultMemoryPolicy = this.Clusters.getDefaultClusterMemoryPolicy(this.clonedCluster); })) ).subscribe(); this.formActionsMenu = [ { text: 'Save and Download', click: () => this.save(true), icon: 'download' }, { text: 'Save', click: () => this.save(), icon: 'checkmark' } ]; this.cachesColDefs = [ {name: 'Name:', cellClass: 'pc-form-grid-col-10'}, {name: 'Mode:', cellClass: 'pc-form-grid-col-10'}, {name: 'Atomicity:', cellClass: 'pc-form-grid-col-20', tip: ` Atomicity: <ul> <li>ATOMIC - in this mode distributed transactions and distributed locking are not supported</li> <li>TRANSACTIONAL - in this mode specified fully ACID-compliant transactional cache behavior</li> <li>TRANSACTIONAL_SNAPSHOT - in this mode specified fully ACID-compliant transactional cache behavior for both key-value API and SQL transactions</li> </ul> `}, {name: 'Backups:', cellClass: 'pc-form-grid-col-10', tip: ` Number of nodes used to back up single partition for partitioned cache `} ]; } addCache() { this.ConfigureState.dispatchAction({type: 'ADD_CACHE_TO_EDIT'}); } removeCache(cache) { this.ConfigureState.dispatchAction( removeClusterItems(this.$uiRouter.globals.params.clusterID, 'caches', [cache._id], false, false) ); } changeCache(cache) { return this.ConfigureState.dispatchAction(changeItem('caches', cache)); } save(download = false) { if (this.form.$invalid) return this.IgniteFormUtils.triggerValidation(this.form, this.$scope); this.ConfigureState.dispatchAction((download ? basicSaveAndDownload : basicSave)(cloneDeep(this.clonedCluster))); } reset() { this.clonedCluster = cloneDeep(this.originalCluster); this.ConfigureState.dispatchAction({type: 'RESET_EDIT_CHANGES'}); } confirmAndReset() { return this.Confirm.confirm('Are you sure you want to undo all changes for current cluster?') .then(() => this.reset()) .catch(() => {}); } }