Skip to content

Commit

Permalink
general: managing multiple resources in a route
Browse files Browse the repository at this point in the history
* Adds 2 new parameters to the ActionStatus interface.
* Updates the precedence of canRead, canUpdate, canDelete
  and canUse functions.
* Updates add button to reflect new routerLink parameter.
* Adds a parameter to the deleteRecord function and modify the event.

Co-Authored-by: Bertrand Zuchuat <[email protected]>
  • Loading branch information
Garfield-fr committed Jul 11, 2023
1 parent 64ab4f8 commit 1431af5
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 41 deletions.
5 changes: 4 additions & 1 deletion projects/rero/ng-core/src/lib/record/action-status.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* RERO angular core
* Copyright (C) 2020 RERO
* Copyright (C) 2019-2023 RERO
* Copyright (C) 2019-2023 UCLouvain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -22,4 +23,6 @@ export interface ActionStatus {
can: boolean;
message: string;
url?: string;
routerLink?: string[];
type?: string | undefined | null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export class DetailComponent implements OnInit, OnDestroy {
this._location.back();
}
});

this._recordUiService.canDeleteRecord$(this.record, this._type).subscribe(result => {
this.deleteStatus = result;
});
Expand Down
35 changes: 22 additions & 13 deletions projects/rero/ng-core/src/lib/record/record-ui.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* RERO angular core
* Copyright (C) 2020 RERO
* Copyright (C) 2019-2023 RERO
* Copyright (C) 2019-2023 UCLouvain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand Down Expand Up @@ -202,6 +203,10 @@ export class RecordUiService {
*/
canUpdateRecord$(record: object, type: string): Observable<ActionStatus> {
const config = this.getResourceConfig(type);
// The canUpdate function takes precedence over permissions
if (config.canUpdate) {
return config.canUpdate(record).pipe(first());
}
if (config.permissions) {
const permissions = config.permissions(record);
return permissions.pipe(
Expand All @@ -214,9 +219,7 @@ export class RecordUiService {
})
);
}
return (config.canUpdate)
? config.canUpdate(record).pipe(first())
: of({ can: true, message: '' });
return of({ can: true, message: '' });
}

/**
Expand All @@ -227,6 +230,10 @@ export class RecordUiService {
*/
canDeleteRecord$(record: object, type: string): Observable<ActionStatus> {
const config = this.getResourceConfig(type);
// The canDelete function takes precedence over permissions
if (config.canDelete) {
return config.canDelete(record).pipe(first());
}
if (config.permissions) {
const permissions = config.permissions(record);
return permissions.pipe(
Expand All @@ -239,9 +246,7 @@ export class RecordUiService {
})
);
}
return (config.canDelete)
? config.canDelete(record).pipe(first())
: of({ can: true, message: '' });
return of({ can: true, message: '' });
}

/**
Expand All @@ -252,6 +257,10 @@ export class RecordUiService {
*/
canReadRecord$(record: object, type: string): Observable<ActionStatus> {
const config = this.getResourceConfig(type);
// The canRead function takes precedence over permissions
if (config.canRead) {
return config.canRead(record).pipe(first());
}
if (config.permissions) {
const permissions = config.permissions(record);
return permissions.pipe(
Expand All @@ -264,9 +273,7 @@ export class RecordUiService {
})
);
}
return (config.canRead)
? config.canRead(record).pipe(first())
: of({ can: true, message: '' });
return of({ can: true, message: '' });
}

/**
Expand All @@ -277,14 +284,16 @@ export class RecordUiService {
*/
canUseRecord$(record: object, type: string): Observable<ActionStatus> {
const config = this.getResourceConfig(type);
// The canUse function takes precedence over permissions
if (config.canUse) {
return config.canUse(record).pipe(first());
}
if (config.permissions) {
const permissions = config.permissions(record);
if ('canUse' in permissions) {
return permissions.canUse;
}
}
return (config.canUse)
? config.canUse(record).pipe(first())
: of({ can: false, message: '' });
return of({ can: false, message: '' });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ export class RecordSearchPageComponent implements OnInit, OnDestroy {
return;
}

const defaulSortValue = this.q ? 'defaultQuery' : 'defaultNoQuery';
const defaultSortValue = this.q ? 'defaultQuery' : 'defaultNoQuery';
config.sortOptions.forEach((option: SortOption) => {
if (option[defaulSortValue] === true) {
if (option[defaultSortValue] === true) {
this.sort = option.value;
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
RERO angular core
Copyright (C) 2022 RERO
Copyright (C) 2022 UCLouvain
Copyright (C) 2019-2023 RERO
Copyright (C) 2019-2023 UCLouvain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
Expand Down Expand Up @@ -36,7 +36,7 @@ <h5 *ngIf="typesInTabs.length === 1 && showLabel">
</h5>
<ng-container *ngIf="hasNoRecord; else results">
<div class="alert alert-info my-4">{{ emptyRecordMessage }}</div>
<a class="btn btn-primary" routerLink="new" *ngIf="adminMode.can && addStatus.can">
<a class="btn btn-primary" [routerLink]="addStatus.routerLink || ['new']" *ngIf="adminMode.can && addStatus.can">
<i class="fa fa-plus mr-0 mr-sm-1"></i>
<span class="d-none d-sm-inline" translate>Add</span>
</a>
Expand All @@ -56,7 +56,7 @@ <h5 *ngIf="typesInTabs.length === 1 && showLabel">
<strong>{{ resultsText }}</strong>
</div>
<div class="col ml-auto text-right">
<a class="btn btn-primary" [routerLink]="addStatus?.url || ['new']" *ngIf="adminMode.can && addStatus.can">
<a id="search-add-button" class="btn btn-primary" [routerLink]="addStatus.routerLink || ['new']" *ngIf="adminMode.can && addStatus.can">
<i class="fa fa-plus mr-0 mr-sm-1"></i>
<span class="d-none d-sm-inline" translate>Add</span>
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ describe('RecordSearchComponent', () => {
component.types[0].total = 2;

expect(component.types[0].total).toBe(2);
component.deleteRecord('1');
component.deleteRecord({ pid: '1' });
expect(component.types[0].total).toBe(2);
});

Expand All @@ -242,7 +242,7 @@ describe('RecordSearchComponent', () => {
component['_config'].total = 2;

expect(component['_config'].total).toBe(2);
component.deleteRecord('1');
component.deleteRecord({ pid: '1' });
tick(10000); // wait for refreshing records
expect(component['_config'].total).toBe(1);
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,11 @@ export class RecordSearchComponent implements OnInit, OnChanges, OnDestroy {

/**
* Delete a record by its PID.
* @param pid - string, PID to delete
* @param event - object
*/
deleteRecord(pid: string) {
this._recordUiService.deleteRecord(this.currentType, pid).pipe(
deleteRecord(event: { pid: string, type?: string }) {
const type = event.type ?? this.currentType;
this._recordUiService.deleteRecord(type, event.pid).pipe(
switchMap(result => {
if (result === true) {
this.page = 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<!--
RERO angular core
Copyright (C) 2020 RERO
Copyright (C) 2019-2023 RERO
Copyright (C) 2019-2023 UCLouvain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
Expand All @@ -32,8 +33,8 @@
class="btn btn-sm btn-outline-primary ml-2"
[title]="'Edit' | translate"
[name]="'Edit' | translate"
(click)="editRecord(record.id)"
routerLink="edit/{{ record.id }}">
(click)="editRecord(record.id, updateStatus?.routerLink)"
[routerLink]="updateStatus.routerLink || ['edit', record.id]">
<i class="fa fa-pencil"></i>
</button>

Expand All @@ -44,7 +45,7 @@
class="btn btn-sm btn-outline-danger"
[title]="'Delete' | translate"
[name]="'Delete' | translate"
(click)="deleteRecord(record.id)">
(click)="deleteRecord(record.id, deleteStatus?.type)">
<i class="fa fa-trash"></i>
</button>
<ng-template #deleteMessageLink>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ describe('RecordSearchResultComponent', () => {
});

it('should delete record', () => {
component.deletedRecord.subscribe((pid: string) => {
expect(pid).toBe('1');
component.deletedRecord.subscribe((result: { pid: string, type: string | undefined | null }) => {
expect(result.pid).toBe('1');
});
component.deleteRecord('1');
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* RERO angular core
* Copyright (C) 2020 RERO
* Copyright (C) 2019-2023 RERO
* Copyright (C) 2019-2023 UCLouvain
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand Down Expand Up @@ -113,7 +114,7 @@ export class RecordSearchResultComponent implements OnInit {
/**
* Event emitted when a record is deleted
*/
@Output() deletedRecord = new EventEmitter<string>();
@Output() deletedRecord = new EventEmitter<{pid: string, type?: string | undefined | null }>();

/**
* Directive for displaying search results
Expand Down Expand Up @@ -190,17 +191,19 @@ export class RecordSearchResultComponent implements OnInit {
/**
* Delete a record
* @param pid - string, pid to delete
* @param type - string, resource type
*/
deleteRecord(pid: string) {
return this.deletedRecord.emit(pid);
deleteRecord(pid: string, type?: string) {
return this.deletedRecord.emit({ pid, type });
}

/**
* Edit a record
* @param pid - string: the pid to edit
*/
editRecord(pid: string) {
this._router.navigate(['/', 'records', this.type, 'edit', pid]);
editRecord(pid: string, url?: string[]) {
const params = url ?? ['/', 'records', this.type, 'edit', pid];
this._router.navigate(params);
}

/**
Expand Down

0 comments on commit 1431af5

Please sign in to comment.