forked from hazza/dspace-angular
65717: Move operations from custom order + sending bundle patch
This commit is contained in:
@@ -24,6 +24,9 @@ import { PaginatedSearchOptions } from '../../../+search-page/paginated-search-o
|
|||||||
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { Bitstream } from '../../../core/shared/bitstream.model';
|
import { Bitstream } from '../../../core/shared/bitstream.model';
|
||||||
import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
|
import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
|
||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
import { MoveOperation } from 'fast-json-patch/lib/core';
|
||||||
|
import { BundleDataService } from '../../../core/data/bundle-data.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-item-bitstreams',
|
selector: 'ds-item-bitstreams',
|
||||||
@@ -66,7 +69,8 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
|
|||||||
public bitstreamService: BitstreamDataService,
|
public bitstreamService: BitstreamDataService,
|
||||||
public objectCache: ObjectCacheService,
|
public objectCache: ObjectCacheService,
|
||||||
public requestService: RequestService,
|
public requestService: RequestService,
|
||||||
public cdRef: ChangeDetectorRef
|
public cdRef: ChangeDetectorRef,
|
||||||
|
public bundleService: BundleDataService
|
||||||
) {
|
) {
|
||||||
super(itemService, objectUpdatesService, router, notificationsService, translateService, EnvConfig, route);
|
super(itemService, objectUpdatesService, router, notificationsService, translateService, EnvConfig, route);
|
||||||
}
|
}
|
||||||
@@ -141,6 +145,19 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
|
|||||||
this.displayNotifications(responses);
|
this.displayNotifications(responses);
|
||||||
this.reset();
|
this.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.bundles$.pipe(take(1)).subscribe((bundles: Bundle[]) => {
|
||||||
|
bundles.forEach((bundle: Bundle) => {
|
||||||
|
this.objectUpdatesService.getMoveOperations(bundle.self).pipe(
|
||||||
|
take(1),
|
||||||
|
isNotEmptyOperator(),
|
||||||
|
map((operations: MoveOperation[]) => [...operations.map((operation: MoveOperation) => Object.assign(operation, {
|
||||||
|
from: `/_links/bitstreams${operation.from}/href`,
|
||||||
|
path: `/_links/bitstreams${operation.path}/href`
|
||||||
|
}))])
|
||||||
|
).subscribe((operations: Operation[]) => this.bundleService.patch(bundle.self, operations));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -104,9 +104,9 @@ export class ServerSyncBufferEffects {
|
|||||||
map((entry: ObjectCacheEntry) => {
|
map((entry: ObjectCacheEntry) => {
|
||||||
if (isNotEmpty(entry.patches)) {
|
if (isNotEmpty(entry.patches)) {
|
||||||
const flatPatch: Operation[] = [].concat(...entry.patches.map((patch) => patch.operations));
|
const flatPatch: Operation[] = [].concat(...entry.patches.map((patch) => patch.operations));
|
||||||
const metadataPatch = flatPatch.filter((op: Operation) => op.path.startsWith('/metadata'));
|
const objectPatch = flatPatch.filter((op: Operation) => op.path.startsWith('/metadata') || op.op === 'move');
|
||||||
if (isNotEmpty(metadataPatch)) {
|
if (isNotEmpty(objectPatch)) {
|
||||||
this.requestService.configure(new PatchRequest(this.requestService.generateRequestId(), href, metadataPatch));
|
this.requestService.configure(new PatchRequest(this.requestService.generateRequestId(), href, objectPatch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ApplyPatchObjectCacheAction(href);
|
return new ApplyPatchObjectCacheAction(href);
|
||||||
|
@@ -122,6 +122,7 @@ import { BrowseDefinition } from './shared/browse-definition.model';
|
|||||||
import { BitstreamDataService } from './data/bitstream-data.service';
|
import { BitstreamDataService } from './data/bitstream-data.service';
|
||||||
import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service';
|
import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service';
|
||||||
import { ObjectSelectService } from '../shared/object-select/object-select.service';
|
import { ObjectSelectService } from '../shared/object-select/object-select.service';
|
||||||
|
import { ArrayMoveChangeAnalyzer } from './data/array-move-change-analyzer.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -201,6 +202,7 @@ const PROVIDERS = [
|
|||||||
DSpaceObjectDataService,
|
DSpaceObjectDataService,
|
||||||
DSOChangeAnalyzer,
|
DSOChangeAnalyzer,
|
||||||
DefaultChangeAnalyzer,
|
DefaultChangeAnalyzer,
|
||||||
|
ArrayMoveChangeAnalyzer,
|
||||||
ObjectSelectService,
|
ObjectSelectService,
|
||||||
CSSVariableService,
|
CSSVariableService,
|
||||||
MenuService,
|
MenuService,
|
||||||
|
38
src/app/core/data/array-move-change-analyzer.service.ts
Normal file
38
src/app/core/data/array-move-change-analyzer.service.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { MoveOperation, Operation } from 'fast-json-patch/lib/core';
|
||||||
|
import { compare } from 'fast-json-patch';
|
||||||
|
import { ChangeAnalyzer } from './change-analyzer';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
import { moveItemInArray } from '@angular/cdk/drag-drop';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to determine move operations between two arrays
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ArrayMoveChangeAnalyzer<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two arrays detecting and returning move operations
|
||||||
|
*
|
||||||
|
* @param array1 The original array
|
||||||
|
* @param array2 The custom array to compare with the original
|
||||||
|
*/
|
||||||
|
diff(array1: T[], array2: T[]): MoveOperation[] {
|
||||||
|
const result = [];
|
||||||
|
const moved = [...array1];
|
||||||
|
array1.forEach((value: T, index: number) => {
|
||||||
|
const otherIndex = array2.indexOf(value);
|
||||||
|
const movedIndex = moved.indexOf(value);
|
||||||
|
if (index !== otherIndex && movedIndex !== otherIndex) {
|
||||||
|
moveItemInArray(moved, movedIndex, otherIndex);
|
||||||
|
result.push(Object.assign({
|
||||||
|
op: 'move',
|
||||||
|
from: '/' + movedIndex,
|
||||||
|
path: '/' + otherIndex
|
||||||
|
}) as MoveOperation)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@@ -24,6 +24,9 @@ import {
|
|||||||
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
||||||
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../../shared/empty.util';
|
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../../shared/empty.util';
|
||||||
import { INotification } from '../../../shared/notifications/models/notification.model';
|
import { INotification } from '../../../shared/notifications/models/notification.model';
|
||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
import { ArrayMoveChangeAnalyzer } from '../array-move-change-analyzer.service';
|
||||||
|
import { MoveOperation } from 'fast-json-patch/lib/core';
|
||||||
|
|
||||||
function objectUpdatesStateSelector(): MemoizedSelector<CoreState, ObjectUpdatesState> {
|
function objectUpdatesStateSelector(): MemoizedSelector<CoreState, ObjectUpdatesState> {
|
||||||
return createSelector(coreSelector, (state: CoreState) => state['cache/object-updates']);
|
return createSelector(coreSelector, (state: CoreState) => state['cache/object-updates']);
|
||||||
@@ -42,7 +45,8 @@ function filterByUrlAndUUIDFieldStateSelector(url: string, uuid: string): Memoiz
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ObjectUpdatesService {
|
export class ObjectUpdatesService {
|
||||||
constructor(private store: Store<CoreState>) {
|
constructor(private store: Store<CoreState>,
|
||||||
|
private comparator: ArrayMoveChangeAnalyzer<string>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,4 +339,16 @@ export class ObjectUpdatesService {
|
|||||||
getLastModified(url: string): Observable<Date> {
|
getLastModified(url: string): Observable<Date> {
|
||||||
return this.getObjectEntry(url).pipe(map((entry: ObjectUpdatesEntry) => entry.lastModified));
|
return this.getObjectEntry(url).pipe(map((entry: ObjectUpdatesEntry) => entry.lastModified));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get move operations based on the custom order
|
||||||
|
* @param url The page's url
|
||||||
|
*/
|
||||||
|
getMoveOperations(url: string): Observable<MoveOperation[]> {
|
||||||
|
return this.getObjectEntry(url).pipe(
|
||||||
|
map((objectEntry) => objectEntry.customOrder),
|
||||||
|
map((customOrder) => this.comparator.diff(customOrder.initialOrder, customOrder.newOrder))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user