1
0
Files
yel-dspace-angular/src/app/core/data/object-updates/object-updates.effects.ts
Kristof De Langhe a054938d80 Merge branch 'master' into w2p-68346_Bundles-in-edit-item-Updates
Conflicts:
	package.json
	src/app/+item-page/item-page-routing.module.ts
	src/app/core/cache/builders/remote-data-build.service.ts
	src/app/core/cache/server-sync-buffer.effects.ts
	src/app/core/core.module.ts
	src/app/core/data/bitstream-data.service.ts
	src/app/core/data/bundle-data.service.ts
	src/app/core/data/data.service.ts
	src/app/core/data/dso-change-analyzer.service.ts
	src/app/core/data/item-data.service.ts
	src/app/core/data/object-updates/object-updates.actions.ts
	src/app/core/shared/bitstream.model.ts
	src/app/core/shared/dspace-object.model.ts
	src/app/shared/mocks/mock-request.service.ts
	src/app/shared/shared.module.ts
	yarn.lock
2020-03-05 17:21:38 +01:00

142 lines
5.6 KiB
TypeScript

import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import {
DiscardObjectUpdatesAction,
ObjectUpdatesAction,
ObjectUpdatesActionTypes, RemoveAllObjectUpdatesAction,
RemoveObjectUpdatesAction
} from './object-updates.actions';
import { delay, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { of as observableOf, race as observableRace, Subject } from 'rxjs';
import { hasNoValue, hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { INotification } from '../../../shared/notifications/models/notification.model';
import {
NotificationsActions,
NotificationsActionTypes,
RemoveNotificationAction
} from '../../../shared/notifications/notifications.actions';
import { Action } from '@ngrx/store';
/**
* NGRX effects for ObjectUpdatesActions
*/
@Injectable()
export class ObjectUpdatesEffects {
/**
* Identifier for when an action on all notifications is performed
*/
private allIdentifier = 'all';
/**
* Map that keeps track of the latest ObjectUpdatesAction for each page's url
*/
private actionMap$: {
/* Use Subject instead of BehaviorSubject:
we only want Actions that are fired while we're listening
actions that were previously fired do not matter anymore
*/
[url: string]: Subject<ObjectUpdatesAction>
} = {};
private notificationActionMap$: {
/* Use Subject instead of BehaviorSubject:
we only want Actions that are fired while we're listening
actions that were previously fired do not matter anymore
*/
[id: string]: Subject<NotificationsActions>
} = { all: new Subject() };
/**
* Effect that makes sure all last fired ObjectUpdatesActions are stored in the map of this service, with the url as their key
*/
@Effect({ dispatch: false }) mapLastActions$ = this.actions$
.pipe(
ofType(...Object.values(ObjectUpdatesActionTypes)),
map((action: ObjectUpdatesAction) => {
if (hasValue((action as any).payload)) {
const url: string = (action as any).payload.url;
if (hasNoValue(this.actionMap$[url])) {
this.actionMap$[url] = new Subject<ObjectUpdatesAction>();
}
this.actionMap$[url].next(action);
}
})
);
/**
* Effect that makes sure all last fired NotificationActions are stored in the notification map of this service, with the id as their key
*/
@Effect({ dispatch: false }) mapLastNotificationActions$ = this.actions$
.pipe(
ofType(...Object.values(NotificationsActionTypes)),
map((action: RemoveNotificationAction) => {
const id: string = action.payload.id || action.payload || this.allIdentifier;
if (hasNoValue(this.notificationActionMap$[id])) {
this.notificationActionMap$[id] = new Subject<NotificationsActions>();
}
this.notificationActionMap$[id].next(action);
}
)
);
/**
* Effect that checks whether the removeAction's notification timeout ends before a user triggers another ObjectUpdatesAction
* When no ObjectUpdatesAction is fired during the timeout, a RemoteObjectUpdatesAction will be returned
* When a REINSTATE action is fired during the timeout, a NO_ACTION action will be returned
* When any other ObjectUpdatesAction is fired during the timeout, a RemoteObjectUpdatesAction will be returned
*/
@Effect() removeAfterDiscardOrReinstateOnUndo$ = this.actions$
.pipe(
ofType(ObjectUpdatesActionTypes.DISCARD),
switchMap((action: DiscardObjectUpdatesAction) => {
const url: string = action.payload.url;
const notification: INotification = action.payload.notification;
const timeOut = notification.options.timeOut;
let removeAction: Action = new RemoveObjectUpdatesAction(action.payload.url);
if (action.payload.discardAll) {
removeAction = new RemoveAllObjectUpdatesAction();
}
return observableRace(
// Either wait for the delay and perform a remove action
observableOf(removeAction).pipe(delay(timeOut)),
// Or wait for a a user action
this.actionMap$[url].pipe(
take(1),
tap(() => {
this.notificationsService.remove(notification);
}),
map((updateAction: ObjectUpdatesAction) => {
if (updateAction.type === ObjectUpdatesActionTypes.REINSTATE) {
// If someone reinstated, do nothing, just let the reinstating happen
return { type: 'NO_ACTION' }
}
// If someone performed another action, assume the user does not want to reinstate and remove all changes
return removeAction
})
),
this.notificationActionMap$[notification.id].pipe(
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_NOTIFICATION),
map(() => {
return removeAction;
})
),
this.notificationActionMap$[this.allIdentifier].pipe(
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_ALL_NOTIFICATIONS),
map(() => {
return removeAction;
})
)
)
}
)
);
constructor(private actions$: Actions,
private notificationsService: NotificationsService) {
}
}