mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
use reorderables instead of relationships
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { metadataRepresentationComponent } from '../../../../shared/metadata-representation/metadata-representation.decorator';
|
||||
import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model';
|
||||
import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component';
|
||||
@@ -11,5 +11,8 @@ import { ItemMetadataRepresentationListElementComponent } from '../../../../shar
|
||||
/**
|
||||
* The component for displaying an item of the type Person as a metadata field
|
||||
*/
|
||||
export class PersonItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent {
|
||||
export class PersonItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
console.log('this.metadataRepresentation', this.metadataRepresentation);
|
||||
}
|
||||
}
|
||||
|
@@ -54,8 +54,8 @@
|
||||
|
||||
<div *ngIf="hasRelationLookup" class="mt-3">
|
||||
<ul class="list-unstyled" cdkDropList (cdkDropListDropped)="moveSelection($event)">
|
||||
<ds-existing-metadata-list-element cdkDrag [cdkDragData]="relationship" *ngFor="let relationship of relationships; trackBy: trackRelationship"
|
||||
[relationship]="relationship"
|
||||
<ds-existing-metadata-list-element cdkDrag [cdkDragData]="relationship" *ngFor="let reorderable of reorderables; trackBy: trackReorderable"
|
||||
[reoRel]="reorderable"
|
||||
[submissionItem]="item"
|
||||
[listId]="listId"
|
||||
[metadataFields]="model.metadataFields"
|
||||
|
@@ -50,6 +50,10 @@ import {
|
||||
DynamicNGBootstrapTimePickerComponent
|
||||
} from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
Reorderable,
|
||||
ReorderableRelationship
|
||||
} from './existing-metadata-list-element/existing-metadata-list-element.component';
|
||||
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD } from './models/typeahead/dynamic-typeahead.model';
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
|
||||
@@ -176,15 +180,14 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
@Input() hasErrorMessaging = false;
|
||||
@Input() layout = null as DynamicFormLayout;
|
||||
@Input() model: any;
|
||||
relationships$: Observable<Relationship[]>;
|
||||
relationships: Relationship[];
|
||||
reorderables$: Observable<ReorderableRelationship[]>;
|
||||
reorderables: ReorderableRelationship[];
|
||||
hasRelationLookup: boolean;
|
||||
modalRef: NgbModalRef;
|
||||
item: Item;
|
||||
listId: string;
|
||||
searchConfig: string;
|
||||
|
||||
|
||||
/**
|
||||
* List of subscriptions to unsubscribe from
|
||||
*/
|
||||
@@ -223,6 +226,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
|
||||
ngOnInit(): void {
|
||||
this.hasRelationLookup = hasValue(this.model.relationship);
|
||||
this.reorderables = [];
|
||||
if (this.hasRelationLookup) {
|
||||
this.listId = 'list-' + this.model.relationship.relationshipType;
|
||||
const item$ = this.submissionObjectService
|
||||
@@ -238,7 +242,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
);
|
||||
|
||||
this.subs.push(item$.subscribe((item) => this.item = item));
|
||||
this.relationships$ = item$.pipe(
|
||||
this.reorderables$ = item$.pipe(
|
||||
switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType)
|
||||
.pipe(
|
||||
getAllSucceededRemoteData(),
|
||||
@@ -251,28 +255,24 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
relationship.leftItem.pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
map((item: Item) => {
|
||||
return { relationship, left: item.uuid === this.item.uuid }
|
||||
map((leftItem: Item) => {
|
||||
return new ReorderableRelationship(relationship, leftItem.uuid !== this.item.uuid)
|
||||
}),
|
||||
)
|
||||
))),
|
||||
map((relationships: { relationship: Relationship, left: boolean }[]) =>
|
||||
relationships
|
||||
.sort((
|
||||
a: { relationship: Relationship, left: boolean },
|
||||
b: { relationship: Relationship, left: boolean }
|
||||
) => {
|
||||
const placeA: number = a.left ? a.relationship.leftPlace : a.relationship.rightPlace;
|
||||
const placeB: number = b.left ? b.relationship.leftPlace : b.relationship.rightPlace;
|
||||
return Math.sign(placeA - placeB);
|
||||
})
|
||||
.map((relationship) => relationship.relationship)
|
||||
)
|
||||
map((relationships: ReorderableRelationship[]) =>
|
||||
relationships
|
||||
.sort((a: Reorderable, b: Reorderable) => {
|
||||
return Math.sign(a.getPlace() - b.getPlace());
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
this.relationships$.subscribe((rels) => this.relationships = rels);
|
||||
this.subs.push(this.reorderables$.subscribe((rs) => {
|
||||
this.reorderables = rs
|
||||
}));
|
||||
|
||||
this.relationService.getRelatedItemsByLabel(this.item, this.model.relationship.relationshipType).pipe(
|
||||
map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))),
|
||||
@@ -334,27 +334,18 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
modalComp.item = this.item;
|
||||
}
|
||||
|
||||
|
||||
moveSelection(event: CdkDragDrop<Relationship>) {
|
||||
moveItemInArray(this.relationships, event.previousIndex, event.currentIndex);
|
||||
moveItemInArray(this.reorderables, event.previousIndex, event.currentIndex);
|
||||
this.zone.runOutsideAngular(() => {
|
||||
observableCombineLatest(
|
||||
this.relationships.map((relationship: Relationship, index: number) =>
|
||||
relationship.leftItem.pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
map((item: Item) => {
|
||||
const left: boolean = item.uuid === this.item.uuid;
|
||||
if (left) {
|
||||
return { relationship, left: item.uuid === this.item.uuid, oldIndex: relationship.leftPlace, newIndex: index }
|
||||
} else {
|
||||
return { relationship, left: item.uuid === this.item.uuid, oldIndex: relationship.rightPlace, newIndex: index }
|
||||
}
|
||||
}),
|
||||
)
|
||||
this.reorderables.map((reo: Reorderable, index: number) => {
|
||||
reo.oldIndex = reo.getPlace();
|
||||
reo.newIndex = index;
|
||||
return reo;
|
||||
}
|
||||
)
|
||||
).pipe(
|
||||
switchMap((relationships: { relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }[]) =>
|
||||
switchMap((relationships: Array<{ relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }>) =>
|
||||
observableCombineLatest(relationships.map((rel: { relationship: Relationship, left: boolean, oldIndex: number, newIndex: number }) => {
|
||||
if (rel.oldIndex !== rel.newIndex) {
|
||||
return this.relationshipService.updatePlace(rel.relationship, rel.newIndex, rel.left);
|
||||
@@ -381,7 +372,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
||||
/**
|
||||
* Prevent unnecessary rerendering so fields don't lose focus
|
||||
*/
|
||||
trackRelationship(index, relationship: Relationship) {
|
||||
return hasValue(relationship) ? relationship.id : undefined;
|
||||
trackReorderable(index, reorderable: Reorderable) {
|
||||
return hasValue(reorderable) ? reorderable.getId() : undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<li *ngIf="metadataRepresentation$ | async">
|
||||
<li *ngIf="metadataRepresentation">
|
||||
<button type="button" class="close float-left" aria-label="Move button" cdkDragHandle>
|
||||
<i aria-hidden="true" class="fas fa-arrows-alt fa-xs"></i>
|
||||
</button>
|
||||
@@ -6,6 +6,6 @@
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<span class="d-inline-block align-middle ml-1">
|
||||
<ds-metadata-representation-loader [mdRepresentation]="metadataRepresentation$ | async"></ds-metadata-representation-loader>
|
||||
<ds-metadata-representation-loader [mdRepresentation]="metadataRepresentation"></ds-metadata-representation-loader>
|
||||
</span>
|
||||
</li>
|
||||
|
@@ -1,10 +1,16 @@
|
||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../../core/shared/operators';
|
||||
import { MetadataRepresentation } from '../../../../../core/shared/metadata-representation/metadata-representation.model';
|
||||
import {
|
||||
getAllSucceededRemoteData,
|
||||
getRemoteDataPayload,
|
||||
getSucceededRemoteData
|
||||
} from '../../../../../core/shared/operators';
|
||||
import { hasValue, isNotEmpty } from '../../../../empty.util';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { of as observableOf, Subscription } from 'rxjs';
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import { Relationship } from '../../../../../core/shared/item-relationships/relationship.model';
|
||||
import { combineLatest as observableCombineLatest } from 'rxjs';
|
||||
import { combineLatest as observableCombineLatest, of } from 'rxjs';
|
||||
import { MetadataValue } from '../../../../../core/shared/metadata.models';
|
||||
import { ItemMetadataRepresentation } from '../../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
|
||||
import { RelationshipOptions } from '../../models/relationship-options.model';
|
||||
@@ -14,19 +20,55 @@ import { Store } from '@ngrx/store';
|
||||
import { AppState } from '../../../../../app.reducer';
|
||||
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
|
||||
|
||||
export abstract class Reorderable {
|
||||
constructor(public oldIndex?: number, public newIndex?: number) {
|
||||
}
|
||||
|
||||
abstract getId(): string;
|
||||
abstract getPlace(): number;
|
||||
}
|
||||
|
||||
export class ReorderableRelationship extends Reorderable {
|
||||
relationship: Relationship;
|
||||
useLeftItem: boolean;
|
||||
|
||||
constructor(relationship: Relationship, useLeftItem: boolean, oldIndex?: number, newIndex?: number) {
|
||||
super(oldIndex, newIndex);
|
||||
this.relationship = relationship;
|
||||
this.useLeftItem = useLeftItem;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.relationship.id;
|
||||
}
|
||||
|
||||
getPlace(): number {
|
||||
if (this.useLeftItem) {
|
||||
return this.relationship.rightPlace
|
||||
} else {
|
||||
return this.relationship.leftPlace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ds-existing-metadata-list-element',
|
||||
templateUrl: './existing-metadata-list-element.component.html',
|
||||
styleUrls: ['./existing-metadata-list-element.component.scss']
|
||||
})
|
||||
export class ExistingMetadataListElementComponent implements OnChanges {
|
||||
export class ExistingMetadataListElementComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() listId: string;
|
||||
@Input() submissionItem: Item;
|
||||
@Input() relationship: Relationship;
|
||||
@Input() reoRel: ReorderableRelationship;
|
||||
@Input() metadataFields: string[];
|
||||
@Input() relationshipOptions: RelationshipOptions;
|
||||
metadataRepresentation$;
|
||||
relatedItem$;
|
||||
metadataRepresentation: MetadataRepresentation;
|
||||
relatedItem: Item;
|
||||
|
||||
/**
|
||||
* List of subscriptions to unsubscribe from
|
||||
*/
|
||||
private subs: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
private selectableListService: SelectableListService,
|
||||
@@ -34,49 +76,44 @@ export class ExistingMetadataListElementComponent implements OnChanges {
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
console.log('reoRel', this.reoRel);
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
const leftItem$ = this.relationship.leftItem.pipe(
|
||||
getSucceededRemoteData(),
|
||||
const item$ = this.reoRel.useLeftItem ?
|
||||
this.reoRel.relationship.leftItem : this.reoRel.relationship.rightItem;
|
||||
|
||||
this.subs.push(item$.pipe(
|
||||
getAllSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid))
|
||||
);
|
||||
).subscribe((item: Item) => {
|
||||
this.relatedItem = item;
|
||||
|
||||
const rightItem$ = this.relationship.rightItem.pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid))
|
||||
);
|
||||
|
||||
this.relatedItem$ = observableCombineLatest(
|
||||
leftItem$,
|
||||
rightItem$,
|
||||
).pipe(
|
||||
map((items: Item[]) =>
|
||||
items.find((item) => item.uuid !== this.submissionItem.uuid)
|
||||
)
|
||||
);
|
||||
|
||||
this.metadataRepresentation$ = this.relatedItem$.pipe(
|
||||
map((relatedItem: Item) => {
|
||||
console.log(relatedItem);
|
||||
const relationMD: MetadataValue = this.submissionItem.firstMetadata(this.relationshipOptions.metadataField, { value: relatedItem.uuid });
|
||||
console.log(relationMD);
|
||||
if (hasValue(relationMD)) {
|
||||
const metadataRepresentationMD: MetadataValue = this.submissionItem.firstMetadata(this.metadataFields, { authority: relationMD.authority });
|
||||
return Object.assign(
|
||||
new ItemMetadataRepresentation(metadataRepresentationMD),
|
||||
relatedItem
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
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 });
|
||||
this.metadataRepresentation = Object.assign(
|
||||
new ItemMetadataRepresentation(metadataRepresentationMD),
|
||||
this.relatedItem
|
||||
)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
removeSelection() {
|
||||
this.relatedItem$.pipe(take(1)).subscribe((relatedItem: Item) => {
|
||||
this.selectableListService.deselectSingle(this.listId, Object.assign(new ItemSearchResult(), { indexableObject: relatedItem }));
|
||||
this.store.dispatch(new RemoveRelationshipAction(this.submissionItem, relatedItem, this.relationshipOptions.relationshipType))
|
||||
})
|
||||
this.selectableListService.deselectSingle(this.listId, Object.assign(new ItemSearchResult(), { indexableObject: this.relatedItem }));
|
||||
this.store.dispatch(new RemoveRelationshipAction(this.submissionItem, this.relatedItem, this.relationshipOptions.relationshipType))
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.subs
|
||||
.filter((sub) => hasValue(sub))
|
||||
.forEach((sub) => sub.unsubscribe());
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user