Skip to content

Commit 2d957bf

Browse files
115215: Fixed advanced workflow options (select reviewer & rating) throwing 404 error
1 parent 659052f commit 2d957bf

10 files changed

Lines changed: 138 additions & 70 deletions

File tree

src/app/access-control/group-registry/group-form/members-list/members-list.component.html

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,33 @@ <h3>{{messagePrefix + '.headMembers' | translate}}</h3>
2020
</tr>
2121
</thead>
2222
<tbody>
23-
<tr *ngFor="let eperson of (ePeopleMembersOfGroup | async)?.page">
24-
<td class="align-middle">{{eperson.id}}</td>
23+
<tr *ngFor="let epersonDTO of (ePeopleMembersOfGroup | async)?.page">
24+
<td class="align-middle">{{epersonDTO.eperson.id}}</td>
2525
<td class="align-middle">
26-
<a [routerLink]="getEPersonEditRoute(eperson.id)">
27-
{{ dsoNameService.getName(eperson) }}
26+
<a [routerLink]="getEPersonEditRoute(epersonDTO.eperson.id)">
27+
{{ dsoNameService.getName(epersonDTO.eperson) }}
2828
</a>
2929
</td>
3030
<td class="align-middle">
31-
{{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}<br/>
32-
{{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }}
31+
{{messagePrefix + '.table.email' | translate}}: {{ epersonDTO.eperson.email ? epersonDTO.eperson.email : '-' }}<br/>
32+
{{messagePrefix + '.table.netid' | translate}}: {{ epersonDTO.eperson.netid ? epersonDTO.eperson.netid : '-' }}
3333
</td>
3434
<td class="align-middle">
3535
<div class="btn-group edit-field">
36-
<button (click)="deleteMemberFromGroup(eperson)"
36+
<button (click)="deleteMemberFromGroup(epersonDTO.eperson)"
37+
*ngIf="epersonDTO.ableToDelete"
3738
[disabled]="actionConfig.remove.disabled"
3839
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
39-
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(eperson) } }}">
40+
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(epersonDTO.eperson) } }}">
4041
<i [ngClass]="actionConfig.remove.icon"></i>
4142
</button>
43+
<button *ngIf="!epersonDTO.ableToDelete"
44+
(click)="addMemberToGroup(epersonDTO.eperson)"
45+
[disabled]="actionConfig.add.disabled"
46+
[ngClass]="['btn btn-sm', actionConfig.add.css]"
47+
title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(epersonDTO.eperson) } }}">
48+
<i [ngClass]="actionConfig.add.icon"></i>
49+
</button>
4250
</div>
4351
</td>
4452
</tr>

src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,13 @@ describe('MembersListComponent', () => {
222222

223223
describe('if first delete button is pressed', () => {
224224
beforeEach(() => {
225+
spyOn(component, 'search').and.callThrough();
225226
const deleteButton: DebugElement = fixture.debugElement.query(By.css('#ePeopleMembersOfGroup tbody .fa-trash-alt'));
226227
deleteButton.nativeElement.click();
227228
fixture.detectChanges();
228229
});
229-
it('then no ePerson remains as a member of the active group.', () => {
230-
const epersonsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tbody tr'));
231-
expect(epersonsFound.length).toEqual(0);
230+
it('should trigger the search to add the user back to the search table', () => {
231+
expect(component.search).toHaveBeenCalled();
232232
});
233233
});
234234
});
@@ -264,13 +264,13 @@ describe('MembersListComponent', () => {
264264

265265
describe('if first add button is pressed', () => {
266266
beforeEach(() => {
267+
spyOn(component, 'search').and.callThrough();
267268
const addButton: DebugElement = fixture.debugElement.query(By.css('#epersonsSearch tbody .fa-plus'));
268269
addButton.nativeElement.click();
269270
fixture.detectChanges();
270271
});
271-
it('then all (two) ePersons are member of the active group. No non-members left', () => {
272-
epersonsFound = fixture.debugElement.queryAll(By.css('#epersonsSearch tbody tr'));
273-
expect(epersonsFound.length).toEqual(0);
272+
it('should trigger the search to remove the user from the search table', () => {
273+
expect(component.search).toHaveBeenCalled();
274274
});
275275
});
276276
});

src/app/access-control/group-registry/group-form/members-list/members-list.component.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,29 @@ import {
2424
} from '@ngx-translate/core';
2525
import {
2626
BehaviorSubject,
27+
combineLatest as observableCombineLatest,
2728
Observable,
29+
ObservedValueOf,
30+
of as observableOf,
2831
Subscription,
2932
} from 'rxjs';
3033
import {
34+
defaultIfEmpty,
3135
map,
3236
switchMap,
3337
take,
3438
} from 'rxjs/operators';
3539

3640
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
37-
import { PaginatedList } from '../../../../core/data/paginated-list.model';
41+
import {
42+
buildPaginatedList,
43+
PaginatedList,
44+
} from '../../../../core/data/paginated-list.model';
3845
import { RemoteData } from '../../../../core/data/remote-data';
3946
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
4047
import { GroupDataService } from '../../../../core/eperson/group-data.service';
4148
import { EPerson } from '../../../../core/eperson/models/eperson.model';
49+
import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model';
4250
import { Group } from '../../../../core/eperson/models/group.model';
4351
import { PaginationService } from '../../../../core/pagination/pagination.service';
4452
import {
@@ -137,7 +145,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
137145
/**
138146
* List of EPeople members of currently active group being edited
139147
*/
140-
ePeopleMembersOfGroup: BehaviorSubject<PaginatedList<EPerson>> = new BehaviorSubject<PaginatedList<EPerson>>(undefined);
148+
ePeopleMembersOfGroup: BehaviorSubject<PaginatedList<EpersonDtoModel>> = new BehaviorSubject(undefined);
141149

142150
/**
143151
* Pagination config used to display the list of EPeople that are result of EPeople search
@@ -226,10 +234,35 @@ export class MembersListComponent implements OnInit, OnDestroy {
226234
return rd;
227235
}
228236
}),
229-
getRemoteDataPayload())
230-
.subscribe((paginatedListOfEPersons: PaginatedList<EPerson>) => {
231-
this.ePeopleMembersOfGroup.next(paginatedListOfEPersons);
232-
}));
237+
switchMap((epersonListRD: RemoteData<PaginatedList<EPerson>>) => {
238+
const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => {
239+
const dto$: Observable<EpersonDtoModel> = observableCombineLatest(
240+
this.isMemberOfGroup(member), (isMember: ObservedValueOf<Observable<boolean>>) => {
241+
const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
242+
epersonDtoModel.eperson = member;
243+
epersonDtoModel.ableToDelete = isMember;
244+
return epersonDtoModel;
245+
});
246+
return dto$;
247+
})]);
248+
return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => {
249+
return buildPaginatedList(epersonListRD.payload.pageInfo, dtos);
250+
}));
251+
}),
252+
).subscribe((paginatedListOfDTOs: PaginatedList<EpersonDtoModel>) => {
253+
this.ePeopleMembersOfGroup.next(paginatedListOfDTOs);
254+
}),
255+
);
256+
}
257+
258+
/**
259+
* We always return true since this is only used by the top section (which represents all the users part of the group
260+
* in {@link MembersListComponent})
261+
*
262+
* @param possibleMember EPerson that is a possible member (being tested) of the group currently being edited
263+
*/
264+
isMemberOfGroup(possibleMember: EPerson): Observable<boolean> {
265+
return observableOf(true);
233266
}
234267

235268
/**

src/app/core/eperson/eperson-data.service.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,17 @@ export class EPersonDataService extends IdentifiableDataService<EPerson> impleme
107107
* @param scope Scope of the EPeople search, default byMetadata
108108
* @param query Query of search
109109
* @param options Options of search request
110+
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
111+
* no valid cached version. Defaults to true
112+
* @param reRequestOnStale Whether or not the request should automatically be re-
113+
* requested after the response becomes stale
110114
*/
111-
public searchByScope(scope: string, query: string, options: FindListOptions = {}, useCachedVersionIfAvailable?: boolean): Observable<RemoteData<PaginatedList<EPerson>>> {
115+
public searchByScope(scope: string, query: string, options: FindListOptions = {}, useCachedVersionIfAvailable?: boolean, reRequestOnStale = true): Observable<RemoteData<PaginatedList<EPerson>>> {
112116
switch (scope) {
113117
case 'metadata':
114-
return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable);
118+
return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable, reRequestOnStale);
115119
case 'email':
116-
return this.getEPersonByEmail(query.trim()).pipe(
120+
return this.getEPersonByEmail(query.trim(), useCachedVersionIfAvailable, reRequestOnStale).pipe(
117121
map((rd: RemoteData<EPerson | NoContent>) => {
118122
if (rd.hasSucceeded) {
119123
// Turn the single EPerson or NoContent in to a PaginatedList<EPerson>
@@ -145,7 +149,7 @@ export class EPersonDataService extends IdentifiableDataService<EPerson> impleme
145149
}),
146150
);
147151
default:
148-
return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable);
152+
return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable, reRequestOnStale);
149153
}
150154
}
151155

src/app/item-page/edit-item-page/modify-item-overview/modify-item-overview.component.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('ModifyItemOverviewComponent', () => {
3737
fixture = TestBed.createComponent(ModifyItemOverviewComponent);
3838
comp = fixture.componentInstance;
3939
comp.item = mockItem;
40+
comp.ngOnChanges();
4041

4142
fixture.detectChanges();
4243
});

src/app/item-page/edit-item-page/modify-item-overview/modify-item-overview.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
import {
66
Component,
77
Input,
8-
OnInit,
8+
OnChanges,
99
} from '@angular/core';
1010
import { TranslateModule } from '@ngx-translate/core';
1111

@@ -21,12 +21,12 @@ import { MetadataMap } from '../../../core/shared/metadata.models';
2121
/**
2222
* Component responsible for rendering a table containing the metadatavalues from the to be edited item
2323
*/
24-
export class ModifyItemOverviewComponent implements OnInit {
24+
export class ModifyItemOverviewComponent implements OnChanges {
2525

2626
@Input() item: Item;
2727
metadata: MetadataMap;
2828

29-
ngOnInit(): void {
30-
this.metadata = this.item.metadata;
29+
ngOnChanges(): void {
30+
this.metadata = this.item?.metadata;
3131
}
3232
}

src/app/shared/mydspace-actions/claimed-task/abstract/claimed-task-actions-abstract.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Component,
33
Injector,
4+
Input,
45
OnDestroy,
56
} from '@angular/core';
67
import { Router } from '@angular/router';
@@ -44,7 +45,7 @@ export abstract class ClaimedTaskActionsAbstractComponent extends MyDSpaceReload
4445
/**
4546
* The item object that belonging to the ClaimedTask object
4647
*/
47-
item: Item;
48+
@Input() item: Item;
4849

4950
/**
5051
* Anchor used to reload the pool task.
@@ -56,7 +57,7 @@ export abstract class ClaimedTaskActionsAbstractComponent extends MyDSpaceReload
5657
/**
5758
* The workflowitem object that belonging to the ClaimedTask object
5859
*/
59-
workflowitem: WorkflowItem;
60+
@Input() workflowitem: WorkflowItem;
6061

6162
protected constructor(protected injector: Injector,
6263
protected router: Router,

src/app/shared/mydspace-actions/claimed-task/switcher/claimed-task-actions-decorator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import {
2+
ADVANCED_WORKFLOW_ACTION_RATING,
23
ADVANCED_WORKFLOW_TASK_OPTION_RATING,
34
AdvancedWorkflowActionRatingComponent,
45
} from '../../../../workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-rating/advanced-workflow-action-rating.component';
56
import {
7+
ADVANCED_WORKFLOW_ACTION_SELECT_REVIEWER,
68
ADVANCED_WORKFLOW_TASK_OPTION_SELECT_REVIEWER,
79
AdvancedWorkflowActionSelectReviewerComponent,
810
} from '../../../../workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/advanced-workflow-action-select-reviewer.component';
@@ -54,8 +56,8 @@ export const WORKFLOW_TASK_OPTION_DECORATOR_MAP = new Map<string, WorkflowTaskOp
5456
]);
5557

5658
export const ADVANCED_WORKFLOW_TASK_OPTION_DECORATOR_MAP = new Map<string, AdvancedWorkflowTaskOptionComponent>([
57-
[ADVANCED_WORKFLOW_TASK_OPTION_RATING, AdvancedWorkflowActionRatingComponent],
58-
[ADVANCED_WORKFLOW_TASK_OPTION_SELECT_REVIEWER, AdvancedWorkflowActionSelectReviewerComponent],
59+
[ADVANCED_WORKFLOW_ACTION_RATING, AdvancedWorkflowActionRatingComponent],
60+
[ADVANCED_WORKFLOW_ACTION_SELECT_REVIEWER, AdvancedWorkflowActionSelectReviewerComponent],
5961
]);
6062

6163
/**

src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.spec.ts

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,38 @@ describe('ReviewersListComponent', () => {
224224
})).not.toBeTruthy();
225225
});
226226
});
227+
228+
it('should replace the value when a new member is added when multipleReviewers is false', () => {
229+
spyOn(component.selectedReviewersUpdated, 'emit');
230+
component.multipleReviewers = false;
231+
component.selectedReviewers = [EPersonMock];
232+
233+
component.addMemberToGroup(EPersonMock2);
234+
235+
expect(component.selectedReviewers).toEqual([EPersonMock2]);
236+
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock2]);
237+
});
238+
239+
it('should add the value when a new member is added when multipleReviewers is true', () => {
240+
spyOn(component.selectedReviewersUpdated, 'emit');
241+
component.multipleReviewers = true;
242+
component.selectedReviewers = [EPersonMock];
243+
244+
component.addMemberToGroup(EPersonMock2);
245+
246+
expect(component.selectedReviewers).toEqual([EPersonMock, EPersonMock2]);
247+
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock, EPersonMock2]);
248+
});
249+
250+
it('should delete the member when present', () => {
251+
spyOn(component.selectedReviewersUpdated, 'emit');
252+
component.selectedReviewers = [EPersonMock];
253+
254+
component.deleteMemberFromGroup(EPersonMock);
255+
256+
expect(component.selectedReviewers).toEqual([]);
257+
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([]);
258+
});
227259
});
228260

229261
describe('when a group is selected', () => {
@@ -245,37 +277,4 @@ describe('ReviewersListComponent', () => {
245277
});
246278
});
247279

248-
249-
it('should replace the value when a new member is added when multipleReviewers is false', () => {
250-
spyOn(component.selectedReviewersUpdated, 'emit');
251-
component.multipleReviewers = false;
252-
component.selectedReviewers = [EPersonMock];
253-
254-
component.addMemberToGroup(EPersonMock2);
255-
256-
expect(component.selectedReviewers).toEqual([EPersonMock2]);
257-
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock2]);
258-
});
259-
260-
it('should add the value when a new member is added when multipleReviewers is true', () => {
261-
spyOn(component.selectedReviewersUpdated, 'emit');
262-
component.multipleReviewers = true;
263-
component.selectedReviewers = [EPersonMock];
264-
265-
component.addMemberToGroup(EPersonMock2);
266-
267-
expect(component.selectedReviewers).toEqual([EPersonMock, EPersonMock2]);
268-
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock, EPersonMock2]);
269-
});
270-
271-
it('should delete the member when present', () => {
272-
spyOn(component.selectedReviewersUpdated, 'emit');
273-
component.selectedReviewers = [EPersonMock];
274-
275-
component.deleteMemberFromGroup(EPersonMock);
276-
277-
expect(component.selectedReviewers).toEqual([]);
278-
expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([]);
279-
});
280-
281280
});

0 commit comments

Comments
 (0)