mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
65717: Ability to discard all field-updates at once (fixes discard and reinstate issues)
This commit is contained in:
@@ -157,13 +157,8 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
|
|||||||
* Shows a notification to remind the user that they can undo this
|
* Shows a notification to remind the user that they can undo this
|
||||||
*/
|
*/
|
||||||
discard() {
|
discard() {
|
||||||
super.discard();
|
|
||||||
const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), {timeOut: this.discardTimeOut});
|
const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), {timeOut: this.discardTimeOut});
|
||||||
this.bundles$.pipe(take(1)).subscribe((bundles: Bundle[]) => {
|
this.objectUpdatesService.discardAllFieldUpdates(this.url, undoNotification);
|
||||||
bundles.forEach((bundle: Bundle) => {
|
|
||||||
this.objectUpdatesService.discardFieldUpdates(bundle.self, undoNotification);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -26,6 +26,11 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() bundle: Bundle;
|
@Input() bundle: Bundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current url of this page
|
||||||
|
*/
|
||||||
|
@Input() url: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The updates to the current bundle
|
* The updates to the current bundle
|
||||||
*/
|
*/
|
||||||
|
@@ -14,6 +14,7 @@ export const ObjectUpdatesActionTypes = {
|
|||||||
DISCARD: type('dspace/core/cache/object-updates/DISCARD'),
|
DISCARD: type('dspace/core/cache/object-updates/DISCARD'),
|
||||||
REINSTATE: type('dspace/core/cache/object-updates/REINSTATE'),
|
REINSTATE: type('dspace/core/cache/object-updates/REINSTATE'),
|
||||||
REMOVE: type('dspace/core/cache/object-updates/REMOVE'),
|
REMOVE: type('dspace/core/cache/object-updates/REMOVE'),
|
||||||
|
REMOVE_ALL: type('dspace/core/cache/object-updates/REMOVE_ALL'),
|
||||||
REMOVE_FIELD: type('dspace/core/cache/object-updates/REMOVE_FIELD'),
|
REMOVE_FIELD: type('dspace/core/cache/object-updates/REMOVE_FIELD'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -144,7 +145,8 @@ export class DiscardObjectUpdatesAction implements Action {
|
|||||||
type = ObjectUpdatesActionTypes.DISCARD;
|
type = ObjectUpdatesActionTypes.DISCARD;
|
||||||
payload: {
|
payload: {
|
||||||
url: string,
|
url: string,
|
||||||
notification: INotification
|
notification: INotification,
|
||||||
|
discardAll: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,12 +155,14 @@ export class DiscardObjectUpdatesAction implements Action {
|
|||||||
* @param url
|
* @param url
|
||||||
* the unique url of the page for which the changes should be discarded
|
* the unique url of the page for which the changes should be discarded
|
||||||
* @param notification The notification that is raised when changes are discarded
|
* @param notification The notification that is raised when changes are discarded
|
||||||
|
* @param discardAll discard all
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
url: string,
|
url: string,
|
||||||
notification: INotification
|
notification: INotification,
|
||||||
|
discardAll = false
|
||||||
) {
|
) {
|
||||||
this.payload = { url, notification };
|
this.payload = { url, notification, discardAll };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +210,13 @@ export class RemoveObjectUpdatesAction implements Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ngrx action to remove all previously discarded updates in the ObjectUpdates state
|
||||||
|
*/
|
||||||
|
export class RemoveAllObjectUpdatesAction implements Action {
|
||||||
|
type = ObjectUpdatesActionTypes.REMOVE_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ngrx action to remove a single field update in the ObjectUpdates state for a certain page url and field uuid
|
* An ngrx action to remove a single field update in the ObjectUpdates state for a certain page url and field uuid
|
||||||
*/
|
*/
|
||||||
|
@@ -3,12 +3,12 @@ import { Actions, Effect, ofType } from '@ngrx/effects';
|
|||||||
import {
|
import {
|
||||||
DiscardObjectUpdatesAction,
|
DiscardObjectUpdatesAction,
|
||||||
ObjectUpdatesAction,
|
ObjectUpdatesAction,
|
||||||
ObjectUpdatesActionTypes,
|
ObjectUpdatesActionTypes, RemoveAllObjectUpdatesAction,
|
||||||
RemoveObjectUpdatesAction
|
RemoveObjectUpdatesAction
|
||||||
} from './object-updates.actions';
|
} from './object-updates.actions';
|
||||||
import { delay, filter, map, switchMap, take, tap } from 'rxjs/operators';
|
import { delay, filter, map, switchMap, take, tap } from 'rxjs/operators';
|
||||||
import { of as observableOf, race as observableRace, Subject } from 'rxjs';
|
import { of as observableOf, race as observableRace, Subject } from 'rxjs';
|
||||||
import { hasNoValue } from '../../../shared/empty.util';
|
import { hasNoValue, hasValue } from '../../../shared/empty.util';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
import { INotification } from '../../../shared/notifications/models/notification.model';
|
import { INotification } from '../../../shared/notifications/models/notification.model';
|
||||||
import {
|
import {
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
NotificationsActionTypes,
|
NotificationsActionTypes,
|
||||||
RemoveNotificationAction
|
RemoveNotificationAction
|
||||||
} from '../../../shared/notifications/notifications.actions';
|
} from '../../../shared/notifications/notifications.actions';
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NGRX effects for ObjectUpdatesActions
|
* NGRX effects for ObjectUpdatesActions
|
||||||
@@ -53,13 +54,14 @@ export class ObjectUpdatesEffects {
|
|||||||
.pipe(
|
.pipe(
|
||||||
ofType(...Object.values(ObjectUpdatesActionTypes)),
|
ofType(...Object.values(ObjectUpdatesActionTypes)),
|
||||||
map((action: ObjectUpdatesAction) => {
|
map((action: ObjectUpdatesAction) => {
|
||||||
|
if (hasValue(action.payload)) {
|
||||||
const url: string = action.payload.url;
|
const url: string = action.payload.url;
|
||||||
if (hasNoValue(this.actionMap$[url])) {
|
if (hasNoValue(this.actionMap$[url])) {
|
||||||
this.actionMap$[url] = new Subject<ObjectUpdatesAction>();
|
this.actionMap$[url] = new Subject<ObjectUpdatesAction>();
|
||||||
}
|
}
|
||||||
this.actionMap$[url].next(action);
|
this.actionMap$[url].next(action);
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,9 +93,15 @@ export class ObjectUpdatesEffects {
|
|||||||
const url: string = action.payload.url;
|
const url: string = action.payload.url;
|
||||||
const notification: INotification = action.payload.notification;
|
const notification: INotification = action.payload.notification;
|
||||||
const timeOut = notification.options.timeOut;
|
const timeOut = notification.options.timeOut;
|
||||||
|
|
||||||
|
let removeAction: Action = new RemoveObjectUpdatesAction(action.payload.url);
|
||||||
|
if (action.payload.discardAll) {
|
||||||
|
removeAction = new RemoveAllObjectUpdatesAction();
|
||||||
|
}
|
||||||
|
|
||||||
return observableRace(
|
return observableRace(
|
||||||
// Either wait for the delay and perform a remove action
|
// Either wait for the delay and perform a remove action
|
||||||
observableOf(new RemoveObjectUpdatesAction(action.payload.url)).pipe(delay(timeOut)),
|
observableOf(removeAction).pipe(delay(timeOut)),
|
||||||
// Or wait for a a user action
|
// Or wait for a a user action
|
||||||
this.actionMap$[url].pipe(
|
this.actionMap$[url].pipe(
|
||||||
take(1),
|
take(1),
|
||||||
@@ -106,19 +114,19 @@ export class ObjectUpdatesEffects {
|
|||||||
return { type: 'NO_ACTION' }
|
return { type: 'NO_ACTION' }
|
||||||
}
|
}
|
||||||
// If someone performed another action, assume the user does not want to reinstate and remove all changes
|
// If someone performed another action, assume the user does not want to reinstate and remove all changes
|
||||||
return new RemoveObjectUpdatesAction(action.payload.url);
|
return removeAction
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
this.notificationActionMap$[notification.id].pipe(
|
this.notificationActionMap$[notification.id].pipe(
|
||||||
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_NOTIFICATION),
|
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_NOTIFICATION),
|
||||||
map(() => {
|
map(() => {
|
||||||
return new RemoveObjectUpdatesAction(action.payload.url);
|
return removeAction;
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
this.notificationActionMap$[this.allIdentifier].pipe(
|
this.notificationActionMap$[this.allIdentifier].pipe(
|
||||||
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_ALL_NOTIFICATIONS),
|
filter((notificationsAction: NotificationsActions) => notificationsAction.type === NotificationsActionTypes.REMOVE_ALL_NOTIFICATIONS),
|
||||||
map(() => {
|
map(() => {
|
||||||
return new RemoveObjectUpdatesAction(action.payload.url);
|
return removeAction;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@@ -105,6 +105,9 @@ export function objectUpdatesReducer(state = initialState, action: ObjectUpdates
|
|||||||
case ObjectUpdatesActionTypes.REMOVE: {
|
case ObjectUpdatesActionTypes.REMOVE: {
|
||||||
return removeObjectUpdates(state, action as RemoveObjectUpdatesAction);
|
return removeObjectUpdates(state, action as RemoveObjectUpdatesAction);
|
||||||
}
|
}
|
||||||
|
case ObjectUpdatesActionTypes.REMOVE_ALL: {
|
||||||
|
return removeAllObjectUpdates(state);
|
||||||
|
}
|
||||||
case ObjectUpdatesActionTypes.REMOVE_FIELD: {
|
case ObjectUpdatesActionTypes.REMOVE_FIELD: {
|
||||||
return removeFieldUpdate(state, action as RemoveFieldUpdateAction);
|
return removeFieldUpdate(state, action as RemoveFieldUpdateAction);
|
||||||
}
|
}
|
||||||
@@ -175,7 +178,24 @@ function addFieldUpdate(state: any, action: AddFieldUpdateAction) {
|
|||||||
* @param action The action to perform on the current state
|
* @param action The action to perform on the current state
|
||||||
*/
|
*/
|
||||||
function discardObjectUpdates(state: any, action: DiscardObjectUpdatesAction) {
|
function discardObjectUpdates(state: any, action: DiscardObjectUpdatesAction) {
|
||||||
|
if (action.payload.discardAll) {
|
||||||
|
let newState = Object.assign({}, state);
|
||||||
|
Object.keys(state).filter((path: string) => !path.endsWith(OBJECT_UPDATES_TRASH_PATH)).forEach((path: string) => {
|
||||||
|
newState = discardObjectUpdatesFor(path, newState);
|
||||||
|
});
|
||||||
|
return newState;
|
||||||
|
} else {
|
||||||
const url: string = action.payload.url;
|
const url: string = action.payload.url;
|
||||||
|
return discardObjectUpdatesFor(url, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard all updates for a specific action's url in the store
|
||||||
|
* @param url The action's url
|
||||||
|
* @param state The current state
|
||||||
|
*/
|
||||||
|
function discardObjectUpdatesFor(url: string, state: any) {
|
||||||
const pageState: ObjectUpdatesEntry = state[url];
|
const pageState: ObjectUpdatesEntry = state[url];
|
||||||
const newFieldStates = {};
|
const newFieldStates = {};
|
||||||
Object.keys(pageState.fieldStates).forEach((uuid: string) => {
|
Object.keys(pageState.fieldStates).forEach((uuid: string) => {
|
||||||
@@ -228,6 +248,18 @@ function removeObjectUpdatesByURL(state: any, url: string) {
|
|||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all updates in the store
|
||||||
|
* @param state The current state
|
||||||
|
*/
|
||||||
|
function removeAllObjectUpdates(state: any) {
|
||||||
|
const newState = Object.assign({}, state);
|
||||||
|
Object.keys(state).filter((path: string) => path.endsWith(OBJECT_UPDATES_TRASH_PATH)).forEach((path: string) => {
|
||||||
|
delete newState[path];
|
||||||
|
});
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard the update for a specific action's url and field UUID in the store
|
* Discard the update for a specific action's url and field UUID in the store
|
||||||
* @param state The current state
|
* @param state The current state
|
||||||
|
@@ -225,6 +225,15 @@ export class ObjectUpdatesService {
|
|||||||
this.store.dispatch(new DiscardObjectUpdatesAction(url, undoNotification));
|
this.store.dispatch(new DiscardObjectUpdatesAction(url, undoNotification));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to dispatch a DiscardObjectUpdatesAction to the store with discardAll set to true
|
||||||
|
* @param url The page's URL for which the changes should be discarded
|
||||||
|
* @param undoNotification The notification which is should possibly be canceled
|
||||||
|
*/
|
||||||
|
discardAllFieldUpdates(url: string, undoNotification: INotification) {
|
||||||
|
this.store.dispatch(new DiscardObjectUpdatesAction(url, undoNotification, true));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to dispatch an ReinstateObjectUpdatesAction to the store
|
* Method to dispatch an ReinstateObjectUpdatesAction to the store
|
||||||
* @param url The page's URL for which the changes should be reinstated
|
* @param url The page's URL for which the changes should be reinstated
|
||||||
|
Reference in New Issue
Block a user