exhaustMap((a) => { if (!(a.ids || []).length) { return of( {type: shortModelsActionTypes.UPSERT, items: []}, {type: `${a.type}_OK`} ); } return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectShortModels(), take(1), switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) return of({type: `${a.type}_OK`}); return from(this.Clusters.getClusterModels(a.clusterID)).pipe( switchMap(({data}) => of( {type: shortModelsActionTypes.UPSERT, items: data}, {type: `${a.type}_OK`} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load domain models: ${error.data}.` }, action: a })) ); })
switchMap(([action, edit]) => { const changedItems = _applyChangedIDs(edit, {cluster: action.cluster}); const actions = [{ type: cachesActionTypes.UPSERT, items: changedItems.caches }, { type: shortCachesActionTypes.UPSERT, items: changedItems.caches }, { type: clustersActionTypes.UPSERT, items: [changedItems.cluster] }, { type: shortClustersActionTypes.UPSERT, items: [this.Clusters.toShortCluster(changedItems.cluster)] } ].filter((a) => a.items.length); return merge( of(...actions), from(this.Clusters.saveBasic(changedItems)).pipe( switchMap((res) => of( {type: 'EDIT_CLUSTER', cluster: changedItems.cluster}, basicSaveOK(changedItems) )), catchError((res) => of( basicSaveErr(changedItems, res), {type: 'UNDO_ACTIONS', actions} )) ) ); })
switchMap((cache) => { if (cache) return of({type: `${a.type}_OK`, cache}); return from(this.Caches.getCache(a.cacheID)).pipe( switchMap(({data}) => of( {type: 'CACHE', cache: data}, {type: `${a.type}_OK`, cache: data} )) ); }),
switchMap((igfs) => { if (igfs) return of({type: `${a.type}_OK`, igfs}); return from(this.IGFSs.getIGFS(a.igfsID)).pipe( switchMap(({data}) => of( {type: 'IGFS', igfs: data}, {type: `${a.type}_OK`, igfs: data} )) ); }),
switchMap((model) => { if (model) return of({type: `${a.type}_OK`, model}); return from(this.Models.getModel(a.modelID)).pipe( switchMap(({data}) => of( {type: 'MODEL', model: data}, {type: `${a.type}_OK`, model: data} )) ); }),
switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) return of({type: `${a.type}_OK`}); return from(this.Clusters.getClusterModels(a.clusterID)).pipe( switchMap(({data}) => of( {type: shortModelsActionTypes.UPSERT, items: data}, {type: `${a.type}_OK`} )) ); }),
exhaustMap((action) => { return from(this.Clusters.getConfiguration(action.clusterID)).pipe( switchMap(({data}) => of( completeConfiguration(data), {type: 'LOAD_COMPLETE_CONFIGURATION_OK', data} )), catchError((error) => of({ type: 'LOAD_COMPLETE_CONFIGURATION_ERR', error: { message: `Failed to load cluster configuration: ${error.data}.` }, action }))); })
exhaustMap((a) => { return from(this.Clusters.getClustersOverview()).pipe( switchMap(({data}) => of( {type: shortClustersActionTypes.SET, items: data}, {type: `${a.type}_OK`} )), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load clusters: ${error.data}` }, action: a })) ); })
componentFromStream(props$ => { const id$ = props$.pipe( map(props => props.params.id), distinctUntilChanged() ); const job$ = id$.pipe( switchMap(id => getGraphQL(id)), map(({ data: { job } }) => job) ); return combineLatest([ job$, props$, jobActionDialog$, disabledDialog$ ]).pipe( map(([job, { router, ...props }, jobActionDialog, disabledDialog]) => { function onJobDeleteSuccess() { router.push("/jobs"); closeDialog(); } return ( <JobDetailPage {...props} job={job} jobActionDialog={jobActionDialog} disabledDialog={disabledDialog} errorMsg={null} handleDestroyButtonClick={handleDestroyButtonClick} handleEditButtonClick={handleEditButtonClick} onJobDeleteSuccess={onJobDeleteSuccess} closeDialog={closeDialog} disableDialog={disableDialog} /> ); }), catchError(() => of(<ErrorScreen />)), startWith(<LoadingScreen />) ); })
switchMap((cluster) => { if (cluster) { return of( {type: 'EDIT_CLUSTER', cluster}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} ); } return from(this.Clusters.getCluster(a.clusterID)).pipe( switchMap(({data}) => of( {type: clustersActionTypes.UPSERT, items: [data]}, {type: 'EDIT_CLUSTER', cluster: data}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} )), catchError((error) => of({ type: 'LOAD_AND_EDIT_CLUSTER_ERR', error: { message: `Failed to load cluster: ${error.data}.` } })) ); })
exhaustMap(([a, shortClusters]) => { if (a.clusterID === 'new') { return of( { type: 'EDIT_CLUSTER', cluster: { ...this.Clusters.getBlankCluster(), name: uniqueName(defaultNames.cluster, shortClusters) } }, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} ); } return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectCluster(a.clusterID), take(1), switchMap((cluster) => { if (cluster) { return of( {type: 'EDIT_CLUSTER', cluster}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} ); } return from(this.Clusters.getCluster(a.clusterID)).pipe( switchMap(({data}) => of( {type: clustersActionTypes.UPSERT, items: [data]}, {type: 'EDIT_CLUSTER', cluster: data}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} )), catchError((error) => of({ type: 'LOAD_AND_EDIT_CLUSTER_ERR', error: { message: `Failed to load cluster: ${error.data}.` } })) ); }) ); })
exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectIGFS(a.igfsID), take(1), switchMap((igfs) => { if (igfs) return of({type: `${a.type}_OK`, igfs}); return from(this.IGFSs.getIGFS(a.igfsID)).pipe( switchMap(({data}) => of( {type: 'IGFS', igfs: data}, {type: `${a.type}_OK`, igfs: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load IGFS: ${error.data}.` } })) ); })
exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectModel(a.modelID), take(1), switchMap((model) => { if (model) return of({type: `${a.type}_OK`, model}); return from(this.Models.getModel(a.modelID)).pipe( switchMap(({data}) => of( {type: 'MODEL', model: data}, {type: `${a.type}_OK`, model: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load domain model: ${error.data}.` } })) ); })
exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectCache(a.cacheID), take(1), switchMap((cache) => { if (cache) return of({type: `${a.type}_OK`, cache}); return from(this.Caches.getCache(a.cacheID)).pipe( switchMap(({data}) => of( {type: 'CACHE', cache: data}, {type: `${a.type}_OK`, cache: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load cache: ${error.data}.` } })) ); })
const removePackageRepositoryGraphql = (name, uri) => dataLayer.query(removePackageRepository, { name, uri }); const deleteEvent$ = new Subject(); const deleteRepository$ = deleteEvent$.pipe( switchMap(repository => { return removePackageRepositoryGraphql(repository.name, repository.url).pipe( startWith({ pendingRequest: true }), map(result => { return { result, pendingRequest: false }; }), tap(() => { repository.complete(); }) ); }), startWith({ pendingRequest: false }), catchError(error => { return deleteRepository$.pipe( startWith({ error: getErrorMessage(error.response), pendingRequest: false }) ); })
componentDidMount(): void { const { editorFocused, kernelStatus, focusAbove, focusBelow } = this.props; require("codemirror/addon/hint/show-hint"); require("codemirror/addon/hint/anyword-hint"); require("codemirror/addon/edit/matchbrackets"); require("codemirror/addon/edit/closebrackets"); require("codemirror/addon/comment/comment.js"); require("codemirror/mode/python/python"); require("codemirror/mode/ruby/ruby"); require("codemirror/mode/javascript/javascript"); require("codemirror/mode/css/css"); require("codemirror/mode/julia/julia"); require("codemirror/mode/r/r"); require("codemirror/mode/clike/clike"); require("codemirror/mode/shell/shell"); require("codemirror/mode/sql/sql"); require("codemirror/mode/markdown/markdown"); require("codemirror/mode/gfm/gfm"); require("./mode/ipython"); this.cm = require("codemirror").fromTextArea( this.textarea, this.defaultOptions ); this.cm.setValue(this.props.defaultValue || this.props.value || ""); // On first load, if focused, set codemirror to focus if (editorFocused) { this.cm.focus(); } this.cm.on("topBoundary", focusAbove); this.cm.on("bottomBoundary", focusBelow); this.cm.on("focus", this.focusChanged.bind(this, true)); this.cm.on("blur", this.focusChanged.bind(this, false)); this.cm.on("change", this.codemirrorValueChanged.bind(this)); const keyupEvents = fromEvent(this.cm, "keyup", (editor, ev) => ({ editor, ev })); this.keyupEventsSubscriber = keyupEvents .pipe(switchMap(i => of(i))) .subscribe(({ editor, ev }) => { const cursor = editor.getDoc().getCursor(); const token = editor.getTokenAt(cursor); if ( !editor.state.completionActive && !excludedIntelliSenseTriggerKeys[ (ev.keyCode || ev.which).toString() ] && (token.type === "tag" || token.type === "variable" || token.string === " " || token.string === "<" || token.string === "/") && kernelStatus === "idle" ) { editor.execCommand("autocomplete", { completeSingle: false }); } }); }
switchMap(() => { const frameReady = new Subject(); const consoleProxy = new Subject(); const frameTests = createTestFramer( document, state$, frameReady, consoleProxy ); const challengeResults = frameReady.pipe( // Delay for jQuery ready code, in jQuery challenges delay(250), pluck('checkChallengePayload'), map(checkChallengePayload => ({ checkChallengePayload, tests: challengeTestsSelector(state$.value) })), switchMap(({ checkChallengePayload, tests }) => { const postTests = of( updateConsole('// tests completed'), logsToConsole('// console output'), checkChallenge(checkChallengePayload) ).pipe(delay(250)); return runTestsInTestFrame(document, tests).pipe( switchMap(tests => { return from(tests).pipe( map(({ message }) => message), filter(overEvery(isString, Boolean)), map(updateConsole), concat(of(updateTests(tests))) ); }), concat(postTests) ); }) ); const buildAndFrameChallenge = action$.pipe( ofType(types.executeChallenge), filter(() => { const { challengeType } = challengeMetaSelector(state$.value); return ( challengeType !== challengeTypes.js && challengeType !== challengeTypes.bonfire ); }), debounceTime(executeDebounceTimeout), filter(() => isJSEnabledSelector(state$.value)), switchMap(() => { const state = state$.value; const { challengeType } = challengeMetaSelector(state); const build = challengeType === challengeTypes.backend ? buildBackendChallenge : buildFromFiles; return build(state).pipe( tap(frameTests), ignoreElements(), startWith(initLogs()), startWith(initConsole('// running tests')), catchError(err => { console.error(err); return of(disableJSOnError(err)); }) ); }) ); const proxyConsole = consoleProxy.pipe(map(updateLogs)); return merge(buildAndFrameChallenge, challengeResults, proxyConsole); })
const handler = (argument, context) => { return rxjs_1.from(loader()) .pipe(operators_1.switchMap(fn => fn(argument, context))); };
switchMap((action) => { const actions = [ { type: modelsActionTypes.UPSERT, items: action.changedItems.models }, { type: shortModelsActionTypes.UPSERT, items: action.changedItems.models.map((m) => this.Models.toShortModel(m)) }, { type: igfssActionTypes.UPSERT, items: action.changedItems.igfss }, { type: shortIGFSsActionTypes.UPSERT, items: action.changedItems.igfss }, { type: cachesActionTypes.UPSERT, items: action.changedItems.caches }, { type: shortCachesActionTypes.UPSERT, items: action.changedItems.caches.map(Caches.toShortCache) }, { type: clustersActionTypes.UPSERT, items: [action.changedItems.cluster] }, { type: shortClustersActionTypes.UPSERT, items: [Clusters.toShortCluster(action.changedItems.cluster)] } ].filter((a) => a.items.length); return merge( of(...actions), from(Clusters.saveAdvanced(action.changedItems)).pipe( switchMap((res) => { return of( {type: 'EDIT_CLUSTER', cluster: action.changedItems.cluster}, {type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_OK', changedItems: action.changedItems} ); }), catchError((res) => { return of({ type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_ERR', changedItems: action.changedItems, action, error: { message: `Failed to save cluster "${action.changedItems.cluster.name}": ${res.data}.` } }, { type: 'UNDO_ACTIONS', actions }); }) ) ); })
export const launchKernelEpic = ( action$: ActionsObservable<redux$Action>, state$: StateObservable<AppState> ): Observable<redux$Action> => action$.pipe( ofType(actions.LAUNCH_KERNEL), // We must kill the previous kernel now // Then launch the next one switchMap((action: actions.LaunchKernelAction) => { if ( !action.payload || !action.payload.kernelSpec || !action.payload.kernelRef ) { return of( actions.launchKernelFailed({ error: new Error("launchKernel needs a kernelSpec and a kernelRef"), kernelRef: action.payload && action.payload.kernelRef, contentRef: action.payload.contentRef }) ); } // TODO: Do the async version of `ipc.send`, potentially coordinate with main process ipc.send("nteract:ping:kernel", action.payload.kernelSpec); const oldKernelRef = selectors.currentKernelRef(state$.value); // Kill the old kernel by emitting the action to kill it if it exists let cleanupOldKernel$ = empty(); if (oldKernelRef && oldKernelRef !== action.payload.kernelRef) { cleanupOldKernel$ = of( actions.killKernel({ restarting: false, kernelRef: oldKernelRef }) ); } return merge( launchKernelObservable( action.payload.kernelSpec, action.payload.cwd, action.payload.kernelRef, action.payload.contentRef ), // Was there a kernel before (?) -- kill it if so, otherwise nothing else cleanupOldKernel$ ).pipe( catchError((error: Error) => of( actions.launchKernelFailed({ error, kernelRef: action.payload.kernelRef, contentRef: action.payload.contentRef }) ) ) ); }), // TODO: ask @jayphelps about `merge(of(errorAction), source)` replaying the // original action catchError((error: Error) => { return of({ type: "ERROR", payload: error, error: true }); }) );
/** * @param {ConfigureState} ConfigureState * @param {Caches} Caches * @param {IGFSs} IGFSs * @param {Models} Models * @param {ConfigSelectors} ConfigSelectors * @param {Clusters} Clusters * @param {object} $state * @param {object} IgniteMessages * @param {object} IgniteConfirm * @param {Confirm} Confirm * @param {ConfigurationDownload} ConfigurationDownload */ constructor(ConfigureState, Caches, IGFSs, Models, ConfigSelectors, Clusters, $state, IgniteMessages, IgniteConfirm, Confirm, ConfigurationDownload) { this.ConfigureState = ConfigureState; this.ConfigSelectors = ConfigSelectors; this.IGFSs = IGFSs; this.Models = Models; this.Caches = Caches; this.Clusters = Clusters; this.$state = $state; this.IgniteMessages = IgniteMessages; this.IgniteConfirm = IgniteConfirm; this.Confirm = Confirm; this.configurationDownload = ConfigurationDownload; this.loadConfigurationEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_COMPLETE_CONFIGURATION'), exhaustMap((action) => { return from(this.Clusters.getConfiguration(action.clusterID)).pipe( switchMap(({data}) => of( completeConfiguration(data), {type: 'LOAD_COMPLETE_CONFIGURATION_OK', data} )), catchError((error) => of({ type: 'LOAD_COMPLETE_CONFIGURATION_ERR', error: { message: `Failed to load cluster configuration: ${error.data}.` }, action }))); }) ); this.storeConfigurationEffect$ = this.ConfigureState.actions$.pipe( ofType(COMPLETE_CONFIGURATION), exhaustMap(({configuration: {cluster, caches, models, igfss}}) => of(...[ cluster && {type: clustersActionTypes.UPSERT, items: [cluster]}, caches && caches.length && {type: cachesActionTypes.UPSERT, items: caches}, models && models.length && {type: modelsActionTypes.UPSERT, items: models}, igfss && igfss.length && {type: igfssActionTypes.UPSERT, items: igfss} ].filter((v) => v))) ); this.saveCompleteConfigurationEffect$ = this.ConfigureState.actions$.pipe( ofType(ADVANCED_SAVE_COMPLETE_CONFIGURATION), switchMap((action) => { const actions = [ { type: modelsActionTypes.UPSERT, items: action.changedItems.models }, { type: shortModelsActionTypes.UPSERT, items: action.changedItems.models.map((m) => this.Models.toShortModel(m)) }, { type: igfssActionTypes.UPSERT, items: action.changedItems.igfss }, { type: shortIGFSsActionTypes.UPSERT, items: action.changedItems.igfss }, { type: cachesActionTypes.UPSERT, items: action.changedItems.caches }, { type: shortCachesActionTypes.UPSERT, items: action.changedItems.caches.map(Caches.toShortCache) }, { type: clustersActionTypes.UPSERT, items: [action.changedItems.cluster] }, { type: shortClustersActionTypes.UPSERT, items: [Clusters.toShortCluster(action.changedItems.cluster)] } ].filter((a) => a.items.length); return merge( of(...actions), from(Clusters.saveAdvanced(action.changedItems)).pipe( switchMap((res) => { return of( {type: 'EDIT_CLUSTER', cluster: action.changedItems.cluster}, {type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_OK', changedItems: action.changedItems} ); }), catchError((res) => { return of({ type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_ERR', changedItems: action.changedItems, action, error: { message: `Failed to save cluster "${action.changedItems.cluster.name}": ${res.data}.` } }, { type: 'UNDO_ACTIONS', actions }); }) ) ); }) ); this.addCacheToEditEffect$ = this.ConfigureState.actions$.pipe( ofType('ADD_CACHE_TO_EDIT'), switchMap(() => this.ConfigureState.state$.pipe(this.ConfigSelectors.selectCacheToEdit('new'), take(1))), map((cache) => ({type: 'UPSERT_CLUSTER_ITEM', itemType: 'caches', item: cache})) ); this.errorNotificationsEffect$ = this.ConfigureState.actions$.pipe( filter((a) => a.error), tap((action) => this.IgniteMessages.showError(action.error)), ignoreElements() ); this.loadUserClustersEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_USER_CLUSTERS'), exhaustMap((a) => { return from(this.Clusters.getClustersOverview()).pipe( switchMap(({data}) => of( {type: shortClustersActionTypes.SET, items: data}, {type: `${a.type}_OK`} )), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load clusters: ${error.data}` }, action: a })) ); }) ); this.loadAndEditClusterEffect$ = ConfigureState.actions$.pipe( ofType('LOAD_AND_EDIT_CLUSTER'), withLatestFrom(this.ConfigureState.state$.pipe(this.ConfigSelectors.selectShortClustersValue())), exhaustMap(([a, shortClusters]) => { if (a.clusterID === 'new') { return of( { type: 'EDIT_CLUSTER', cluster: { ...this.Clusters.getBlankCluster(), name: uniqueName(defaultNames.cluster, shortClusters) } }, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} ); } return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectCluster(a.clusterID), take(1), switchMap((cluster) => { if (cluster) { return of( {type: 'EDIT_CLUSTER', cluster}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} ); } return from(this.Clusters.getCluster(a.clusterID)).pipe( switchMap(({data}) => of( {type: clustersActionTypes.UPSERT, items: [data]}, {type: 'EDIT_CLUSTER', cluster: data}, {type: 'LOAD_AND_EDIT_CLUSTER_OK'} )), catchError((error) => of({ type: 'LOAD_AND_EDIT_CLUSTER_ERR', error: { message: `Failed to load cluster: ${error.data}.` } })) ); }) ); }) ); this.loadCacheEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_CACHE'), exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectCache(a.cacheID), take(1), switchMap((cache) => { if (cache) return of({type: `${a.type}_OK`, cache}); return from(this.Caches.getCache(a.cacheID)).pipe( switchMap(({data}) => of( {type: 'CACHE', cache: data}, {type: `${a.type}_OK`, cache: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load cache: ${error.data}.` } })) ); }) ); this.storeCacheEffect$ = this.ConfigureState.actions$.pipe( ofType('CACHE'), map((a) => ({type: cachesActionTypes.UPSERT, items: [a.cache]})) ); this.loadShortCachesEffect$ = ConfigureState.actions$.pipe( ofType('LOAD_SHORT_CACHES'), exhaustMap((a) => { if (!(a.ids || []).length) return of({type: `${a.type}_OK`}); return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectShortCaches(), take(1), switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) return of({type: `${a.type}_OK`}); return from(this.Clusters.getClusterCaches(a.clusterID)).pipe( switchMap(({data}) => of( {type: shortCachesActionTypes.UPSERT, items: data}, {type: `${a.type}_OK`} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load caches: ${error.data}.` }, action: a })) ); }) ); this.loadIgfsEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_IGFS'), exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectIGFS(a.igfsID), take(1), switchMap((igfs) => { if (igfs) return of({type: `${a.type}_OK`, igfs}); return from(this.IGFSs.getIGFS(a.igfsID)).pipe( switchMap(({data}) => of( {type: 'IGFS', igfs: data}, {type: `${a.type}_OK`, igfs: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load IGFS: ${error.data}.` } })) ); }) ); this.storeIgfsEffect$ = this.ConfigureState.actions$.pipe( ofType('IGFS'), map((a) => ({type: igfssActionTypes.UPSERT, items: [a.igfs]})) ); this.loadShortIgfssEffect$ = ConfigureState.actions$.pipe( ofType('LOAD_SHORT_IGFSS'), exhaustMap((a) => { if (!(a.ids || []).length) { return of( {type: shortIGFSsActionTypes.UPSERT, items: []}, {type: `${a.type}_OK`} ); } return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectShortIGFSs(), take(1), switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) return of({type: `${a.type}_OK`}); return from(this.Clusters.getClusterIGFSs(a.clusterID)).pipe( switchMap(({data}) => of( {type: shortIGFSsActionTypes.UPSERT, items: data}, {type: `${a.type}_OK`} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load IGFSs: ${error.data}.` }, action: a })) ); }) ); this.loadModelEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_MODEL'), exhaustMap((a) => { return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectModel(a.modelID), take(1), switchMap((model) => { if (model) return of({type: `${a.type}_OK`, model}); return from(this.Models.getModel(a.modelID)).pipe( switchMap(({data}) => of( {type: 'MODEL', model: data}, {type: `${a.type}_OK`, model: data} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load domain model: ${error.data}.` } })) ); }) ); this.storeModelEffect$ = this.ConfigureState.actions$.pipe( ofType('MODEL'), map((a) => ({type: modelsActionTypes.UPSERT, items: [a.model]})) ); this.loadShortModelsEffect$ = this.ConfigureState.actions$.pipe( ofType('LOAD_SHORT_MODELS'), exhaustMap((a) => { if (!(a.ids || []).length) { return of( {type: shortModelsActionTypes.UPSERT, items: []}, {type: `${a.type}_OK`} ); } return this.ConfigureState.state$.pipe( this.ConfigSelectors.selectShortModels(), take(1), switchMap((items) => { if (!items.pristine && a.ids && a.ids.every((_id) => items.value.has(_id))) return of({type: `${a.type}_OK`}); return from(this.Clusters.getClusterModels(a.clusterID)).pipe( switchMap(({data}) => of( {type: shortModelsActionTypes.UPSERT, items: data}, {type: `${a.type}_OK`} )) ); }), catchError((error) => of({ type: `${a.type}_ERR`, error: { message: `Failed to load domain models: ${error.data}.` }, action: a })) ); }) ); this.basicSaveRedirectEffect$ = this.ConfigureState.actions$.pipe( ofType(BASIC_SAVE_OK), tap((a) => this.$state.go('base.configuration.edit.basic', {clusterID: a.changedItems.cluster._id}, {location: 'replace', custom: {justIDUpdate: true}})), ignoreElements() ); this.basicDownloadAfterSaveEffect$ = this.ConfigureState.actions$.pipe( ofType(BASIC_SAVE_AND_DOWNLOAD), zip(this.ConfigureState.actions$.pipe(ofType(BASIC_SAVE_OK))), pluck('1'), tap((a) => this.configurationDownload.downloadClusterConfiguration(a.changedItems.cluster)), ignoreElements() ); this.advancedDownloadAfterSaveEffect$ = merge( this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_CLUSTER)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_CACHE)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_IGFS)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_MODEL)), ).pipe( filter((a) => a.download), zip(this.ConfigureState.actions$.pipe(ofType('ADVANCED_SAVE_COMPLETE_CONFIGURATION_OK'))), pluck('1'), tap((a) => this.configurationDownload.downloadClusterConfiguration(a.changedItems.cluster)), ignoreElements() ); this.advancedSaveRedirectEffect$ = this.ConfigureState.actions$.pipe( ofType('ADVANCED_SAVE_COMPLETE_CONFIGURATION_OK'), withLatestFrom(this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_COMPLETE_CONFIGURATION))), pluck('1', 'changedItems'), map((req) => { const firstChangedItem = Object.keys(req).filter((k) => k !== 'cluster') .map((k) => Array.isArray(req[k]) ? [k, req[k][0]] : [k, req[k]]) .filter((v) => v[1]) .pop(); return firstChangedItem ? [...firstChangedItem, req.cluster] : ['cluster', req.cluster, req.cluster]; }), tap(([type, value, cluster]) => { 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}); 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}); 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}); 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); break; } default: break; } }), ignoreElements() ); this.removeClusterItemsEffect$ = this.ConfigureState.actions$.pipe( ofType(REMOVE_CLUSTER_ITEMS), exhaustMap((a) => { return a.confirm // TODO: list items to remove in confirmation ? from(this.Confirm.confirm('Are you sure you want to remove these items?')).pipe( mapTo(a), catchError(() => empty()) ) : of(a); }), map((a) => removeClusterItemsConfirmed(a.clusterID, a.itemType, a.itemIDs)) ); this.persistRemovedClusterItemsEffect$ = this.ConfigureState.actions$.pipe( ofType(REMOVE_CLUSTER_ITEMS_CONFIRMED), withLatestFrom(this.ConfigureState.actions$.pipe(ofType(REMOVE_CLUSTER_ITEMS))), filter(([a, b]) => { return a.itemType === b.itemType && b.save && JSON.stringify(a.itemIDs) === JSON.stringify(b.itemIDs); }), pluck('0'), withLatestFrom(this.ConfigureState.state$.pipe(pluck('edit'))), map(([action, edit]) => advancedSaveCompleteConfiguration(edit)) ); this.confirmClustersRemovalEffect$ = this.ConfigureState.actions$.pipe( ofType(CONFIRM_CLUSTERS_REMOVAL), pluck('clusterIDs'), switchMap((ids) => this.ConfigureState.state$.pipe( this.ConfigSelectors.selectClusterNames(ids), take(1) )), exhaustMap((names) => { return from(this.Confirm.confirm(` <p>Are you sure you want to remove these clusters?</p> <ul>${names.map((name) => `<li>${name}</li>`).join('')}</ul> `)).pipe( map(confirmClustersRemovalOK), catchError(() => empty()) ); }) ); this.persistRemovedClustersLocallyEffect$ = this.ConfigureState.actions$.pipe( ofType(CONFIRM_CLUSTERS_REMOVAL_OK), withLatestFrom(this.ConfigureState.actions$.pipe(ofType(CONFIRM_CLUSTERS_REMOVAL))), switchMap(([, {clusterIDs}]) => of( {type: shortClustersActionTypes.REMOVE, ids: clusterIDs}, {type: clustersActionTypes.REMOVE, ids: clusterIDs} )) ); this.persistRemovedClustersRemotelyEffect$ = this.ConfigureState.actions$.pipe( ofType(CONFIRM_CLUSTERS_REMOVAL_OK), withLatestFrom( this.ConfigureState.actions$.pipe(ofType(CONFIRM_CLUSTERS_REMOVAL)), this.ConfigureState.actions$.pipe(ofType(shortClustersActionTypes.REMOVE)), this.ConfigureState.actions$.pipe(ofType(clustersActionTypes.REMOVE)) ), switchMap(([, {clusterIDs}, ...backup]) => this.Clusters.removeCluster$(clusterIDs).pipe( mapTo({ type: 'REMOVE_CLUSTERS_OK' }), catchError((e) => of( { type: 'REMOVE_CLUSTERS_ERR', error: { message: `Failed to remove clusters: ${e.data}` } }, { type: 'UNDO_ACTIONS', actions: backup } )) )) ); this.notifyRemoteClustersRemoveSuccessEffect$ = this.ConfigureState.actions$.pipe( ofType('REMOVE_CLUSTERS_OK'), withLatestFrom(this.ConfigureState.actions$.pipe(ofType(CONFIRM_CLUSTERS_REMOVAL))), tap(([, {clusterIDs}]) => this.IgniteMessages.showInfo(`Cluster(s) removed: ${clusterIDs.length}`)), ignoreElements() ); const _applyChangedIDs = (edit, {cache, igfs, model, cluster} = {}) => ({ cluster: { ...edit.changes.cluster, ...(cluster ? cluster : {}), caches: cache ? uniq([...edit.changes.caches.ids, cache._id]) : edit.changes.caches.ids, igfss: igfs ? uniq([...edit.changes.igfss.ids, igfs._id]) : edit.changes.igfss.ids, models: model ? uniq([...edit.changes.models.ids, model._id]) : edit.changes.models.ids }, caches: cache ? uniq([...edit.changes.caches.changedItems, cache]) : edit.changes.caches.changedItems, igfss: igfs ? uniq([...edit.changes.igfss.changedItems, igfs]) : edit.changes.igfss.changedItems, models: model ? uniq([...edit.changes.models.changedItems, model]) : edit.changes.models.changedItems }); this.advancedSaveCacheEffect$ = merge( this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_CLUSTER)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_CACHE)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_IGFS)), this.ConfigureState.actions$.pipe(ofType(ADVANCED_SAVE_MODEL)), ).pipe( withLatestFrom(this.ConfigureState.state$.pipe(pluck('edit'))), map(([action, edit]) => ({ type: ADVANCED_SAVE_COMPLETE_CONFIGURATION, changedItems: _applyChangedIDs(edit, action) })) ); this.basicSaveEffect$ = merge( this.ConfigureState.actions$.pipe(ofType(BASIC_SAVE)), this.ConfigureState.actions$.pipe(ofType(BASIC_SAVE_AND_DOWNLOAD)) ).pipe( withLatestFrom(this.ConfigureState.state$.pipe(pluck('edit'))), switchMap(([action, edit]) => { const changedItems = _applyChangedIDs(edit, {cluster: action.cluster}); const actions = [{ type: cachesActionTypes.UPSERT, items: changedItems.caches }, { type: shortCachesActionTypes.UPSERT, items: changedItems.caches }, { type: clustersActionTypes.UPSERT, items: [changedItems.cluster] }, { type: shortClustersActionTypes.UPSERT, items: [this.Clusters.toShortCluster(changedItems.cluster)] } ].filter((a) => a.items.length); return merge( of(...actions), from(this.Clusters.saveBasic(changedItems)).pipe( switchMap((res) => of( {type: 'EDIT_CLUSTER', cluster: changedItems.cluster}, basicSaveOK(changedItems) )), catchError((res) => of( basicSaveErr(changedItems, res), {type: 'UNDO_ACTIONS', actions} )) ) ); }) ); this.basicSaveOKMessagesEffect$ = this.ConfigureState.actions$.pipe( ofType(BASIC_SAVE_OK), tap((action) => this.IgniteMessages.showInfo(`Cluster "${action.changedItems.cluster.name}" saved.`)), ignoreElements() ); }
const subscribeWhen = p$ => source => { if (process.env.DEBUG && !p$) throw Error(); return p$.pipe(switchMap(p => (p ? source : NEVER))); };
export const commListenEpic = (action$: ActionsObservable<*>) => action$.pipe( ofType(LAUNCH_KERNEL_SUCCESSFUL), switchMap(commActionObservable) ); // We have a new channel