mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
fix a number of issues with name variants
This commit is contained in:
@@ -44,11 +44,12 @@ import {
|
||||
FindByIDRequest,
|
||||
FindListOptions,
|
||||
FindListRequest,
|
||||
GetRequest, PatchRequest
|
||||
GetRequest, PatchRequest, PutRequest
|
||||
} from './request.models';
|
||||
import { RequestEntry } from './request.reducer';
|
||||
import { RequestService } from './request.service';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { GenericConstructor } from '../shared/generic-constructor';
|
||||
|
||||
export abstract class DataService<T extends CacheableObject> {
|
||||
protected abstract requestService: RequestService;
|
||||
@@ -307,24 +308,23 @@ export abstract class DataService<T extends CacheableObject> {
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
searchBy(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<T>>> {
|
||||
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const hrefObs = this.getSearchByHref(searchMethod, options, ...linksToFollow);
|
||||
|
||||
return hrefObs.pipe(
|
||||
find((href: string) => hasValue(href)),
|
||||
tap((href: string) => {
|
||||
this.requestService.removeByHrefSubstring(href);
|
||||
const request = new FindListRequest(this.requestService.generateRequestId(), href, options);
|
||||
request.responseMsToLive = 10 * 1000;
|
||||
hrefObs.pipe(
|
||||
find((href: string) => hasValue(href))
|
||||
).subscribe((href: string) => {
|
||||
this.requestService.removeByHrefSubstring(href);
|
||||
const request = new FindListRequest(requestId, href, options);
|
||||
request.responseMsToLive = 10 * 1000;
|
||||
this.requestService.configure(request);
|
||||
});
|
||||
|
||||
this.requestService.configure(request);
|
||||
}
|
||||
return this.requestService.getByUUID(requestId).pipe(
|
||||
find((requestEntry) => hasValue(requestEntry) && requestEntry.completed),
|
||||
switchMap((requestEntry) =>
|
||||
this.rdbService.buildList<T>(requestEntry.request.href, ...linksToFollow)
|
||||
),
|
||||
switchMap((href) => this.requestService.getByHref(href)),
|
||||
skipWhile((requestEntry) => hasValue(requestEntry) && requestEntry.completed),
|
||||
switchMap((href) =>
|
||||
this.rdbService.buildList<T>(hrefObs, ...linksToFollow) as Observable<RemoteData<PaginatedList<T>>>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -353,6 +353,23 @@ export abstract class DataService<T extends CacheableObject> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a PUT request for the specified object
|
||||
*
|
||||
* @param object The object to send a put request for.
|
||||
*/
|
||||
put(object: T): Observable<RemoteData<T>> {
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const serializedObject = new DSpaceSerializer(object.constructor as GenericConstructor<{}>).serialize(object);
|
||||
const request = new PutRequest(requestId, object._links.self.href, serializedObject);
|
||||
this.requestService.configure(request);
|
||||
|
||||
return this.requestService.getByUUID(requestId).pipe(
|
||||
find((request: RequestEntry) => hasValue(request) && request.completed),
|
||||
switchMap(() => this.findByHref(object._links.self.href))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { combineLatest as observableCombineLatest } from 'rxjs';
|
||||
import { combineLatest as observableCombineLatest, OperatorFunction } from 'rxjs';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
find,
|
||||
map,
|
||||
startWith,
|
||||
switchMap,
|
||||
@@ -44,7 +45,7 @@ import {
|
||||
configureRequest, getFirstSucceededRemoteDataPayload,
|
||||
getRemoteDataPayload,
|
||||
getResponseFromEntry,
|
||||
getSucceededRemoteData
|
||||
getSucceededRemoteData, getPaginatedListPayload
|
||||
} from '../shared/operators';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
@@ -53,6 +54,7 @@ import { PaginatedList } from './paginated-list';
|
||||
import { RemoteData, RemoteDataState } from './remote-data';
|
||||
import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import has = Reflect.has;
|
||||
|
||||
const relationshipListsStateSelector = (state: AppState) => state.relationshipLists;
|
||||
|
||||
@@ -167,7 +169,7 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
* Method to remove an item that's part of a relationship from the cache
|
||||
* @param item The item to remove from the cache
|
||||
*/
|
||||
private refreshRelationshipItemsInCache(item) {
|
||||
public refreshRelationshipItemsInCache(item) {
|
||||
this.objectCache.remove(item._links.self.href);
|
||||
this.requestService.removeByHrefSubstring(item.uuid);
|
||||
observableCombineLatest(
|
||||
@@ -310,24 +312,29 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
* @param label The rightward or leftward type of the relationship
|
||||
*/
|
||||
getRelationshipByItemsAndLabel(item1: Item, item2: Item, label: string, options?: FindListOptions): Observable<Relationship> {
|
||||
return this.getItemRelationshipsByLabel(item1, label, options, followLink('relationshipType'), followLink('leftItem'), followLink('rightItem'))
|
||||
.pipe(
|
||||
console.log('getRelationshipByItemsAndLabel', item1, item2, label, options);
|
||||
return this.getItemRelationshipsByLabel(
|
||||
item1,
|
||||
label,
|
||||
options,
|
||||
followLink('relationshipType'),
|
||||
followLink('leftItem'),
|
||||
followLink('rightItem')
|
||||
).pipe(
|
||||
getSucceededRemoteData(),
|
||||
isNotEmptyOperator(),
|
||||
map((relationshipListRD: RemoteData<PaginatedList<Relationship>>) => relationshipListRD.payload.page),
|
||||
mergeMap((relationships: Relationship[]) => {
|
||||
return observableCombineLatest(...relationships.map((relationship: Relationship) => {
|
||||
return observableCombineLatest(
|
||||
this.isItemMatchWithItemRD(this.itemService.findByHref(relationship._links.leftItem.href), item2),
|
||||
this.isItemMatchWithItemRD(this.itemService.findByHref(relationship._links.rightItem.href), item2)
|
||||
).pipe(
|
||||
map(([isLeftItem, isRightItem]) => isLeftItem || isRightItem),
|
||||
map((isMatch) => isMatch ? relationship : undefined)
|
||||
);
|
||||
})
|
||||
)
|
||||
// the mergemap below will emit all elements of the list as separate events
|
||||
mergeMap((relationshipListRD: RemoteData<PaginatedList<Relationship>>) => relationshipListRD.payload.page),
|
||||
mergeMap((relationship: Relationship) => {
|
||||
return observableCombineLatest([
|
||||
this.isItemMatchWithItemRD(this.itemService.findByHref(relationship._links.leftItem.href), item2),
|
||||
this.isItemMatchWithItemRD(this.itemService.findByHref(relationship._links.rightItem.href), item2)
|
||||
]).pipe(
|
||||
map(([isLeftItem, isRightItem]) => isLeftItem || isRightItem),
|
||||
map((isMatch) => isMatch ? relationship : undefined)
|
||||
);
|
||||
}),
|
||||
map((relationships: Relationship[]) => relationships.find(((relationship) => hasValue(relationship))))
|
||||
filter((relationship) => hasValue(relationship)),
|
||||
take(1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -384,11 +391,8 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
* @param nameVariant The name variant to set for the matching relationship
|
||||
*/
|
||||
public updateNameVariant(item1: Item, item2: Item, relationshipLabel: string, nameVariant: string): Observable<RemoteData<Relationship>> {
|
||||
let count = 0
|
||||
const update$: Observable<RemoteData<Relationship>> = this.getRelationshipByItemsAndLabel(item1, item2, relationshipLabel)
|
||||
return this.getRelationshipByItemsAndLabel(item1, item2, relationshipLabel)
|
||||
.pipe(
|
||||
tap((v) => console.log('updateNameVariant after getRelationshipByItemsAndLabel', v)),
|
||||
filter((relation: Relationship) => hasValue(relation)),
|
||||
switchMap((relation: Relationship) =>
|
||||
relation.relationshipType.pipe(
|
||||
getSucceededRemoteData(),
|
||||
@@ -399,7 +403,6 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
)
|
||||
),
|
||||
switchMap((relationshipAndType: { relation: Relationship, type: RelationshipType }) => {
|
||||
console.log('updateNameVariant switchMap', relationshipAndType);
|
||||
const { relation, type } = relationshipAndType;
|
||||
let updatedRelationship;
|
||||
if (relationshipLabel === type.leftwardType) {
|
||||
@@ -409,15 +412,7 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
}
|
||||
return this.update(updatedRelationship);
|
||||
}),
|
||||
tap((relationshipRD: RemoteData<Relationship>) => {
|
||||
if (relationshipRD.hasSucceeded && count < 1) {
|
||||
count++;
|
||||
this.refreshRelationshipItemsInCache(item1);
|
||||
this.refreshRelationshipItemsInCache(item2);
|
||||
}
|
||||
})
|
||||
);
|
||||
return update$
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,7 @@
|
||||
form {
|
||||
z-index: 1;
|
||||
&:before {
|
||||
pointer-events: none; // prevent the icon from ‘catching‘ the click
|
||||
position: absolute;
|
||||
font-weight: 900;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
@@ -15,4 +16,4 @@ form {
|
||||
input.suggestion_input {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
|
||||
this.relationshipService.getNameVariant(this.listID, this.dso.uuid)
|
||||
.pipe(take(1))
|
||||
.subscribe((nameVariant: string) => {
|
||||
this.selectedName = nameVariant || defaultValue;
|
||||
this.selectedName = nameVariant || defaultValue;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
form {
|
||||
&:before {
|
||||
pointer-events: none; // prevent the icon from ‘catching‘ the click
|
||||
position: absolute;
|
||||
font-weight: 900;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
|
@@ -83,7 +83,12 @@ import { SelectableListService } from '../../../object-list/selectable-list/sele
|
||||
import { DsDynamicDisabledComponent } from './models/disabled/dynamic-disabled.component';
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_DISABLED } from './models/disabled/dynamic-disabled.model';
|
||||
import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component';
|
||||
import { getAllSucceededRemoteData, getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
|
||||
import {
|
||||
getAllSucceededRemoteData,
|
||||
getRemoteDataPayload,
|
||||
getSucceededRemoteData,
|
||||
getAllSucceededRemoteDataPayload, getPaginatedListPayload, getFirstSucceededRemoteDataPayload
|
||||
} 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';
|
||||
@@ -95,11 +100,13 @@ import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
|
||||
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
import { MetadataValue } from '../../../../core/shared/metadata.models';
|
||||
import { MetadataValue, VIRTUAL_METADATA_PREFIX } from '../../../../core/shared/metadata.models';
|
||||
import { FormService } from '../../form.service';
|
||||
import { SelectableListState } from '../../../object-list/selectable-list/selectable-list.reducer';
|
||||
import { SubmissionService } from '../../../../submission/submission.service';
|
||||
import { followLink } from '../../../utils/follow-link-config.model';
|
||||
import { paginatedRelationsToItems } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils';
|
||||
import { RelationshipOptions } from '../models/relationship-options.model';
|
||||
|
||||
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
||||
switch (model.type) {
|
||||
@@ -261,13 +268,37 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
}
|
||||
}
|
||||
if (this.model.relationshipConfig) {
|
||||
const relationshipOptions = Object.assign(new RelationshipOptions(), this.model.relationshipConfig);
|
||||
this.listId = 'list-' + this.model.relationshipConfig.relationshipType;
|
||||
this.setItem();
|
||||
const subscription = this.selectableListService.getSelectableList(this.listId).pipe(
|
||||
find((list: SelectableListState) => hasNoValue(list)),
|
||||
switchMap(() => this.item$.pipe(take(1))),
|
||||
switchMap((item) => {
|
||||
return this.relationshipService.getRelatedItemsByLabel(item, this.model.relationshipConfig.relationshipType).pipe(
|
||||
const relationshipsRD$ = this.relationshipService.getItemRelationshipsByLabel(item,
|
||||
this.model.relationshipConfig.relationshipType,
|
||||
undefined,
|
||||
followLink('leftItem'),
|
||||
followLink('rightItem'),
|
||||
followLink('relationshipType')
|
||||
);
|
||||
|
||||
relationshipsRD$.pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
getPaginatedListPayload()
|
||||
).subscribe((relationships: Relationship[]) => {
|
||||
// set initial namevariants for pre-existing relationships
|
||||
relationships.forEach((relationship: Relationship) => {
|
||||
const relationshipMD: MetadataValue = item.firstMetadata(relationshipOptions.metadataField, { authority: `${VIRTUAL_METADATA_PREFIX}${relationship.id}` });
|
||||
const nameVariantMD: MetadataValue = item.firstMetadata(this.model.metadataFields, { authority: `${VIRTUAL_METADATA_PREFIX}${relationship.id}` });
|
||||
if (hasValue(relationshipMD) && isNotEmpty(relationshipMD.value) && hasValue(nameVariantMD) && isNotEmpty(nameVariantMD.value)) {
|
||||
this.relationshipService.setNameVariant(this.listId, relationshipMD.value, nameVariantMD.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return relationshipsRD$.pipe(
|
||||
paginatedRelationsToItems(item.uuid),
|
||||
getSucceededRemoteData(),
|
||||
map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((i) => Object.assign(new ItemSearchResult(), { indexableObject: i }))),
|
||||
)
|
||||
|
@@ -208,6 +208,7 @@ export class ExistingMetadataListElementComponent implements OnInit, OnChanges,
|
||||
const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: this.relatedItem.uuid });
|
||||
if (hasValue(relationMD)) {
|
||||
const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority });
|
||||
|
||||
const nextValue = Object.assign(
|
||||
new ItemMetadataRepresentation(metadataRepresentationMD),
|
||||
this.relatedItem
|
||||
|
@@ -7,6 +7,7 @@ export interface DynamicRowArrayModelConfig extends DynamicFormArrayModelConfig
|
||||
submissionId: string;
|
||||
relationshipConfig: RelationshipOptions;
|
||||
metadataKey: string;
|
||||
metadataFields: string[];
|
||||
}
|
||||
|
||||
export class DynamicRowArrayModel extends DynamicFormArrayModel {
|
||||
@@ -15,6 +16,7 @@ export class DynamicRowArrayModel extends DynamicFormArrayModel {
|
||||
@serializable() submissionId: string;
|
||||
@serializable() relationshipConfig: RelationshipOptions;
|
||||
@serializable() metadataKey: string;
|
||||
@serializable() metadataFields: string[];
|
||||
isRowArray = true;
|
||||
|
||||
constructor(config: DynamicRowArrayModelConfig, layout?: DynamicFormControlLayout) {
|
||||
@@ -24,5 +26,6 @@ export class DynamicRowArrayModel extends DynamicFormArrayModel {
|
||||
this.submissionId = config.submissionId;
|
||||
this.relationshipConfig = config.relationshipConfig;
|
||||
this.metadataKey = config.metadataKey;
|
||||
this.metadataFields = config.metadataFields;
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import { RequestService } from '../../../../../core/data/request.service';
|
||||
import { ServerSyncBufferActionTypes } from '../../../../../core/cache/server-sync-buffer.actions';
|
||||
import { CommitPatchOperationsAction, JsonPatchOperationsActionTypes, PatchOperationsActions } from '../../../../../core/json-patch/json-patch-operations.actions';
|
||||
import { followLink } from '../../../../utils/follow-link-config.model';
|
||||
import { RemoteData } from '../../../../../core/data/remote-data';
|
||||
|
||||
const DEBOUNCE_TIME = 500;
|
||||
|
||||
@@ -101,10 +102,14 @@ export class RelationshipEffects {
|
||||
if (inProgress) {
|
||||
this.nameVariantUpdates[identifier] = nameVariant;
|
||||
} else {
|
||||
this.relationshipService.updateNameVariant(item1, item2, relationshipType, nameVariant).pipe(take(1))
|
||||
.subscribe(() => {
|
||||
this.updateAfterPatchSubmissionId = submissionId;
|
||||
});
|
||||
this.relationshipService.updateNameVariant(item1, item2, relationshipType, nameVariant).pipe(
|
||||
filter((relationshipRD: RemoteData<Relationship>) => hasValue(relationshipRD.payload)),
|
||||
take(1)
|
||||
).subscribe(() => {
|
||||
this.updateAfterPatchSubmissionId = submissionId;
|
||||
this.relationshipService.refreshRelationshipItemsInCache(item1);
|
||||
this.relationshipService.refreshRelationshipItemsInCache(item2);
|
||||
});
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -161,8 +166,6 @@ export class RelationshipEffects {
|
||||
|
||||
private removeRelationship(item1: Item, item2: Item, relationshipType: string, submissionId: string) {
|
||||
this.relationshipService.getRelationshipByItemsAndLabel(item1, item2, relationshipType).pipe(
|
||||
take(1),
|
||||
hasValueOperator(),
|
||||
mergeMap((relationship: Relationship) => this.relationshipService.deleteRelationship(relationship.id, 'none')),
|
||||
take(1),
|
||||
switchMap(() => this.refreshWorkspaceItemInCache(submissionId)),
|
||||
|
@@ -268,7 +268,8 @@ describe('FormBuilderService test suite', () => {
|
||||
];
|
||||
},
|
||||
required: false,
|
||||
metadataKey: 'dc.contributor.author'
|
||||
metadataKey: 'dc.contributor.author',
|
||||
metadataFields: ['dc.contributor.author']
|
||||
},
|
||||
),
|
||||
];
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const RELATION_METADATA_PREFIX = 'relation.'
|
||||
const RELATION_METADATA_PREFIX = 'relation.';
|
||||
|
||||
/**
|
||||
* The submission options for fields that can represent relationships
|
||||
|
@@ -55,6 +55,7 @@ export abstract class FieldParser {
|
||||
required: JSON.parse( this.configData.mandatory),
|
||||
submissionId: this.submissionId,
|
||||
metadataKey,
|
||||
metadataFields: this.getAllFieldIds(),
|
||||
groupFactory: () => {
|
||||
let model;
|
||||
let isFirstModelInArray = true;
|
||||
|
@@ -10,7 +10,6 @@ import { AuthorityValue } from '../../core/integration/models/authority.value';
|
||||
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
|
||||
import { DynamicRowGroupModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
|
||||
import { FormRowModel } from '../../core/config/models/config-submission-form.model';
|
||||
import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
|
||||
|
||||
export const qualdropSelectConfig = {
|
||||
name: 'dc.identifier_QUALDROP_METADATA',
|
||||
@@ -82,7 +81,8 @@ const rowArrayQualdropConfig = {
|
||||
},
|
||||
required: false,
|
||||
submissionId: '1234',
|
||||
metadataKey: 'dc.some.key'
|
||||
metadataKey: 'dc.some.key',
|
||||
metadataFields: ['dc.some.key']
|
||||
} as DynamicRowArrayModelConfig;
|
||||
|
||||
export const MockRowArrayQualdropModel: DynamicRowArrayModel = new DynamicRowArrayModel(rowArrayQualdropConfig);
|
||||
|
Reference in New Issue
Block a user