mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge remote-tracking branch 'alexandre/fix-create-relationship-not-working-between-same-types_contribute-7.6' into w2p-113560_edit-item-add-relationships-one-by-one
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<h5>
|
<h5>
|
||||||
{{getRelationshipMessageKey() | async | translate}}
|
{{relationshipMessageKey$ | async | translate}}
|
||||||
<button class="ml-2 btn btn-success" [disabled]="(hasChanges | async)" (click)="openLookup()">
|
<button class="ml-2 btn btn-success" [disabled]="(hasChanges | async)" (click)="openLookup()">
|
||||||
<i class="fas fa-plus"></i>
|
<i class="fas fa-plus"></i>
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.relationships.edit.buttons.add" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.relationships.edit.buttons.add" | translate}}</span>
|
||||||
|
@@ -47,7 +47,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
SelectableListService
|
SelectableListService
|
||||||
} from '../../../../shared/object-list/selectable-list/selectable-list.service';
|
} from '../../../../shared/object-list/selectable-list/selectable-list.service';
|
||||||
import { SearchResult } from '../../../../shared/search/models/search-result.model';
|
import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model';
|
||||||
import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model';
|
import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model';
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
@@ -63,6 +63,7 @@ import { FieldChangeType } from '../../../../core/data/object-updates/field-chan
|
|||||||
import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
|
import { APP_CONFIG, AppConfig } from '../../../../../config/app-config.interface';
|
||||||
import { itemLinksToFollow } from '../../../../shared/utils/relation-query.utils';
|
import { itemLinksToFollow } from '../../../../shared/utils/relation-query.utils';
|
||||||
import { EditItemRelationshipsService } from '../edit-item-relationships.service';
|
import { EditItemRelationshipsService } from '../edit-item-relationships.service';
|
||||||
|
import { Identifiable } from '../../../../core/data/object-updates/identifiable.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-edit-relationship-list',
|
selector: 'ds-edit-relationship-list',
|
||||||
@@ -101,7 +102,7 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* The event emmiter to submit the new information
|
* The event emmiter to submit the new information
|
||||||
*/
|
*/
|
||||||
@Output() submit: EventEmitter<any> = new EventEmitter();
|
@Output() submitModal: EventEmitter<void> = new EventEmitter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable that emits the left and right item type of {@link relationshipType} simultaneously.
|
* Observable that emits the left and right item type of {@link relationshipType} simultaneously.
|
||||||
@@ -116,6 +117,11 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private relatedEntityType$: Observable<ItemType>;
|
private relatedEntityType$: Observable<ItemType>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The translation key for the entity type
|
||||||
|
*/
|
||||||
|
relationshipMessageKey$: Observable<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list ID to save selected entities under
|
* The list ID to save selected entities under
|
||||||
*/
|
*/
|
||||||
@@ -185,11 +191,10 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
* Get the i18n message key for this relationship type
|
* Get the i18n message key for this relationship type
|
||||||
*/
|
*/
|
||||||
public getRelationshipMessageKey(): Observable<string> {
|
public getRelationshipMessageKey(): Observable<string> {
|
||||||
|
return observableCombineLatest([
|
||||||
return observableCombineLatest(
|
|
||||||
this.getLabel(),
|
this.getLabel(),
|
||||||
this.relatedEntityType$,
|
this.relatedEntityType$,
|
||||||
).pipe(
|
]).pipe(
|
||||||
map(([label, relatedEntityType]) => {
|
map(([label, relatedEntityType]) => {
|
||||||
if (hasValue(label) && label.indexOf('is') > -1 && label.indexOf('Of') > -1) {
|
if (hasValue(label) && label.indexOf('is') > -1 && label.indexOf('Of') > -1) {
|
||||||
const relationshipLabel = `${label.substring(2, label.indexOf('Of'))}`;
|
const relationshipLabel = `${label.substring(2, label.indexOf('Of'))}`;
|
||||||
@@ -254,11 +259,11 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
modalComp.collection = collection;
|
modalComp.collection = collection;
|
||||||
});
|
});
|
||||||
|
|
||||||
modalComp.select = (...selectableObjects: SearchResult<Item>[]) => {
|
modalComp.select = (...selectableObjects: ItemSearchResult[]) => {
|
||||||
selectableObjects.forEach((searchResult) => {
|
selectableObjects.forEach((searchResult) => {
|
||||||
const relatedItem: Item = searchResult.indexableObject;
|
const relatedItem: Item = searchResult.indexableObject;
|
||||||
|
|
||||||
const foundIndex = modalComp.toRemove.findIndex( el => el.uuid === relatedItem.uuid);
|
const foundIndex = modalComp.toRemove.findIndex((itemSearchResult: ItemSearchResult) => itemSearchResult.indexableObject.uuid === relatedItem.uuid);
|
||||||
|
|
||||||
if (foundIndex !== -1) {
|
if (foundIndex !== -1) {
|
||||||
modalComp.toRemove.splice(foundIndex,1);
|
modalComp.toRemove.splice(foundIndex,1);
|
||||||
@@ -282,7 +287,7 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
modalComp.deselect = (...selectableObjects: SearchResult<Item>[]) => {
|
modalComp.deselect = (...selectableObjects: ItemSearchResult[]) => {
|
||||||
selectableObjects.forEach((searchResult) => {
|
selectableObjects.forEach((searchResult) => {
|
||||||
const relatedItem: Item = searchResult.indexableObject;
|
const relatedItem: Item = searchResult.indexableObject;
|
||||||
|
|
||||||
@@ -350,7 +355,7 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
).subscribe({
|
).subscribe({
|
||||||
complete: () => {
|
complete: () => {
|
||||||
this.editItemRelationshipsService.submit(this.item, this.url)
|
this.editItemRelationshipsService.submit(this.item, this.url)
|
||||||
this.submit.emit();
|
this.submitModal.emit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -393,67 +398,6 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the existing field updates regarding a relationship with a given item
|
|
||||||
* @param relatedItem The item for which to get the existing field updates
|
|
||||||
*/
|
|
||||||
private getFieldUpdatesForRelatedItem(relatedItem: Item): Observable<RelationshipIdentifiable[]> {
|
|
||||||
return this.updates$.pipe(
|
|
||||||
take(1),
|
|
||||||
map((updates) => Object.values(updates)
|
|
||||||
.map((update) => update.field as RelationshipIdentifiable)
|
|
||||||
.filter((field) => field.relationship)
|
|
||||||
),
|
|
||||||
mergeMap((identifiables) =>
|
|
||||||
observableCombineLatest(
|
|
||||||
identifiables.map((identifiable) => this.getRelatedItem(identifiable.relationship))
|
|
||||||
).pipe(
|
|
||||||
defaultIfEmpty([]),
|
|
||||||
map((relatedItems) => {
|
|
||||||
return identifiables.filter( (identifiable, index) => {
|
|
||||||
return relatedItems[index].uuid === relatedItem.uuid;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given item is related with the item we are editing relationships
|
|
||||||
* @param relatedItem The item for which to get the existing field updates
|
|
||||||
*/
|
|
||||||
private getIsRelatedItem(relatedItem: Item): Observable<boolean> {
|
|
||||||
|
|
||||||
return this.currentItemIsLeftItem$.pipe(
|
|
||||||
take(1),
|
|
||||||
map( isLeft => {
|
|
||||||
if (isLeft) {
|
|
||||||
const listOfRelatedItems = this.item.allMetadataValues( 'relation.' + this.relationshipType.leftwardType );
|
|
||||||
return !!listOfRelatedItems.find( (uuid) => uuid === relatedItem.uuid );
|
|
||||||
} else {
|
|
||||||
const listOfRelatedItems = this.item.allMetadataValues( 'relation.' + this.relationshipType.rightwardType );
|
|
||||||
return !!listOfRelatedItems.find( (uuid) => uuid === relatedItem.uuid );
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the related item for a given relationship
|
|
||||||
* @param relationship The relationship for which to get the related item
|
|
||||||
*/
|
|
||||||
private getRelatedItem(relationship: Relationship): Observable<Item> {
|
|
||||||
return this.relationshipService.isLeftItem(relationship, this.item).pipe(
|
|
||||||
switchMap((isLeftItem) => isLeftItem ? relationship.rightItem : relationship.leftItem),
|
|
||||||
getFirstSucceededRemoteData(),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
) as Observable<Item>;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// store the left and right type of the relationship in a single observable
|
// store the left and right type of the relationship in a single observable
|
||||||
this.relationshipLeftAndRightType$ = observableCombineLatest([
|
this.relationshipLeftAndRightType$ = observableCombineLatest([
|
||||||
@@ -465,8 +409,14 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
))) as Observable<[ItemType, ItemType]>;
|
))) as Observable<[ItemType, ItemType]>;
|
||||||
|
|
||||||
this.relatedEntityType$ = this.relationshipLeftAndRightType$.pipe(
|
this.relatedEntityType$ = this.relationshipLeftAndRightType$.pipe(
|
||||||
map((relatedTypes: ItemType[]) => relatedTypes.find((relatedType) => relatedType.uuid !== this.itemType.uuid)),
|
map(([leftType, rightType]: [ItemType, ItemType]) => {
|
||||||
hasValueOperator()
|
if (leftType.uuid !== this.itemType.uuid) {
|
||||||
|
return leftType;
|
||||||
|
} else {
|
||||||
|
return rightType;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
hasValueOperator(),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.relatedEntityType$.pipe(
|
this.relatedEntityType$.pipe(
|
||||||
@@ -475,6 +425,8 @@ export class EditRelationshipListComponent implements OnInit, OnDestroy {
|
|||||||
(relatedEntityType) => this.listId = `edit-relationship-${this.itemType.id}-${relatedEntityType.id}`
|
(relatedEntityType) => this.listId = `edit-relationship-${this.itemType.id}-${relatedEntityType.id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.relationshipMessageKey$ = this.getRelationshipMessageKey();
|
||||||
|
|
||||||
this.subs.push(this.relationshipLeftAndRightType$.pipe(
|
this.subs.push(this.relationshipLeftAndRightType$.pipe(
|
||||||
map(([leftType, rightType]: [ItemType, ItemType]) => {
|
map(([leftType, rightType]: [ItemType, ItemType]) => {
|
||||||
if (leftType.id === this.itemType.id) {
|
if (leftType.id === this.itemType.id) {
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
<div class="item-relationships">
|
<div class="item-relationships">
|
||||||
<ng-container *ngVar="entityType$ | async as entityType">
|
<ng-container *ngIf="entityType$ | async as entityType">
|
||||||
<ng-container *ngIf="entityType">
|
|
||||||
<div class="button-row top d-flex space-children-mr">
|
<div class="button-row top d-flex space-children-mr">
|
||||||
<button class="btn btn-danger ml-auto" *ngIf="!(isReinstatable() | async)"
|
<button class="btn btn-danger ml-auto" *ngIf="!(isReinstatable() | async)"
|
||||||
[disabled]="!(hasChanges() | async)"
|
[disabled]="!(hasChanges() | async)"
|
||||||
@@ -19,20 +18,20 @@
|
|||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngVar="relationshipTypes$ | async as relationshipTypes">
|
<div *ngIf="relationshipTypes$ | async as relationshipTypes; else loading" class="mb-4">
|
||||||
<ng-container *ngIf="relationshipTypes">
|
<div *ngFor="let relationshipType of relationshipTypes; trackBy: trackById" class="mb-4">
|
||||||
<div *ngFor="let relationshipType of relationshipTypes" class="mb-4">
|
|
||||||
<ds-edit-relationship-list
|
<ds-edit-relationship-list
|
||||||
[url]="url"
|
[url]="url"
|
||||||
[item]="item"
|
[item]="item"
|
||||||
[itemType]="entityType$ | async"
|
[itemType]="entityType"
|
||||||
[relationshipType]="relationshipType"
|
[relationshipType]="relationshipType"
|
||||||
[hasChanges]="hasChanges()"
|
[hasChanges]="hasChanges()"
|
||||||
></ds-edit-relationship-list>
|
></ds-edit-relationship-list>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</div>
|
||||||
<ds-themed-loading *ngIf="!relationshipTypes"></ds-themed-loading>
|
<ng-template #loading>
|
||||||
</ng-container>
|
<ds-themed-loading></ds-themed-loading>
|
||||||
|
</ng-template>
|
||||||
<div class="button-row bottom">
|
<div class="button-row bottom">
|
||||||
<div class="float-right space-children-mr ml-gap">
|
<div class="float-right space-children-mr ml-gap">
|
||||||
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
@@ -53,7 +52,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
|
||||||
<div *ngIf="!entityType"
|
<div *ngIf="!entityType"
|
||||||
class="alert alert-info mt-2" role="alert">
|
class="alert alert-info mt-2" role="alert">
|
||||||
{{ 'item.edit.relationships.no-entity-type' | translate }}
|
{{ 'item.edit.relationships.no-entity-type' | translate }}
|
||||||
|
@@ -121,6 +121,13 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to prevent unnecessary for loop re-rendering
|
||||||
|
*/
|
||||||
|
trackById(index: number, relationshipType: RelationshipType): string {
|
||||||
|
return relationshipType.id;
|
||||||
|
}
|
||||||
|
|
||||||
getRelationshipTypeFollowLinks() {
|
getRelationshipTypeFollowLinks() {
|
||||||
return [
|
return [
|
||||||
followLink('leftType'),
|
followLink('leftType'),
|
||||||
|
@@ -29,6 +29,7 @@ import { RemoteDataBuildService } from '../../../../../core/cache/builders/remot
|
|||||||
import { getAllSucceededRemoteDataPayload } from '../../../../../core/shared/operators';
|
import { getAllSucceededRemoteDataPayload } from '../../../../../core/shared/operators';
|
||||||
import { followLink } from '../../../../utils/follow-link-config.model';
|
import { followLink } from '../../../../utils/follow-link-config.model';
|
||||||
import { RelationshipType } from '../../../../../core/shared/item-relationships/relationship-type.model';
|
import { RelationshipType } from '../../../../../core/shared/item-relationships/relationship-type.model';
|
||||||
|
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dynamic-lookup-relation-modal',
|
selector: 'ds-dynamic-lookup-relation-modal',
|
||||||
@@ -141,12 +142,12 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
|
|||||||
/**
|
/**
|
||||||
* Maintain the list of the related items to be added
|
* Maintain the list of the related items to be added
|
||||||
*/
|
*/
|
||||||
toAdd = [];
|
toAdd: ItemSearchResult[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain the list of the related items to be removed
|
* Maintain the list of the related items to be removed
|
||||||
*/
|
*/
|
||||||
toRemove = [];
|
toRemove: ItemSearchResult[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable buttons while the submit button is pressed
|
* Disable buttons while the submit button is pressed
|
||||||
|
Reference in New Issue
Block a user