From f1407b7f5b1d66febc8a9f0feb2e0c1b289a0638 Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Thu, 14 Jan 2021 16:20:04 +0100 Subject: [PATCH 1/4] 75832: Groups registry refactor --- .../group-form/group-form.component.ts | 8 +-- .../members-list/members-list.component.html | 42 ++++++++-------- .../members-list/members-list.component.ts | 50 +++++++++++++++---- .../subgroup-list/subgroups-list.component.ts | 2 +- .../groups-registry.component.html | 8 ++- .../groups-registry.component.ts | 21 +++----- src/app/core/eperson/eperson-data.service.ts | 6 +-- .../core/eperson/models/eperson-dto.model.ts | 4 ++ .../core/eperson/models/group-dto.model.ts | 15 +++++- src/app/core/eperson/models/group.model.ts | 10 +++- src/app/core/shared/dspace-object.model.ts | 2 +- src/assets/i18n/en.json5 | 2 - 12 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.ts b/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.ts index 81e9513433..7984fc50d1 100644 --- a/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.ts @@ -143,7 +143,9 @@ export class GroupFormComponent implements OnInit, OnDestroy { initialisePage() { this.subs.push(this.route.params.subscribe((params) => { - this.setActiveGroup(params.groupId); + if (params.groupId !== 'newGroup') { + this.setActiveGroup(params.groupId); + } })); this.canEdit$ = this.groupDataService.getActiveGroup().pipe( hasValueOperator(), @@ -225,14 +227,12 @@ export class GroupFormComponent implements OnInit, OnDestroy { { value: this.groupDescription.value } - ], + ] }, }; if (group === null) { - console.log('createNewGroup', values); this.createNewGroup(values); } else { - console.log('editGroup', group); this.editGroup(group); } } diff --git a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.html index 0ac67aff75..8e2d23f8d5 100644 --- a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.html +++ b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.html @@ -24,10 +24,10 @@ - @@ -42,23 +42,23 @@ - - {{ePerson.id}} - {{ePerson.name}} + + {{ePerson.eperson.id}} + {{ePerson.eperson.name}}
- -
@@ -70,7 +70,7 @@
- @@ -45,7 +45,6 @@ {{messagePrefix + 'table.id' | translate}} {{messagePrefix + 'table.name' | translate}} {{messagePrefix + 'table.members' | translate}} - {{messagePrefix + 'table.edit' | translate}} @@ -53,8 +52,7 @@ {{groupDto.group.id}} {{groupDto.group.name}} - {{(getMembers(groupDto.group) | async)?.payload?.totalElements + (getSubgroups(groupDto.group) | async)?.payload?.totalElements}} - + {{groupDto.epersons?.totalElements + groupDto.subgroups?.totalElements}}
diff --git a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts index db5b1d3e3b..7a8e670267 100644 --- a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts @@ -169,16 +169,16 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { /** * Delete Group */ - deleteGroup(group: Group) { - if (hasValue(group.id)) { - this.groupService.delete(group.id).pipe(getFirstCompletedRemoteData()) + deleteGroup(group: GroupDtoModel) { + if (hasValue(group.group.id)) { + this.groupService.delete(group.group.id).pipe(getFirstCompletedRemoteData()) .subscribe((rd: RemoteData) => { if (rd.hasSucceeded) { - this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: group.name })); + this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: group.group.name })); this.reset(); } else { this.notificationsService.error( - this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: group.name }), + this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: group.group.name }), this.translateService.get(this.messagePrefix + 'notification.deleted.failure.content', { cause: rd.errorMessage })); } }); @@ -194,7 +194,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { ).subscribe((href: string) => { this.requestService.setStaleByHrefSubstring(href); }); - } +} /** * Get the members (epersons embedded value of a group) @@ -233,15 +233,6 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { this.search({ query: '' }); } - /** - * Extract optional UUID from a group name => To be resolved to community or collection with link - * (Or will be resolved in backend and added to group object, tbd) //TODO - * @param groupName - */ - getOptionalComColFromName(groupName: string): string { - return this.groupService.getUUIDFromString(groupName); - } - /** * Unsub all subscriptions */ diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts index 9d1be80366..79df246833 100644 --- a/src/app/core/eperson/eperson-data.service.ts +++ b/src/app/core/eperson/eperson-data.service.ts @@ -63,10 +63,10 @@ export class EPersonDataService extends DataService { * @param query Query of search * @param options Options of search request */ - public searchByScope(scope: string, query: string, options: FindListOptions = {}): Observable>> { + public searchByScope(scope: string, query: string, options: FindListOptions = {}, useCachedVersionIfAvailable?: boolean): Observable>> { switch (scope) { case 'metadata': - return this.getEpeopleByMetadata(query.trim(), options); + return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable); case 'email': return this.getEPersonByEmail(query.trim()).pipe( map((rd: RemoteData) => { @@ -100,7 +100,7 @@ export class EPersonDataService extends DataService { }) ); default: - return this.getEpeopleByMetadata(query.trim(), options); + return this.getEpeopleByMetadata(query.trim(), options, useCachedVersionIfAvailable); } } diff --git a/src/app/core/eperson/models/eperson-dto.model.ts b/src/app/core/eperson/models/eperson-dto.model.ts index f491f6f8be..0e79902196 100644 --- a/src/app/core/eperson/models/eperson-dto.model.ts +++ b/src/app/core/eperson/models/eperson-dto.model.ts @@ -13,5 +13,9 @@ export class EpersonDtoModel { * Whether or not the linked EPerson is able to be deleted */ public ableToDelete: boolean; + /** + * Whether or not this EPerson is member of group on page it is being used on + */ + public memberOfGroup: boolean; } diff --git a/src/app/core/eperson/models/group-dto.model.ts b/src/app/core/eperson/models/group-dto.model.ts index db167dc6b2..47a70cf326 100644 --- a/src/app/core/eperson/models/group-dto.model.ts +++ b/src/app/core/eperson/models/group-dto.model.ts @@ -1,7 +1,9 @@ +import { PaginatedList } from '../../data/paginated-list.model'; +import { EPerson } from './eperson.model'; import { Group } from './group.model'; /** - * This class serves as a Data Transfer Model that contains the Group and whether or not it's able to be deleted + * This class serves as a Data Transfer Model that contains the Group, whether or not it's able to be deleted and its members */ export class GroupDtoModel { @@ -9,9 +11,20 @@ export class GroupDtoModel { * The Group linked to this object */ public group: Group; + /** * Whether or not the linked Group is able to be deleted */ public ableToDelete: boolean; + /** + * List of subgroups of this group + */ + public subgroups: PaginatedList; + + /** + * List of members of this group + */ + public epersons: PaginatedList; + } diff --git a/src/app/core/eperson/models/group.model.ts b/src/app/core/eperson/models/group.model.ts index 9e13627116..f147cc53a6 100644 --- a/src/app/core/eperson/models/group.model.ts +++ b/src/app/core/eperson/models/group.model.ts @@ -1,4 +1,4 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; +import { autoserialize, autoserializeAs, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; import { link, typedObject } from '../../cache/builders/build-decorators'; import { PaginatedList } from '../../data/paginated-list.model'; @@ -10,12 +10,20 @@ import { HALLink } from '../../shared/hal-link.model'; import { EPerson } from './eperson.model'; import { EPERSON } from './eperson.resource-type'; import { GROUP } from './group.resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; @typedObject @inheritSerialization(DSpaceObject) export class Group extends DSpaceObject { static type = GROUP; + /** + * A string representing the unique name of this Group + */ + @excludeFromEquals + @autoserializeAs('name') + protected _name: string; + /** * A string representing the unique handle of this Group */ diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index b88adfe861..9d1fba4f86 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -29,7 +29,7 @@ export class DSpaceObject extends ListableObject implements CacheableObject { @excludeFromEquals @deserializeAs('name') - private _name: string; + protected _name: string; /** * The human-readable identifier of this DSpaceObject diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 603acb3f48..5ddde2a307 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -308,8 +308,6 @@ "admin.access-control.groups.table.members": "Members", - "admin.access-control.groups.table.comcol": "Community / Collection", - "admin.access-control.groups.table.edit": "Edit", "admin.access-control.groups.table.edit.buttons.edit": "Edit \"{{name}}\"", From dde149aceacdd2b658c4632f72098a5b0b7120cd Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Thu, 4 Feb 2021 12:11:18 +0100 Subject: [PATCH 2/4] 75832: [Issue 962]: Fix unnecessary calls creating/deleting groups - feedback --- .../members-list/members-list.component.ts | 163 ++++++++++-------- src/assets/i18n/en.json5 | 2 + 2 files changed, 96 insertions(+), 69 deletions(-) diff --git a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts index 7a09f6ac8b..d01d117a86 100644 --- a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts @@ -2,8 +2,14 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { Observable, of as observableOf, Subscription, BehaviorSubject, ObservedValueOf, combineLatest as observableCombineLatest} from 'rxjs'; -import { map, mergeMap, take } from 'rxjs/operators'; +import { + Observable, + of as observableOf, + Subscription, + BehaviorSubject, + combineLatest as observableCombineLatest, ObservedValueOf, +} from 'rxjs'; +import { map, mergeMap, switchMap, take } from 'rxjs/operators'; import {buildPaginatedList, PaginatedList} from '../../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../../core/data/remote-data'; import { EPersonDataService } from '../../../../../core/eperson/eperson-data.service'; @@ -13,7 +19,7 @@ import { Group } from '../../../../../core/eperson/models/group.model'; import { getRemoteDataPayload, getFirstSucceededRemoteData, - getFirstCompletedRemoteData + getFirstCompletedRemoteData, getAllCompletedRemoteData } from '../../../../../core/shared/operators'; import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../../../shared/pagination/pagination-component-options.model'; @@ -23,9 +29,7 @@ import {EpersonDtoModel} from '../../../../../core/eperson/models/eperson-dto.mo * Keys to keep track of specific subscriptions */ enum SubKey { - Members, ActiveGroup, - SearchResults, MembersDTO, SearchResultsDTO, } @@ -45,12 +49,10 @@ export class MembersListComponent implements OnInit, OnDestroy { /** * EPeople being displayed in search result, initially all members, after search result of search */ - searchResults$: BehaviorSubject>> = new BehaviorSubject(undefined); ePeopleSearchDtos: BehaviorSubject> = new BehaviorSubject>(undefined); /** * List of EPeople members of currently active group being edited */ - members$: BehaviorSubject>> = new BehaviorSubject(undefined); ePeopleMembersOfGroupDtos: BehaviorSubject> = new BehaviorSubject>(undefined); /** @@ -135,17 +137,58 @@ export class MembersListComponent implements OnInit, OnDestroy { * @private */ private retrieveMembers(page: number) { - this.unsubFrom(SubKey.Members); - this.subs.set( - SubKey.Members, - this.ePersonDataService.findAllByHref(this.groupBeingEdited._links.epersons.href, { - currentPage: page, - elementsPerPage: this.config.pageSize - } - ).subscribe((rd: RemoteData>) => { - this.members$.next(rd); - if (rd.payload !== undefined) { - this.setEpersonDTOsFromResult(rd, this.ePeopleMembersOfGroupDtos, SubKey.MembersDTO); + this.unsubFrom(SubKey.MembersDTO); + this.subs.set(SubKey.MembersDTO, this.ePersonDataService.findAllByHref(this.groupBeingEdited._links.epersons.href, { + currentPage: page, + elementsPerPage: this.config.pageSize + }).pipe( + getAllCompletedRemoteData(), + map((rd: RemoteData) => { + if (rd.hasFailed) { + this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure', {cause: rd.errorMessage})); + } else { + return rd; + } + }), + switchMap((epersonListRD: RemoteData>) => { + const dtos$ = observableCombineLatest(...epersonListRD.payload.page.map((member: EPerson) => { + const dto$: Observable = observableCombineLatest( + this.isMemberOfGroup(member), (isMember: ObservedValueOf>) => { + const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); + epersonDtoModel.eperson = member; + epersonDtoModel.memberOfGroup = isMember; + return epersonDtoModel; + }); + return dto$; + })); + return dtos$.pipe(map((dtos: EpersonDtoModel[]) => { + return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); + })) + })) + .subscribe((paginatedListOfDTOs: PaginatedList) => { + this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); + })); + } + + /** + * Whether or not the given ePerson is a member of the group currently being edited + * @param possibleMember EPerson that is a possible member (being tested) of the group currently being edited + */ + isMemberOfGroup(possibleMember: EPerson): Observable { + return this.groupDataService.getActiveGroup().pipe(take(1), + mergeMap((group: Group) => { + if (group != null) { + return this.ePersonDataService.findAllByHref(group._links.epersons.href, { + currentPage: 1, + elementsPerPage: 9999 + }, false) + .pipe( + getFirstSucceededRemoteData(), + getRemoteDataPayload(), + map((listEPeopleInGroup: PaginatedList) => listEPeopleInGroup.page.filter((ePersonInList: EPerson) => ePersonInList.id === possibleMember.id)), + map((epeople: EPerson[]) => epeople.length > 0)); + } else { + return observableOf(false); } })); } @@ -173,6 +216,7 @@ export class MembersListComponent implements OnInit, OnDestroy { if (activeGroup != null) { const response = this.groupDataService.deleteMemberFromGroup(activeGroup, ePerson.eperson); this.showNotifications('deleteMember', response, ePerson.eperson.name, activeGroup); + this.search({ scope: this.currentSearchScope, query: this.currentSearchQuery }); } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup')); } @@ -195,29 +239,6 @@ export class MembersListComponent implements OnInit, OnDestroy { }); } - /** - * Whether or not the given ePerson is a member of the group currently being edited - * @param possibleMember EPerson that is a possible member (being tested) of the group currently being edited - */ - isMemberOfGroup(possibleMember: EPerson): Observable { - return this.groupDataService.getActiveGroup().pipe(take(1), - mergeMap((group: Group) => { - if (group != null) { - return this.ePersonDataService.findAllByHref(group._links.epersons.href, { - currentPage: 1, - elementsPerPage: 9999 - }) - .pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - map((listEPeopleInGroup: PaginatedList) => listEPeopleInGroup.page.filter((ePersonInList: EPerson) => ePersonInList.id === possibleMember.id)), - map((epeople: EPerson[]) => epeople.length > 0)); - } else { - return observableOf(false); - } - })); - } - /** * Search in the EPeople by name, email or metadata * @param data Contains scope and query param @@ -237,34 +258,38 @@ export class MembersListComponent implements OnInit, OnDestroy { } this.searchDone = true; - this.unsubFrom(SubKey.SearchResults); - this.subs.set(SubKey.SearchResults, this.ePersonDataService.searchByScope(this.currentSearchScope, this.currentSearchQuery, { - currentPage: this.configSearch.currentPage, - elementsPerPage: this.configSearch.pageSize - }).subscribe((rd: RemoteData>) => { - this.searchResults$.next(rd); - if (rd.payload !== undefined) { - this.setEpersonDTOsFromResult(rd, this.ePeopleSearchDtos, SubKey.SearchResultsDTO); - } - })); - } - - private setEpersonDTOsFromResult(rd: RemoteData>, addTo: BehaviorSubject>, subkey) { - this.unsubFrom(subkey); - const dtos$ = observableCombineLatest(...rd.payload.page.map((member: EPerson) => { - const dto$: Observable = observableCombineLatest( - this.isMemberOfGroup(member), (isMember: ObservedValueOf>) => { - const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); - epersonDtoModel.eperson = member; - epersonDtoModel.memberOfGroup = isMember; - return epersonDtoModel; - }); - return dto$; - })); - this.subs.set(subkey,dtos$.pipe(map((dtos: EpersonDtoModel[]) => { - const paginatedListOfDTOs = buildPaginatedList(rd.payload.pageInfo, dtos); - addTo.next(paginatedListOfDTOs); - })).subscribe()); + this.unsubFrom(SubKey.SearchResultsDTO); + this.subs.set(SubKey.SearchResultsDTO, + this.ePersonDataService.searchByScope(this.currentSearchScope, this.currentSearchQuery, { + currentPage: this.configSearch.currentPage, + elementsPerPage: this.configSearch.pageSize + }, false).pipe( + getAllCompletedRemoteData(), + map((rd: RemoteData) => { + if (rd.hasFailed) { + this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure', {cause: rd.errorMessage})); + } else { + return rd; + } + }), + switchMap((epersonListRD: RemoteData>) => { + const dtos$ = observableCombineLatest(...epersonListRD.payload.page.map((member: EPerson) => { + const dto$: Observable = observableCombineLatest( + this.isMemberOfGroup(member), (isMember: ObservedValueOf>) => { + const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); + epersonDtoModel.eperson = member; + epersonDtoModel.memberOfGroup = isMember; + return epersonDtoModel; + }); + return dto$; + })); + return dtos$.pipe(map((dtos: EpersonDtoModel[]) => { + return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); + })) + })) + .subscribe((paginatedListOfDTOs: PaginatedList) => { + this.ePeopleSearchDtos.next(paginatedListOfDTOs); + })); } /** diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 5ddde2a307..cb1453beed 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -402,6 +402,8 @@ "admin.access-control.groups.form.members-list.no-items": "No EPeople found in that search", + "admin.access-control.groups.form.subgroups-list.notification.failure": "Something went wrong: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head": "Groups", "admin.access-control.groups.form.subgroups-list.search.head": "Add Subgroup", From 569f35437068b5bf9d93db93e4b4ced00a4df3d3 Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Mon, 8 Feb 2021 15:00:44 +0100 Subject: [PATCH 3/4] 75832: [Issue 962]: Members total in Group registry fixed with GroupDTO --- .../group-form/members-list/members-list.component.ts | 4 ++-- .../group-registry/groups-registry.component.ts | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts index d01d117a86..f1d25725d6 100644 --- a/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/group-form/members-list/members-list.component.ts @@ -163,7 +163,7 @@ export class MembersListComponent implements OnInit, OnDestroy { })); return dtos$.pipe(map((dtos: EpersonDtoModel[]) => { return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); - })) + })); })) .subscribe((paginatedListOfDTOs: PaginatedList) => { this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); @@ -285,7 +285,7 @@ export class MembersListComponent implements OnInit, OnDestroy { })); return dtos$.pipe(map((dtos: EpersonDtoModel[]) => { return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); - })) + })); })) .subscribe((paginatedListOfDTOs: PaginatedList) => { this.ePeopleSearchDtos.next(paginatedListOfDTOs); diff --git a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts index 7a8e670267..06fe2d56be 100644 --- a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts @@ -111,12 +111,17 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { return observableCombineLatest(groups.page.map((group: Group) => { return observableCombineLatest([ this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(group) ? group.self : undefined), - this.hasLinkedDSO(group) + this.hasLinkedDSO(group), + this.getSubgroups(group), + this.getMembers(group) ]).pipe( - map(([isAuthorized, hasLinkedDSO]: boolean[]) => { + map(([isAuthorized, hasLinkedDSO, subgroups, members]: + [boolean, boolean, RemoteData>, RemoteData>]) => { const groupDtoModel: GroupDtoModel = new GroupDtoModel(); groupDtoModel.ableToDelete = isAuthorized && !hasLinkedDSO; groupDtoModel.group = group; + groupDtoModel.subgroups = subgroups.payload; + groupDtoModel.epersons = members.payload; return groupDtoModel; } ) From dd241c86b2e1d4b21c57a8127efcbdcfc11964f5 Mon Sep 17 00:00:00 2001 From: Marie Verdonck Date: Thu, 11 Feb 2021 12:36:32 +0100 Subject: [PATCH 4/4] 75832: [Issue 962]: Fix no change in search result if no results & fix 404 messages at delete in registry --- .../groups-registry.component.ts | 80 +++++++++---------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts index 06fe2d56be..305da75eeb 100644 --- a/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts +++ b/src/app/+admin/admin-access-control/group-registry/groups-registry.component.ts @@ -26,7 +26,7 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, - getAllSucceededRemoteData + getFirstSucceededRemoteData } from '../../../core/shared/operators'; import { PageInfo } from '../../../core/shared/page-info.model'; import { hasValue } from '../../../shared/empty.util'; @@ -55,15 +55,12 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { currentPage: 1 }); - /** - * A list of all the current Groups within the repository or the result of the search - */ - groups$: BehaviorSubject>> = new BehaviorSubject>>({} as any); /** * A BehaviorSubject with the list of GroupDtoModel objects made from the Groups in the repository or * as the result of the search */ groupsDto$: BehaviorSubject> = new BehaviorSubject>({} as any); + deletedGroupsIds: string[] = []; /** * An observable for the pageInfo, needed to pass to the pagination component @@ -104,35 +101,6 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { ngOnInit() { this.search({ query: this.currentSearchQuery }); - - this.subs.push(this.groups$.pipe( - getAllSucceededRemoteDataPayload(), - switchMap((groups: PaginatedList) => { - return observableCombineLatest(groups.page.map((group: Group) => { - return observableCombineLatest([ - this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(group) ? group.self : undefined), - this.hasLinkedDSO(group), - this.getSubgroups(group), - this.getMembers(group) - ]).pipe( - map(([isAuthorized, hasLinkedDSO, subgroups, members]: - [boolean, boolean, RemoteData>, RemoteData>]) => { - const groupDtoModel: GroupDtoModel = new GroupDtoModel(); - groupDtoModel.ableToDelete = isAuthorized && !hasLinkedDSO; - groupDtoModel.group = group; - groupDtoModel.subgroups = subgroups.payload; - groupDtoModel.epersons = members.payload; - return groupDtoModel; - } - ) - ); - })).pipe(map((dtos: GroupDtoModel[]) => { - return buildPaginatedList(groups.pageInfo, dtos); - })); - })).subscribe((value: PaginatedList) => { - this.groupsDto$.next(value); - this.pageInfoState$.next(value.pageInfo); - })); } /** @@ -159,14 +127,42 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { this.searchSub.unsubscribe(); this.subs = this.subs.filter((sub: Subscription) => sub !== this.searchSub); } + this.searchSub = this.groupService.searchGroups(this.currentSearchQuery.trim(), { currentPage: this.config.currentPage, elementsPerPage: this.config.pageSize }).pipe( - getAllSucceededRemoteData() - ).subscribe((groupsRD: RemoteData>) => { - this.groups$.next(groupsRD); - this.pageInfoState$.next(groupsRD.payload.pageInfo); + getAllSucceededRemoteDataPayload(), + switchMap((groups: PaginatedList) => { + if (groups.page.length === 0) { + return observableOf(buildPaginatedList(groups.pageInfo, [])); + } + return observableCombineLatest(groups.page.map((group: Group) => { + if (!this.deletedGroupsIds.includes(group.id)) { + return observableCombineLatest([ + this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(group) ? group.self : undefined), + this.hasLinkedDSO(group), + this.getSubgroups(group), + this.getMembers(group) + ]).pipe( + map(([isAuthorized, hasLinkedDSO, subgroups, members]: + [boolean, boolean, RemoteData>, RemoteData>]) => { + const groupDtoModel: GroupDtoModel = new GroupDtoModel(); + groupDtoModel.ableToDelete = isAuthorized && !hasLinkedDSO; + groupDtoModel.group = group; + groupDtoModel.subgroups = subgroups.payload; + groupDtoModel.epersons = members.payload; + return groupDtoModel; + } + ) + ); + } + })).pipe(map((dtos: GroupDtoModel[]) => { + return buildPaginatedList(groups.pageInfo, dtos); + })); + })).subscribe((value: PaginatedList) => { + this.groupsDto$.next(value); + this.pageInfoState$.next(value.pageInfo); }); this.subs.push(this.searchSub); } @@ -179,6 +175,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { this.groupService.delete(group.group.id).pipe(getFirstCompletedRemoteData()) .subscribe((rd: RemoteData) => { if (rd.hasSucceeded) { + this.deletedGroupsIds = [...this.deletedGroupsIds, group.group.id]; this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: group.group.name })); this.reset(); } else { @@ -199,14 +196,14 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { ).subscribe((href: string) => { this.requestService.setStaleByHrefSubstring(href); }); -} + } /** * Get the members (epersons embedded value of a group) * @param group */ getMembers(group: Group): Observable>> { - return this.ePersonDataService.findAllByHref(group._links.epersons.href); + return this.ePersonDataService.findAllByHref(group._links.epersons.href).pipe(getFirstSucceededRemoteData()); } /** @@ -214,7 +211,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { * @param group */ getSubgroups(group: Group): Observable>> { - return this.groupService.findAllByHref(group._links.subgroups.href); + return this.groupService.findAllByHref(group._links.subgroups.href).pipe(getFirstSucceededRemoteData()); } /** @@ -223,6 +220,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { */ hasLinkedDSO(group: Group): Observable { return this.dSpaceObjectDataService.findByHref(group._links.object.href).pipe( + getFirstSucceededRemoteData(), map((rd: RemoteData) => hasValue(rd) && hasValue(rd.payload)), catchError(() => observableOf(false)), );