fixes for replacing/moving

This commit is contained in:
lotte
2020-02-19 17:04:37 +01:00
parent 1a6f67d12e
commit c98a4a1c3f
7 changed files with 107 additions and 47 deletions

View File

@@ -7,7 +7,7 @@ import {
} from '../json-patch-operations.actions'; } from '../json-patch-operations.actions';
import { JsonPatchOperationPathObject } from './json-patch-operation-path-combiner'; import { JsonPatchOperationPathObject } from './json-patch-operation-path-combiner';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { isEmpty, isNotEmpty } from '../../../shared/empty.util'; import { hasNoValue, isEmpty, isNotEmpty } from '../../../shared/empty.util';
import { dateToISOFormat } from '../../../shared/date.util'; import { dateToISOFormat } from '../../../shared/date.util';
import { AuthorityValue } from '../../integration/models/authority.value'; import { AuthorityValue } from '../../integration/models/authority.value';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
@@ -53,12 +53,16 @@ export class JsonPatchOperationsBuilder {
* a boolean representing if the value to be added is a plain text value * a boolean representing if the value to be added is a plain text value
*/ */
replace(path: JsonPatchOperationPathObject, value, plain = false) { replace(path: JsonPatchOperationPathObject, value, plain = false) {
this.store.dispatch( if (hasNoValue(value) || (typeof value === 'object' && hasNoValue(value.value))) {
new NewPatchReplaceOperationAction( this.remove(path);
path.rootElement, } else {
path.subRootElement, this.store.dispatch(
path.path, new NewPatchReplaceOperationAction(
this.prepareValue(value, plain, false))); path.rootElement,
path.subRootElement,
path.path,
this.prepareValue(value, plain, false)));
}
} }
move(path: JsonPatchOperationPathObject, prevPath: string) { move(path: JsonPatchOperationPathObject, prevPath: string) {

View File

@@ -74,7 +74,7 @@ import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/relation-group/dynamic-relation-group.model'; import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/relation-group/dynamic-relation-group.model';
import { DsDatePickerInlineComponent } from './models/date-picker-inline/dynamic-date-picker-inline.component'; import { DsDatePickerInlineComponent } from './models/date-picker-inline/dynamic-date-picker-inline.component';
import { map, startWith, switchMap, find, take, tap, filter } from 'rxjs/operators'; import { map, startWith, switchMap, find, take, tap, filter } from 'rxjs/operators';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs'; import { combineLatest, combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
import { SearchResult } from '../../../search/search-result.model'; import { SearchResult } from '../../../search/search-result.model';
import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
@@ -100,6 +100,7 @@ import { FormService } from '../../form.service';
import { deepClone } from 'fast-json-patch'; import { deepClone } from 'fast-json-patch';
import { SelectableListState } from '../../../object-list/selectable-list/selectable-list.reducer'; import { SelectableListState } from '../../../object-list/selectable-list/selectable-list.reducer';
import { SubmissionService } from '../../../../submission/submission.service'; import { SubmissionService } from '../../../../submission/submission.service';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null { export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
switch (model.type) { switch (model.type) {
@@ -187,6 +188,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
isRelationship: boolean; isRelationship: boolean;
modalRef: NgbModalRef; modalRef: NgbModalRef;
item: Item; item: Item;
item$: Observable<Item>;
collection: Collection; collection: Collection;
listId: string; listId: string;
searchConfig: string; searchConfig: string;
@@ -245,13 +247,13 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
.pipe( .pipe(
getAllSucceededRemoteData(), getAllSucceededRemoteData(),
getRemoteDataPayload()); getRemoteDataPayload());
this.relationshipValue$ = relationship$.pipe( this.relationshipValue$ = combineLatest(this.item$.pipe(take(1)), relationship$).pipe(
switchMap((relationship: Relationship) => switchMap(([item, relationship]: [Item, Relationship]) =>
relationship.leftItem.pipe( relationship.leftItem.pipe(
getSucceededRemoteData(), getSucceededRemoteData(),
getRemoteDataPayload(), getRemoteDataPayload(),
map((leftItem: Item) => { map((leftItem: Item) => {
return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid, this.relationshipService) return new ReorderableRelationship(relationship, leftItem.uuid !== item.uuid, this.relationshipService, this.store, this.model.submissionId)
}), }),
) )
), ),
@@ -264,10 +266,11 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
this.setItem(); this.setItem();
const subscription = this.selectableListService.getSelectableList(this.listId).pipe( const subscription = this.selectableListService.getSelectableList(this.listId).pipe(
find((list: SelectableListState) => hasNoValue(list)), find((list: SelectableListState) => hasNoValue(list)),
switchMap(() => { switchMap(() => this.item$.pipe(take(1))),
return this.relationService.getRelatedItemsByLabel(this.item, this.model.relationshipConfig.relationshipType).pipe( switchMap((item) => {
return this.relationService.getRelatedItemsByLabel(item, this.model.relationshipConfig.relationshipType).pipe(
getSucceededRemoteData(), getSucceededRemoteData(),
map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))), map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((i) => Object.assign(new ItemSearchResult(), { indexableObject: i }))),
) )
}) })
).subscribe((relatedItems: Array<SearchResult<Item>>) => this.selectableListService.select(this.listId, relatedItems)); ).subscribe((relatedItems: Array<SearchResult<Item>>) => this.selectableListService.select(this.listId, relatedItems));
@@ -328,7 +331,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
modalComp.query = this.model.value ? this.model.value.value : ''; modalComp.query = this.model.value ? this.model.value.value : '';
if (hasValue(this.model.value)) { if (hasValue(this.model.value)) {
this.model.valueUpdates.next(''); // this.model.reset();
// this.model.value = undefined;
// this.model.valueUpdates(undefined);
this.model.value.value = undefined;
this.change.emit(); this.change.emit();
} }
this.submissionService.dispatchSave(this.model.submissionId); this.submissionService.dispatchSave(this.model.submissionId);
@@ -358,10 +364,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
getRemoteDataPayload() getRemoteDataPayload()
); );
const item$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()))); this.item$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload())));
const collection$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.collection as Observable<RemoteData<Collection>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()))); const collection$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.collection as Observable<RemoteData<Collection>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload())));
this.subs.push(item$.subscribe((item) => this.item = item)); this.subs.push(this.item$.subscribe((item) => this.item = item));
this.subs.push(collection$.subscribe((collection) => this.collection = collection)); this.subs.push(collection$.subscribe((collection) => this.collection = collection));
} }
} }

View File

@@ -23,7 +23,7 @@ import { SelectableListService } from '../../../../object-list/selectable-list/s
import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model'; import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model';
import { RelationshipOptions } from '../../models/relationship-options.model'; import { RelationshipOptions } from '../../models/relationship-options.model';
import { DynamicConcatModel } from '../models/ds-dynamic-concat.model'; import { DynamicConcatModel } from '../models/ds-dynamic-concat.model';
import { RemoveRelationshipAction } from '../relation-lookup-modal/relationship.actions'; import { RemoveRelationshipAction, UpdateRelationshipAction } from '../relation-lookup-modal/relationship.actions';
import { SubmissionObject } from '../../../../../core/submission/models/submission-object.model'; import { SubmissionObject } from '../../../../../core/submission/models/submission-object.model';
// tslint:disable:max-classes-per-file // tslint:disable:max-classes-per-file
@@ -85,7 +85,14 @@ export class ReorderableFormFieldMetadataValue extends Reorderable {
*/ */
export class ReorderableRelationship extends Reorderable { export class ReorderableRelationship extends Reorderable {
constructor(public relationship: Relationship, public useLeftItem: boolean, protected relationshipService: RelationshipService, oldIndex?: number, newIndex?: number) { constructor(
public relationship: Relationship,
public useLeftItem: boolean,
protected relationshipService: RelationshipService,
protected store: Store<AppState>,
protected submissionID: string,
oldIndex?: number,
newIndex?: number) {
super(oldIndex, newIndex); super(oldIndex, newIndex);
this.relationship = relationship; this.relationship = relationship;
this.useLeftItem = useLeftItem; this.useLeftItem = useLeftItem;
@@ -104,6 +111,7 @@ export class ReorderableRelationship extends Reorderable {
} }
update(): Observable<RemoteData<Relationship>> { update(): Observable<RemoteData<Relationship>> {
this.store.dispatch(new UpdateRelationshipAction(this.relationship, this.submissionID))
const updatedRelationship$ = this.relationshipService.updatePlace(this).pipe( const updatedRelationship$ = this.relationshipService.updatePlace(this).pipe(
getSucceededRemoteData(), getSucceededRemoteData(),
); );
@@ -147,23 +155,25 @@ export class ExistingMetadataListElementComponent implements OnChanges, OnDestro
} }
ngOnChanges() { ngOnChanges() {
const item$ = this.reoRel.useLeftItem ? if (hasValue(this.reoRel)) {
this.reoRel.relationship.leftItem : this.reoRel.relationship.rightItem; const item$ = this.reoRel.useLeftItem ?
this.subs.push(item$.pipe( this.reoRel.relationship.leftItem : this.reoRel.relationship.rightItem;
getAllSucceededRemoteData(), this.subs.push(item$.pipe(
getRemoteDataPayload(), getAllSucceededRemoteData(),
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid)) getRemoteDataPayload(),
).subscribe((item: Item) => { filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid))
this.relatedItem = item; ).subscribe((item: Item) => {
const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid }); this.relatedItem = item;
if (hasValue(relationMD)) { const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid });
const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority }); if (hasValue(relationMD)) {
this.metadataRepresentation = Object.assign( const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority });
new ItemMetadataRepresentation(metadataRepresentationMD), this.metadataRepresentation = Object.assign(
this.relatedItem new ItemMetadataRepresentation(metadataRepresentationMD),
) this.relatedItem
} )
})); }
}));
}
} }
/** /**
@@ -184,4 +194,5 @@ export class ExistingMetadataListElementComponent implements OnChanges, OnDestro
} }
} }
// tslint:enable:max-classes-per-file // tslint:enable:max-classes-per-file

View File

@@ -40,6 +40,7 @@ import { SubmissionState } from '../../../../../../submission/submission.reducer
import { ObjectCacheService } from '../../../../../../core/cache/object-cache.service'; import { ObjectCacheService } from '../../../../../../core/cache/object-cache.service';
import { RequestService } from '../../../../../../core/data/request.service'; import { RequestService } from '../../../../../../core/data/request.service';
import { SubmissionService } from '../../../../../../submission/submission.service'; import { SubmissionService } from '../../../../../../submission/submission.service';
import { AppState } from '../../../../../../app.reducer';
@Component({ @Component({
selector: 'ds-dynamic-form-array', selector: 'ds-dynamic-form-array',
@@ -72,6 +73,7 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
protected zone: NgZone, protected zone: NgZone,
protected formService: DynamicFormService, protected formService: DynamicFormService,
private submissionService: SubmissionService, private submissionService: SubmissionService,
private store: Store<AppState>,
) { ) {
super(layoutService, validationService); super(layoutService, validationService);
} }
@@ -87,9 +89,11 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
getRemoteDataPayload() getRemoteDataPayload()
) )
) )
).subscribe((item) => this.submissionItem = item); ).subscribe((item) => {
this.submissionItem = item;
this.updateReorderables();
});
this.updateReorderables();
} }
private updateReorderables(): void { private updateReorderables(): void {
@@ -123,6 +127,8 @@ export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent imple
relationship, relationship,
leftItem.uuid !== this.submissionItem.uuid, leftItem.uuid !== this.submissionItem.uuid,
this.relationshipService, this.relationshipService,
this.store,
this.model.submissionId,
index, index,
index index
); );

View File

@@ -12,7 +12,7 @@ import { RelationshipOptions } from '../../models/relationship-options.model';
import { SearchResult } from '../../../../search/search-result.model'; import { SearchResult } from '../../../../search/search-result.model';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators'; import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators';
import { AddRelationshipAction, RemoveRelationshipAction, UpdateRelationshipAction } from './relationship.actions'; import { AddRelationshipAction, RemoveRelationshipAction, UpdateRelationshipNameVariantAction } from './relationship.actions';
import { RelationshipService } from '../../../../../core/data/relationship.service'; import { RelationshipService } from '../../../../../core/data/relationship.service';
import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service'; import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@@ -178,7 +178,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
const nameVariant$ = this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid); const nameVariant$ = this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid);
this.subMap[sri.indexableObject.uuid] = nameVariant$.pipe( this.subMap[sri.indexableObject.uuid] = nameVariant$.pipe(
skip(1), skip(1),
).subscribe((nameVariant: string) => this.store.dispatch(new UpdateRelationshipAction(this.item, sri.indexableObject, this.relationshipOptions.relationshipType, this.submissionId, nameVariant))) ).subscribe((nameVariant: string) => this.store.dispatch(new UpdateRelationshipNameVariantAction(this.item, sri.indexableObject, this.relationshipOptions.relationshipType, this.submissionId, nameVariant)))
} }
/** /**

View File

@@ -4,10 +4,12 @@
import { type } from '../../../../ngrx/type'; import { type } from '../../../../ngrx/type';
import { Action } from '@ngrx/store'; import { Action } from '@ngrx/store';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model';
export const RelationshipActionTypes = { export const RelationshipActionTypes = {
ADD_RELATIONSHIP: type('dspace/relationship/ADD_RELATIONSHIP'), ADD_RELATIONSHIP: type('dspace/relationship/ADD_RELATIONSHIP'),
REMOVE_RELATIONSHIP: type('dspace/relationship/REMOVE_RELATIONSHIP'), REMOVE_RELATIONSHIP: type('dspace/relationship/REMOVE_RELATIONSHIP'),
UPDATE_NAME_VARIANT: type('dspace/relationship/UPDATE_NAME_VARIANT'),
UPDATE_RELATIONSHIP: type('dspace/relationship/UPDATE_RELATIONSHIP'), UPDATE_RELATIONSHIP: type('dspace/relationship/UPDATE_RELATIONSHIP'),
}; };
@@ -46,8 +48,8 @@ export class AddRelationshipAction implements Action {
} }
} }
export class UpdateRelationshipAction implements Action { export class UpdateRelationshipNameVariantAction implements Action {
type = RelationshipActionTypes.UPDATE_RELATIONSHIP; type = RelationshipActionTypes.UPDATE_NAME_VARIANT;
payload: { payload: {
item1: Item; item1: Item;
@@ -58,7 +60,7 @@ export class UpdateRelationshipAction implements Action {
}; };
/** /**
* Create a new UpdateRelationshipAction * Create a new UpdateRelationshipNameVariantAction
* *
* @param item1 The first item in the relationship * @param item1 The first item in the relationship
* @param item2 The second item in the relationship * @param item2 The second item in the relationship
@@ -77,6 +79,28 @@ export class UpdateRelationshipAction implements Action {
} }
} }
export class UpdateRelationshipAction implements Action {
type = RelationshipActionTypes.UPDATE_RELATIONSHIP;
payload: {
relationship: Relationship;
submissionId: string;
};
/**
* Create a new UpdateRelationshipAction
*
* @param relationship The relationship
* @param submissionId The current submissionId
*/
constructor(
relationship: Relationship,
submissionId: string,
) {
this.payload = { relationship, submissionId };
}
}
/** /**
* An ngrx action to remove an existing relationship * An ngrx action to remove an existing relationship
*/ */

View File

@@ -4,7 +4,7 @@ import { debounceTime, filter, map, mergeMap, switchMap, take, tap } from 'rxjs/
import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { RelationshipService } from '../../../../../core/data/relationship.service'; import { RelationshipService } from '../../../../../core/data/relationship.service';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../../core/shared/operators'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../../core/shared/operators';
import { AddRelationshipAction, RelationshipAction, RelationshipActionTypes, UpdateRelationshipAction } from './relationship.actions'; import { AddRelationshipAction, RelationshipAction, RelationshipActionTypes, UpdateRelationshipAction, UpdateRelationshipNameVariantAction } from './relationship.actions';
import { Item } from '../../../../../core/shared/item.model'; import { Item } from '../../../../../core/shared/item.model';
import { hasNoValue, hasValue, hasValueOperator } from '../../../../empty.util'; import { hasNoValue, hasValue, hasValueOperator } from '../../../../empty.util';
import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model';
@@ -18,6 +18,7 @@ import { Store } from '@ngrx/store';
import { ObjectCacheService } from '../../../../../core/cache/object-cache.service'; import { ObjectCacheService } from '../../../../../core/cache/object-cache.service';
import { RequestService } from '../../../../../core/data/request.service'; import { RequestService } from '../../../../../core/data/request.service';
import { ServerSyncBufferActionTypes } from '../../../../../core/cache/server-sync-buffer.actions'; import { ServerSyncBufferActionTypes } from '../../../../../core/cache/server-sync-buffer.actions';
import { CommitPatchOperationsAction, JsonPatchOperationsActionTypes, PatchOperationsActions } from '../../../../../core/json-patch/json-patch-operations.actions';
const DEBOUNCE_TIME = 5000; const DEBOUNCE_TIME = 5000;
@@ -91,8 +92,8 @@ export class RelationshipEffects {
*/ */
@Effect({ dispatch: false }) updateNameVariantsActions$ = this.actions$ @Effect({ dispatch: false }) updateNameVariantsActions$ = this.actions$
.pipe( .pipe(
ofType(RelationshipActionTypes.UPDATE_RELATIONSHIP), ofType(RelationshipActionTypes.UPDATE_NAME_VARIANT),
map((action: UpdateRelationshipAction) => { map((action: UpdateRelationshipNameVariantAction) => {
const { item1, item2, relationshipType, submissionId, nameVariant } = action.payload; const { item1, item2, relationshipType, submissionId, nameVariant } = action.payload;
const identifier: string = this.createIdentifier(item1, item2, relationshipType); const identifier: string = this.createIdentifier(item1, item2, relationshipType);
const inProgress = hasValue(this.debounceMap[identifier]); const inProgress = hasValue(this.debounceMap[identifier]);
@@ -108,9 +109,17 @@ export class RelationshipEffects {
) )
); );
@Effect({ dispatch: false }) updateRelationshipActions$ = this.actions$
.pipe(
ofType(RelationshipActionTypes.UPDATE_RELATIONSHIP),
map((action: UpdateRelationshipAction) => {
this.updateAfterPatchSubmissionId = action.payload.submissionId;
})
);
@Effect() commitServerSyncBuffer = this.actions$ @Effect() commitServerSyncBuffer = this.actions$
.pipe( .pipe(
ofType(ServerSyncBufferActionTypes.EMPTY), ofType(ServerSyncBufferActionTypes.EMPTY, JsonPatchOperationsActionTypes.COMMIT_JSON_PATCH_OPERATIONS),
filter(() => hasValue(this.updateAfterPatchSubmissionId)), filter(() => hasValue(this.updateAfterPatchSubmissionId)),
switchMap(() => this.refreshWorkspaceItemInCache(this.updateAfterPatchSubmissionId)), switchMap(() => this.refreshWorkspaceItemInCache(this.updateAfterPatchSubmissionId)),
map((submissionObject) => new SaveSubmissionSectionFormSuccessAction(this.updateAfterPatchSubmissionId, [submissionObject], false)) map((submissionObject) => new SaveSubmissionSectionFormSuccessAction(this.updateAfterPatchSubmissionId, [submissionObject], false))