Skip to content

Commit

Permalink
Merge pull request #3060 from alexandrevryghem/w2p-113560_edit-item-a…
Browse files Browse the repository at this point in the history
…dd-relationships-one-by-one_contribute-main

Fixed creation & deletion of relationships not working correctly & added same entity type relationship support
  • Loading branch information
tdonohue authored May 31, 2024
2 parents 123b6b7 + 62e07e7 commit ebf9469
Show file tree
Hide file tree
Showing 30 changed files with 1,197 additions and 572 deletions.
6 changes: 5 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
Observable,
} from 'rxjs';
import {
delay,
distinctUntilChanged,
take,
withLatestFrom,
Expand Down Expand Up @@ -136,7 +137,10 @@ export class AppComponent implements OnInit, AfterViewInit {
}

ngAfterViewInit() {
this.router.events.subscribe((event) => {
this.router.events.pipe(
// delay(0) to prevent "Expression has changed after it was checked" errors
delay(0),
).subscribe((event) => {
if (event instanceof NavigationStart) {
distinctNext(this.isRouteLoading$, true);
} else if (
Expand Down
2 changes: 2 additions & 0 deletions src/app/core/data/object-updates/object-updates.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export interface VirtualMetadataSource {

export interface RelationshipIdentifiable extends Identifiable {
nameVariant?: string;
originalItem: Item;
originalIsLeft: boolean
relatedItem: Item;
relationship: Relationship;
type: RelationshipType;
Expand Down
17 changes: 15 additions & 2 deletions src/app/core/data/object-updates/object-updates.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
filter,
map,
switchMap,
take,
} from 'rxjs/operators';

import {
Expand Down Expand Up @@ -212,17 +213,29 @@ export class ObjectUpdatesService {
* @param url The page's URL for which the changes are saved
* @param field An updated field for the page's object
*/
saveAddFieldUpdate(url: string, field: Identifiable) {
saveAddFieldUpdate(url: string, field: Identifiable): Observable<boolean> {
const update$: Observable<boolean> = this.getFieldUpdatesExclusive(url, [field]).pipe(
filter((fieldUpdates: FieldUpdates) => fieldUpdates[field.uuid].changeType === FieldChangeType.ADD),
take(1),
map(() => true),
);
this.saveFieldUpdate(url, field, FieldChangeType.ADD);
return update$;
}

/**
* Calls the saveFieldUpdate method with FieldChangeType.REMOVE
* @param url The page's URL for which the changes are saved
* @param field An updated field for the page's object
*/
saveRemoveFieldUpdate(url: string, field: Identifiable) {
saveRemoveFieldUpdate(url: string, field: Identifiable): Observable<boolean> {
const update$: Observable<boolean> = this.getFieldUpdatesExclusive(url, [field]).pipe(
filter((fieldUpdates: FieldUpdates) => fieldUpdates[field.uuid].changeType === FieldChangeType.REMOVE),
take(1),
map(() => true),
);
this.saveFieldUpdate(url, field, FieldChangeType.REMOVE);
return update$;
}

/**
Expand Down
40 changes: 33 additions & 7 deletions src/app/core/data/relationship-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
* @param id the ID of the relationship to delete
* @param copyVirtualMetadata whether to copy this relationship's virtual metadata to the related Items
* accepted values: none, all, left, right, configured
* @param shouldRefresh refresh the cache for the items in the relationship after creating
* it. Disable this if you want to add relationships in bulk, and
* want to refresh the cachemanually at the end
*/
deleteRelationship(id: string, copyVirtualMetadata: string): Observable<RemoteData<NoContent>> {
deleteRelationship(id: string, copyVirtualMetadata: string, shouldRefresh = true): Observable<RemoteData<NoContent>> {
return this.getRelationshipEndpoint(id).pipe(
isNotEmptyOperator(),
take(1),
Expand All @@ -167,7 +170,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
sendRequest(this.requestService),
switchMap((restRequest: RestRequest) => this.rdbService.buildFromRequestUUID(restRequest.uuid)),
getFirstCompletedRemoteData(),
tap(() => this.refreshRelationshipItemsInCacheByRelationship(id)),
tap(() => {
if (shouldRefresh) {
this.refreshRelationshipItemsInCacheByRelationship(id);
}
}),
);
}

Expand All @@ -178,8 +185,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
* @param item2 The second item of the relationship
* @param leftwardValue The leftward value of the relationship
* @param rightwardValue The rightward value of the relationship
* @param shouldRefresh refresh the cache for the items in the relationship after creating it.
* Disable this if you want to add relationships in bulk, and want to refresh
* the cache manually at the end
*/
addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string): Observable<RemoteData<Relationship>> {
addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string, shouldRefresh = true): Observable<RemoteData<Relationship>> {
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list');
Expand All @@ -194,8 +204,12 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
sendRequest(this.requestService),
switchMap((restRequest: RestRequest) => this.rdbService.buildFromRequestUUID(restRequest.uuid)),
getFirstCompletedRemoteData(),
tap(() => this.refreshRelationshipItemsInCache(item1)),
tap(() => this.refreshRelationshipItemsInCache(item2)),
tap(() => {
if (shouldRefresh) {
this.refreshRelationshipItemsInCache(item1);
this.refreshRelationshipItemsInCache(item2);
}
}),
) as Observable<RemoteData<Relationship>>;
}

Expand Down Expand Up @@ -223,7 +237,7 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
* Method to remove an item that's part of a relationship from the cache
* @param item The item to remove from the cache
*/
public refreshRelationshipItemsInCache(item) {
public refreshRelationshipItemsInCache(item: Item): void {
this.objectCache.remove(item._links.self.href);
this.requestService.removeByHrefSubstring(item.uuid);
observableCombineLatest([
Expand Down Expand Up @@ -336,7 +350,19 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
} else {
findListOptions.searchParams = searchParams;
}
return this.searchBy('byLabel', findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);

// always set reRequestOnStale to false here, so it doesn't happen automatically in BaseDataService
const result$ = this.searchBy('byLabel', findListOptions, useCachedVersionIfAvailable, false, ...linksToFollow);

// add this result as a dependency of the item, meaning that if the item is invalided, this
// result will be as well
this.addDependency(result$, item._links.self.href);

// do the reRequestOnStale call here, to ensure any re-requests also get added as dependencies
return result$.pipe(
this.reRequestStaleRemoteData(reRequestOnStale, () =>
this.getItemRelationshipsByLabel(item, label, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)),
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl
*/
updates$: Observable<FieldUpdates>;

hasChanges$: Observable<boolean>;

isReinstatable$: Observable<boolean>;

/**
* Route to the item's page
*/
Expand Down Expand Up @@ -101,10 +105,9 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl
}

this.discardTimeOut = environment.item.edit.undoTimeout;
this.url = this.router.url;
if (this.url.indexOf('?') > 0) {
this.url = this.url.substr(0, this.url.indexOf('?'));
}
this.url = this.router.url.split('?')[0];
this.hasChanges$ = this.hasChanges();
this.isReinstatable$ = this.isReinstatable();
this.hasChanges().pipe(first()).subscribe((hasChanges) => {
if (!hasChanges) {
this.initializeOriginalFields();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
class="fas fa-upload"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.upload-button" | translate}}</span>
</button>
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
<button class="btn btn-warning" *ngIf="isReinstatable$ | async"
[attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate"
(click)="reinstate()"><i
class="fas fa-undo-alt"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span>
</button>
<button class="btn btn-primary" [disabled]="(hasChanges() | async) !== true || submitting"
<button class="btn btn-primary" [disabled]="(hasChanges$ | async) !== true || submitting"
[attr.aria-label]="'item.edit.bitstreams.save-button' | translate"
(click)="submit()"><i
class="fas fa-save"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span>
</button>
<button class="btn btn-danger" *ngIf="(isReinstatable() | async) !== true"
<button class="btn btn-danger" *ngIf="(isReinstatable$ | async) !== true"
[attr.aria-label]="'item.edit.bitstreams.discard-button' | translate"
[disabled]="(hasChanges() | async) !== true || submitting"
[disabled]="(hasChanges$ | async) !== true || submitting"
(click)="discard()"><i
class="fas fa-times"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.discard-button" | translate}}</span>
Expand Down Expand Up @@ -52,21 +52,21 @@

<div class="button-row bottom">
<div class="mt-4 float-right space-children-mr ml-gap">
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
<button class="btn btn-warning" *ngIf="isReinstatable$ | async"
[attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate"
(click)="reinstate()"><i
class="fas fa-undo-alt"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span>
</button>
<button class="btn btn-primary" [disabled]="(hasChanges() | async) !== true || submitting"
<button class="btn btn-primary" [disabled]="(hasChanges$ | async) !== true || submitting"
[attr.aria-label]="'item.edit.bitstreams.save-button' | translate"
(click)="submit()"><i
class="fas fa-save"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span>
</button>
<button class="btn btn-danger" *ngIf="(isReinstatable() | async) !== true"
<button class="btn btn-danger" *ngIf="(isReinstatable$ | async) !== true"
[attr.aria-label]="'item.edit.bitstreams.discard-button' | translate"
[disabled]="(hasChanges() | async) !== true || submitting"
[disabled]="(hasChanges$ | async) !== true || submitting"
(click)="discard()"><i
class="fas fa-times"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.discard-button" | translate}}</span>
Expand Down
Loading

0 comments on commit ebf9469

Please sign in to comment.