diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index ed7e7c559a..dfeeab17c2 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -32,7 +32,7 @@ import { BitstreamFormatRegistryState } from './+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; import { ObjectSelectionListState, objectSelectionReducer } from './shared/object-select/object-select.reducer'; -import { relationshipListReducer, RelationshipListsState } from './shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.reducer'; +import { nameVariantReducer, NameVariantListsState } from './shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; export interface AppState { router: fromRouter.RouterReducerState; @@ -49,7 +49,7 @@ export interface AppState { menus: MenusState; objectSelection: ObjectSelectionListState; selectableLists: SelectableListsState; - relationshipLists: RelationshipListsState; + relationshipLists: NameVariantListsState; } export const appReducers: ActionReducerMap = { @@ -67,7 +67,7 @@ export const appReducers: ActionReducerMap = { menus: menusReducer, objectSelection: objectSelectionReducer, selectableLists: selectableListReducer, - relationshipLists: relationshipListReducer + relationshipLists: nameVariantReducer }; export const routerStateSelector = (state: AppState) => state.router; diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index 0841a47642..bac7ddcdb2 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -28,13 +28,13 @@ import { SearchParam } from '../cache/models/search-param.model'; import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; import { RemoveNameVariantAction, SetNameVariantAction } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.actions'; import { AppState, keySelector } from '../../app.reducer'; -import { RelationshipListState, RelationshipState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.reducer'; +import { NameVariantListState, RelationshipState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; const relationshipListsStateSelector = (state: AppState) => state.relationshipLists; -const relationshipListStateSelector = (listID: string): MemoizedSelector => { - return keySelector(listID, relationshipListsStateSelector); +const relationshipListStateSelector = (listID: string): MemoizedSelector => { + return keySelector(listID, relationshipListsStateSelector); }; const relationshipStateSelector = (listID: string, itemID: string): MemoizedSelector => { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 8c6e2502a9..6a36c90cb3 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -82,7 +82,7 @@ import { DsDynamicDisabledComponent } from './models/disabled/dynamic-disabled.c import { DYNAMIC_FORM_CONTROL_TYPE_DISABLED } from './models/disabled/dynamic-disabled.model'; import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; -import { getSucceededRemoteData } from '../../../../core/shared/operators'; +import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators'; import { RemoteData } from '../../../../core/data/remote-data'; import { Item } from '../../../../core/shared/item.model'; import { ItemDataService } from '../../../../core/data/item-data.service'; @@ -269,14 +269,17 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo } openLookup() { - this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, { size: 'lg' }); - const modalComp = this.modalRef.componentInstance; - modalComp.repeatable = this.model.repeatable; - modalComp.listId = this.listId; - modalComp.relationshipOptions = this.model.relationship; - modalComp.label = this.model.label; - modalComp.itemRD$ = this.model.workspaceItem.item; - modalComp.metadataFields = this.model.metadataFields; + this.model.workspaceItem.item.pipe(getSucceededRemoteData(), getRemoteDataPayload()) + .subscribe((item: Item) => { + this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, { size: 'lg' }); + const modalComp = this.modalRef.componentInstance; + modalComp.repeatable = this.model.repeatable; + modalComp.listId = this.listId; + modalComp.relationshipOptions = this.model.relationship; + modalComp.label = this.model.label; + modalComp.item = item; + modalComp.metadataFields = this.model.metadataFields; + }) } removeSelection(object: SearchResult) { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts index bf448fb603..b4a4d8dbc9 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts @@ -2,7 +2,7 @@ import { Component, NgZone, OnInit } from '@angular/core'; import { combineLatest, Observable, Subscription } from 'rxjs'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { hasValue, hasValueOperator } from '../../../../empty.util'; -import { map, switchMap, take, tap } from 'rxjs/operators'; +import { map, skip, switchMap, take, tap } from 'rxjs/operators'; import { SEARCH_CONFIG_SERVICE } from '../../../../../+my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service'; import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service'; @@ -22,7 +22,7 @@ import { Context } from '../../../../../core/shared/context.model'; import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model'; import { MetadataValue } from '../../../../../core/shared/metadata.models'; import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; -import { RelationshipListState } from './relationship.reducer'; +import { NameVariantListState } from './name-variant.reducer'; @Component({ selector: 'ds-dynamic-lookup-relation-modal', @@ -40,11 +40,14 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { label: string; relationshipOptions: RelationshipOptions; listId: string; - itemRD$; + item; repeatable: boolean; selection$: Observable; context: Context; metadataFields: string; + subMap: { + [uuid: string]: Subscription + }; constructor( public modal: NgbActiveModal, @@ -61,8 +64,6 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { if (this.relationshipOptions.nameVariants) { this.context = Context.Submission; } - this.itemRD$.subscribe((r) => console.log(r)); - this.setExistingNameVariants(); } close() { @@ -73,8 +74,16 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { this.zone.runOutsideAngular( () => { const obs: Observable = combineLatest(...selectableObjects.map((sri: SearchResult) => { - return this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid) - .pipe(map((nameVariant: string) => { + const nameVariant$ = this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid); + this.subMap[sri.indexableObject.uuid] = nameVariant$ + .pipe(skip(1)) + .subscribe((nameVariant: string) => + this.relationshipService.updateNameVariant(this.item, sri.indexableObject, this.relationshipOptions.relationshipType, nameVariant) + ); + return nameVariant$ + .pipe( + take(1), + map((nameVariant: string) => { return { item: sri.indexableObject, nameVariant @@ -84,10 +93,10 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { }) ); - combineLatest(this.itemRD$.pipe(getSucceededRemoteData()), obs) - .subscribe(([itemRD, obs]: [RemoteData, any[]]) => { + obs + .subscribe((obs: any[]) => { return obs.forEach((object: any) => { - this.store.dispatch(new AddRelationshipAction(itemRD.payload, object.item, this.relationshipOptions.relationshipType, object.nameVariant)); + this.store.dispatch(new AddRelationshipAction(this.item, object.item, this.relationshipOptions.relationshipType, object.nameVariant)); this.addSelectSubscription(object); } ); @@ -97,28 +106,22 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { deselect(...selectableObjects: SearchResult[]) { this.zone.runOutsideAngular( - () => this.itemRD$.pipe( - getSucceededRemoteData(), - tap((itemRD: RemoteData) => { - return selectableObjects.forEach((object) => { - this.store.dispatch(new RemoveRelationshipAction(itemRD.payload, object.indexableObject, this.relationshipOptions.relationshipType)); - this.addSelectSubscription(object); - }); - } - ) - ).subscribe() - ); + () => selectableObjects.forEach((object) => { + this.store.dispatch(new RemoveRelationshipAction(this.item, object.indexableObject, this.relationshipOptions.relationshipType)); + this.addSelectSubscription(object); + }) + ) + ; } subscriptions = new Map(); addSelectSubscription(itemSR: SearchResult) { - const item$ = this.itemRD$.pipe(getSucceededRemoteData(), getRemoteDataPayload()); const nameVariant$ = this.relationshipService.getNameVariant(this.listId, itemSR.indexableObject.uuid).pipe(hasValueOperator()); - const subscription = combineLatest(item$, nameVariant$) + const subscription = nameVariant$ .pipe( - switchMap(([item, nameVariant]: [Item, string]) => { - return this.relationshipService.getRelationshipByItemsAndLabel(item, itemSR.indexableObject, this.relationshipOptions.relationshipType) + switchMap((nameVariant: string) => { + return this.relationshipService.getRelationshipByItemsAndLabel(this.item, itemSR.indexableObject, this.relationshipOptions.relationshipType) .pipe(map((relationship: Relationship) => Object.assign(new Relationship(), relationship, { leftwardValue: nameVariant }))) }), switchMap((updatedRelation: Relationship) => this.relationshipService.update(updatedRelation)) @@ -139,10 +142,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { } setExistingNameVariants() { - const virtualMDs$: Observable = this.itemRD$.pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - map((item: Item) => item.allMetadata(this.metadataFields).filter((mdValue) => mdValue.isVirtual))); + const virtualMDs$: Observable = this.item.allMetadata(this.metadataFields).filter((mdValue) => mdValue.isVirtual); const relatedItemPairs$: Observable<[Item, Item][]> = virtualMDs$.pipe( switchMap((mds: MetadataValue[]) => combineLatest(mds.map((md: MetadataValue) => this.relationshipService.findById(md.virtualValue).pipe(getSucceededRemoteData(), getRemoteDataPayload())))), @@ -155,8 +155,8 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { ) ); - const relatedItems$: Observable = combineLatest(relatedItemPairs$, this.itemRD$).pipe( - map(([relatedItemPairs, itemRD]: [[Item, Item][], RemoteData]) => relatedItemPairs.map(([left, right]: [Item, Item]) => left.uuid === itemRD.payload.uuid ? left : right)) + const relatedItems$: Observable = relatedItemPairs$.pipe( + map(([relatedItemPairs,]: [[Item, Item][]]) => relatedItemPairs.map(([left, right]: [Item, Item]) => left.uuid === this.item.uuid ? left : right)) ); combineLatest(virtualMDs$, relatedItems$).pipe(take(1)).subscribe(([virtualMDs, relatedItems]) => { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions.ts new file mode 100644 index 0000000000..dbd0938945 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions.ts @@ -0,0 +1,54 @@ +/** + * The list of NameVariantAction type definitions + */ +import { type } from '../../../../ngrx/type'; +import { Action } from '@ngrx/store'; +import { Item } from '../../../../../core/shared/item.model'; + +export const NameVariantActionTypes = { + SET_NAME_VARIANT: type('dspace/name-variant/SET_NAME_VARIANT'), + REMOVE_NAME_VARIANT: type('dspace/name-variant/REMOVE_NAME_VARIANT'), +}; + +/* tslint:disable:max-classes-per-file */ + +export abstract class NameVariantListAction implements Action { + type; + payload: { + listID: string; + itemID: string; + }; + + constructor(listID: string, itemID: string) { + this.payload = { listID, itemID }; + } +} + +export class SetNameVariantAction extends NameVariantListAction { + type = NameVariantActionTypes.SET_NAME_VARIANT; + payload: { + listID: string; + itemID: string; + nameVariant: string; + }; + + constructor(listID: string, itemID: string, nameVariant: string) { + super(listID, itemID); + this.payload.nameVariant = nameVariant; + } +} + +export class RemoveNameVariantAction extends NameVariantListAction { + type = NameVariantActionTypes.REMOVE_NAME_VARIANT; + constructor(listID: string, itemID: string) { + super(listID, itemID); + } +} +/* tslint:enable:max-classes-per-file */ + +/** + * A type to encompass all RelationshipActions + */ +export type NameVariantAction + = SetNameVariantAction + | RemoveNameVariantAction diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.ts new file mode 100644 index 0000000000..8fe1830219 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.ts @@ -0,0 +1,45 @@ +/** + * Represents the state of all lists containing name variants in the store + */ + +import { NameVariantAction, NameVariantActionTypes, SetNameVariantAction } from './name-variant.actions'; + +export type NameVariantListsState = { + [listID: string]: NameVariantListState; +} + +/** + * Represents the state of a single list containing nameVariants in the store + */ +export type NameVariantListState = { + [itemID: string]: string; +} + +/** + * Reducer that handles NameVariantAction to update the NameVariantListsState + * @param {NameVariantListsState} state The initial NameVariantListsState + * @param {NameVariantAction} action The Action to be performed on the state + * @returns {NameVariantListsState} The new, reduced NameVariantListsState + */ +export function nameVariantReducer(state: NameVariantListsState = {}, action: NameVariantAction): NameVariantListsState { + switch (action.type) { + case NameVariantActionTypes.SET_NAME_VARIANT: { + const listState: NameVariantListState = state[action.payload.listID] || {}; + const nameVariant = (action as SetNameVariantAction).payload.nameVariant; + const newListState = setNameVariant(listState, action.payload.itemID, nameVariant); + return Object.assign({}, state, { [action.payload.listID]: newListState }); + } + case NameVariantActionTypes.REMOVE_NAME_VARIANT: { + const listState: NameVariantListState = state[action.payload.listID] || {}; + const newListState = setNameVariant(listState, action.payload.itemID, undefined); + return Object.assign({}, state, { [action.payload.listID]: newListState }); + } + default: { + return state; + } + } +} + +function setNameVariant(state: NameVariantListState, itemID: string, nameVariant: string) { + return Object.assign({}, state, { [itemID]: { nameVariant } }); +} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.actions.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.actions.ts index abff6622d7..a988b0bbea 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.actions.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.actions.ts @@ -8,46 +8,9 @@ import { Item } from '../../../../../core/shared/item.model'; export const RelationshipActionTypes = { ADD_RELATIONSHIP: type('dspace/relationship/ADD_RELATIONSHIP'), REMOVE_RELATIONSHIP: type('dspace/relationship/REMOVE_RELATIONSHIP'), - SET_NAME_VARIANT: type('dspace/relationship/SET_NAME_VARIANT'), - REMOVE_NAME_VARIANT: type('dspace/relationship/REMOVE_NAME_VARIANT'), }; /* tslint:disable:max-classes-per-file */ - -export abstract class RelationshipListAction implements Action { - type; - payload: { - listID: string; - itemID: string; - }; - - constructor(listID: string, itemID: string) { - this.payload = { listID, itemID }; - } -} - -export class SetNameVariantAction extends RelationshipListAction { - type = RelationshipActionTypes.SET_NAME_VARIANT; - payload: { - listID: string; - itemID: string; - nameVariant: string; - }; - - constructor(listID: string, itemID: string, nameVariant: string) { - super(listID, itemID); - this.payload.nameVariant = nameVariant; - } -} - -export class RemoveNameVariantAction extends RelationshipListAction { - type = RelationshipActionTypes.REMOVE_NAME_VARIANT; - constructor(listID: string, itemID: string, ) { - super(listID, itemID); - } -} - - /** * An ngrx action to create a new relationship */ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.reducer.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.reducer.ts deleted file mode 100644 index 393353d4b7..0000000000 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.reducer.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Represents the state of all lists containing relationships in the store - */ -import { RelationshipActionTypes, RelationshipListAction, SetNameVariantAction } from './relationship.actions'; - -export type RelationshipListsState = { - [listID: string]: RelationshipListState; -} - -/** - * Represents the state of a single list containing relationships in the store - */ -export type RelationshipListState = { - [itemID: string]: RelationshipState; -} - -/** - * Represents the state of a relationship in a list in the store - */ -export type RelationshipState = { - nameVariant: string; -} - -/** - * Reducer that handles RelationshipListAction to update the RelationshipListsState - * @param {RelationshipListsState} state The initial RelationshipListsState - * @param {RelationshipListAction} action The Action to be performed on the state - * @returns {RelationshipListsState} The new, reduced RelationshipListsState - */ -export function relationshipListReducer(state: RelationshipListsState = {}, action: RelationshipListAction): RelationshipListsState { - switch (action.type) { - case RelationshipActionTypes.SET_NAME_VARIANT: { - const listState: RelationshipListState = state[action.payload.listID] || {}; - const nameVariant = (action as SetNameVariantAction).payload.nameVariant; - const newListState = setNameVariant(listState, action.payload.itemID, nameVariant); - return Object.assign({}, state, { [action.payload.listID]: newListState }); - } - case RelationshipActionTypes.REMOVE_NAME_VARIANT: { - const listState: RelationshipListState = state[action.payload.listID] || {}; - const newListState = setNameVariant(listState, action.payload.itemID, undefined); - return Object.assign({}, state, { [action.payload.listID]: newListState }); - } - default: { - return state; - } - } -} - -function setNameVariant(state: RelationshipListState, itemID: string, nameVariant: string) { - return Object.assign({}, state, { [itemID]: { nameVariant } }); -}