From 964371066a299ea25193d54f7bc878e681f59d9c Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 11 Oct 2022 15:05:06 +0200 Subject: [PATCH] 95632: Refactor orcid/claim person buttons to dso-menu-resolver --- .../researcher-profile-data.service.ts | 22 ++- .../dso-page/dso-edit-menu.resolver.spec.ts | 49 ++++- .../shared/dso-page/dso-edit-menu.resolver.ts | 69 ++++++- .../dso-page-orcid-button.component.html | 6 - .../dso-page-orcid-button.component.scss | 0 .../dso-page-orcid-button.component.spec.ts | 76 ------- .../dso-page-orcid-button.component.ts | 39 ---- .../person-page-claim-button.component.html | 7 - .../person-page-claim-button.component.scss | 0 ...person-page-claim-button.component.spec.ts | 186 ------------------ .../person-page-claim-button.component.ts | 84 -------- src/app/shared/menu/menu.service.ts | 22 ++- src/app/shared/shared.module.ts | 4 - 13 files changed, 142 insertions(+), 422 deletions(-) delete mode 100644 src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.html delete mode 100644 src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.scss delete mode 100644 src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.spec.ts delete mode 100644 src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.ts delete mode 100644 src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.html delete mode 100644 src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.scss delete mode 100644 src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.spec.ts delete mode 100644 src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.ts diff --git a/src/app/core/profile/researcher-profile-data.service.ts b/src/app/core/profile/researcher-profile-data.service.ts index 8c62879c37..c43bf696f8 100644 --- a/src/app/core/profile/researcher-profile-data.service.ts +++ b/src/app/core/profile/researcher-profile-data.service.ts @@ -3,8 +3,8 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Operation, ReplaceOperation } from 'fast-json-patch'; -import { Observable } from 'rxjs'; -import { find, map } from 'rxjs/operators'; +import { Observable, of as observableOf } from 'rxjs'; +import { find, map, mergeMap } from 'rxjs/operators'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../cache/object-cache.service'; @@ -130,6 +130,24 @@ export class ResearcherProfileDataService extends IdentifiableDataService { + return this.createFromExternalSource(sourceUri).pipe( + getFirstCompletedRemoteData(), + mergeMap((rd: RemoteData) => { + if (rd.hasSucceeded) { + return this.findRelatedItemId(rd.payload); + } else { + return observableOf(null); + } + }), + ); + } + /** * Create a new object on the server, and store the response in the object cache diff --git a/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts b/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts index 82085ff86a..abfe618174 100644 --- a/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts +++ b/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts @@ -1,7 +1,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { MenuServiceStub } from '../testing/menu-service.stub'; import { of as observableOf } from 'rxjs'; -import { TranslateModule } from '@ngx-translate/core'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; import { AdminSidebarComponent } from '../../admin/admin-sidebar/admin-sidebar.component'; @@ -18,6 +18,8 @@ import { MenuID } from '../menu/menu-id.model'; import { MenuItemType } from '../menu/menu-item-type.model'; import { TextMenuItemModel } from '../menu/menu-item/models/text.model'; import { LinkMenuItemModel } from '../menu/menu-item/models/link.model'; +import { ResearcherProfileDataService } from '../../core/profile/researcher-profile-data.service'; +import { NotificationsService } from '../notifications/notifications.service'; describe('DSOEditMenuResolver', () => { @@ -31,6 +33,9 @@ describe('DSOEditMenuResolver', () => { let menuService; let authorizationService; let dsoVersioningModalService; + let researcherProfileService; + let notificationsService; + let translate; const route = { data: { @@ -99,6 +104,16 @@ describe('DSOEditMenuResolver', () => { getVersioningTooltipMessage: observableOf('message'), openCreateVersionModal: {} }); + researcherProfileService = jasmine.createSpyObj('researcherProfileService', { + createFromExternalSourceAndReturnRelatedItemId: observableOf('mock-id'), + }); + translate = jasmine.createSpyObj('translate', { + get: observableOf('translated-message'), + }); + notificationsService = jasmine.createSpyObj('notificationsService', { + success: {}, + error: {}, + }); TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule], @@ -108,6 +123,9 @@ describe('DSOEditMenuResolver', () => { {provide: MenuService, useValue: menuService}, {provide: AuthorizationDataService, useValue: authorizationService}, {provide: DsoVersioningModalService, useValue: dsoVersioningModalService}, + {provide: ResearcherProfileDataService, useValue: researcherProfileService}, + {provide: TranslateService, useValue: translate}, + {provide: NotificationsService, useValue: notificationsService}, { provide: NgbModal, useValue: { open: () => {/*comment*/ @@ -194,17 +212,30 @@ describe('DSOEditMenuResolver', () => { }); }); describe('getDsoMenus', () => { - it('should return as first part the item version list ', (done) => { + it('should return as first part the item version, orcid and claim list ', (done) => { const result = resolver.getDsoMenus(testObject, route, state); result[0].subscribe((menuList) => { - expect(menuList.length).toEqual(1); - expect(menuList[0].id).toEqual('version-dso'); + expect(menuList.length).toEqual(3); + expect(menuList[0].id).toEqual('orcid-dso'); expect(menuList[0].active).toEqual(false); - expect(menuList[0].visible).toEqual(true); - expect(menuList[0].model.type).toEqual(MenuItemType.ONCLICK); - expect((menuList[0].model as TextMenuItemModel).text).toEqual('message'); - expect(menuList[0].model.disabled).toEqual(false); - expect(menuList[0].icon).toEqual('code-branch'); + // Visible should be false due to the item not being of type person + expect(menuList[0].visible).toEqual(false); + expect(menuList[0].model.type).toEqual(MenuItemType.LINK); + + expect(menuList[1].id).toEqual('version-dso'); + expect(menuList[1].active).toEqual(false); + expect(menuList[1].visible).toEqual(true); + expect(menuList[1].model.type).toEqual(MenuItemType.ONCLICK); + expect((menuList[1].model as TextMenuItemModel).text).toEqual('message'); + expect(menuList[1].model.disabled).toEqual(false); + expect(menuList[1].icon).toEqual('code-branch'); + + expect(menuList[2].id).toEqual('claim-dso'); + expect(menuList[2].active).toEqual(false); + // Visible should be false due to the item not being of type person + expect(menuList[2].visible).toEqual(false); + expect(menuList[2].model.type).toEqual(MenuItemType.ONCLICK); + expect((menuList[2].model as TextMenuItemModel).text).toEqual('item.page.claim.button'); done(); }); diff --git a/src/app/shared/dso-page/dso-edit-menu.resolver.ts b/src/app/shared/dso-page/dso-edit-menu.resolver.ts index ba695a002c..31e1baf76b 100644 --- a/src/app/shared/dso-page/dso-edit-menu.resolver.ts +++ b/src/app/shared/dso-page/dso-edit-menu.resolver.ts @@ -9,15 +9,18 @@ import { Item } from '../../core/shared/item.model'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { OnClickMenuItemModel } from '../menu/menu-item/models/onclick.model'; import { getFirstCompletedRemoteData } from '../../core/shared/operators'; -import { map, switchMap } from 'rxjs/operators'; +import { map, mergeMap, switchMap, take } from 'rxjs/operators'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { DsoVersioningModalService } from './dso-versioning-modal-service/dso-versioning-modal.service'; -import { hasNoValue, hasValue } from '../empty.util'; +import { hasNoValue, hasValue, isNotEmpty } from '../empty.util'; import { MenuID } from '../menu/menu-id.model'; import { MenuItemType } from '../menu/menu-item-type.model'; import { MenuSection } from '../menu/menu-section.model'; import { getDSORoute } from '../../app-routing-paths'; +import { ResearcherProfileDataService } from '../../core/profile/researcher-profile-data.service'; +import { NotificationsService } from '../notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; /** * Creates the menus for the dspace object pages @@ -33,6 +36,9 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection protected authorizationService: AuthorizationDataService, protected modalService: NgbModal, protected dsoVersioningModalService: DsoVersioningModalService, + protected researcherProfileService: ResearcherProfileDataService, + protected notificationsService: NotificationsService, + protected translate: TranslateService, ) { } @@ -96,7 +102,7 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection link: new URLCombiner(getDSORoute(dso), 'edit', 'metadata').toString() } as LinkMenuItemModel, icon: 'pencil-alt', - index: 1 + index: 2 }, ]; }) @@ -104,17 +110,32 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection } /** - * Get item sepcific menus + * Get item specific menus */ protected getItemMenu(dso): Observable { if (dso instanceof Item) { return combineLatest([ this.authorizationService.isAuthorized(FeatureID.CanCreateVersion, dso.self), this.dsoVersioningModalService.isNewVersionButtonDisabled(dso), - this.dsoVersioningModalService.getVersioningTooltipMessage(dso, 'item.page.version.hasDraft', 'item.page.version.create') + this.dsoVersioningModalService.getVersioningTooltipMessage(dso, 'item.page.version.hasDraft', 'item.page.version.create'), + this.authorizationService.isAuthorized(FeatureID.CanSynchronizeWithORCID, dso.self), + this.authorizationService.isAuthorized(FeatureID.CanClaimItem, dso.self), ]).pipe( - map(([canCreateVersion, disableVersioning, versionTooltip]) => { + map(([canCreateVersion, disableVersioning, versionTooltip, canSynchronizeWithOrcid, canClaimItem]) => { + const isPerson = this.getDsoType(dso) === 'person'; return [ + { + id: 'orcid-dso', + active: false, + visible: isPerson && canSynchronizeWithOrcid, + model: { + type: MenuItemType.LINK, + text: 'item.page.orcid.tooltip', + link: new URLCombiner(getDSORoute(dso), 'orcid').toString() + } as LinkMenuItemModel, + icon: 'orcid fab fa-lg', + index: 0 + }, { id: 'version-dso', active: false, @@ -128,7 +149,21 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection } } as OnClickMenuItemModel, icon: 'code-branch', - index: 0 + index: 1 + }, + { + id: 'claim-dso', + active: false, + visible: isPerson && canClaimItem, + model: { + type: MenuItemType.ONCLICK, + text: 'item.page.claim.button', + function: () => { + this.claimResearcher(dso); + } + } as OnClickMenuItemModel, + icon: 'hand-paper', + index: 3 }, ]; }), @@ -138,6 +173,26 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection } } + /** + * Claim a researcher by creating a profile + * Shows notifications and/or hides the menu section on success/error + */ + protected claimResearcher(dso) { + this.researcherProfileService.createFromExternalSourceAndReturnRelatedItemId(dso.self) + .subscribe((id: string) => { + if (isNotEmpty(id)) { + this.notificationsService.success(this.translate.get('researcherprofile.success.claim.title'), + this.translate.get('researcherprofile.success.claim.body')); + this.authorizationService.invalidateAuthorizationsRequestCache(); + this.menuService.hideMenuSection(MenuID.DSO_EDIT, 'claim-dso-' + dso.uuid); + } else { + this.notificationsService.error( + this.translate.get('researcherprofile.error.claim.title'), + this.translate.get('researcherprofile.error.claim.body')); + } + }); + } + /** * Retrieve the dso or entity type for an object to be used in generic messages */ diff --git a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.html b/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.html deleted file mode 100644 index 305900ae33..0000000000 --- a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.scss b/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.spec.ts b/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.spec.ts deleted file mode 100644 index c70ec4b808..0000000000 --- a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { Item } from '../../../core/shared/item.model'; -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { of as observableOf } from 'rxjs'; -import { TranslateModule } from '@ngx-translate/core'; -import { RouterTestingModule } from '@angular/router/testing'; -import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; -import { By } from '@angular/platform-browser'; -import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { DsoPageOrcidButtonComponent } from './dso-page-orcid-button.component'; - -describe('DsoPageOrcidButtonComponent', () => { - let component: DsoPageOrcidButtonComponent; - let fixture: ComponentFixture; - - let authorizationService: AuthorizationDataService; - let dso: DSpaceObject; - - beforeEach(waitForAsync(() => { - dso = Object.assign(new Item(), { - id: 'test-item', - _links: { - self: { href: 'test-item-selflink' } - } - }); - authorizationService = jasmine.createSpyObj('authorizationService', { - isAuthorized: observableOf(true) - }); - TestBed.configureTestingModule({ - declarations: [DsoPageOrcidButtonComponent], - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule], - providers: [ - { provide: AuthorizationDataService, useValue: authorizationService } - ] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DsoPageOrcidButtonComponent); - component = fixture.componentInstance; - component.dso = dso; - component.pageRoute = 'test'; - fixture.detectChanges(); - }); - - it('should check the authorization of the current user', () => { - expect(authorizationService.isAuthorized).toHaveBeenCalledWith(FeatureID.CanSynchronizeWithORCID, dso.self); - }); - - describe('when the user is authorized', () => { - beforeEach(() => { - (authorizationService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(true)); - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should render a link', () => { - const link = fixture.debugElement.query(By.css('a')); - expect(link).not.toBeNull(); - }); - }); - - describe('when the user is not authorized', () => { - beforeEach(() => { - (authorizationService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(false)); - component.ngOnInit(); - fixture.detectChanges(); - }); - - it('should not render a link', () => { - const link = fixture.debugElement.query(By.css('a')); - expect(link).toBeNull(); - }); - }); -}); diff --git a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.ts b/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.ts deleted file mode 100644 index c345d8cbdc..0000000000 --- a/src/app/shared/dso-page/dso-page-orcid-button/dso-page-orcid-button.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { BehaviorSubject } from 'rxjs'; -import { take } from 'rxjs/operators'; - -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; - -@Component({ - selector: 'ds-dso-page-orcid-button', - templateUrl: './dso-page-orcid-button.component.html', - styleUrls: ['./dso-page-orcid-button.component.scss'] -}) -export class DsoPageOrcidButtonComponent implements OnInit { - /** - * The DSpaceObject to display a button to the edit page for - */ - @Input() dso: DSpaceObject; - - /** - * The prefix of the route to the edit page (before the object's UUID, e.g. "items") - */ - @Input() pageRoute: string; - - /** - * Whether or not the current user is authorized to edit the DSpaceObject - */ - isAuthorized: BehaviorSubject = new BehaviorSubject(false); - - constructor(protected authorizationService: AuthorizationDataService) { } - - ngOnInit() { - this.authorizationService.isAuthorized(FeatureID.CanSynchronizeWithORCID, this.dso.self).pipe(take(1)).subscribe((isAuthorized: boolean) => { - this.isAuthorized.next(isAuthorized); - }); - } - -} diff --git a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.html b/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.html deleted file mode 100644 index c4bba286bf..0000000000 --- a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.html +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.scss b/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.spec.ts b/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.spec.ts deleted file mode 100644 index 5d589187b9..0000000000 --- a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { of as observableOf } from 'rxjs'; -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; - -import { PersonPageClaimButtonComponent } from './person-page-claim-button.component'; -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; -import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; -import { ResearcherProfileDataService } from '../../../core/profile/researcher-profile-data.service'; -import { RouteService } from '../../../core/services/route.service'; -import { routeServiceStub } from '../../testing/route-service.stub'; -import { Item } from '../../../core/shared/item.model'; -import { ResearcherProfile } from '../../../core/profile/model/researcher-profile.model'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; -import { getTestScheduler } from 'jasmine-marbles'; -import { TestScheduler } from 'rxjs/testing'; - -describe('PersonPageClaimButtonComponent', () => { - let scheduler: TestScheduler; - let component: PersonPageClaimButtonComponent; - let fixture: ComponentFixture; - - const mockItem: Item = Object.assign(new Item(), { - metadata: { - 'person.email': [ - { - language: 'en_US', - value: 'fake@email.com' - } - ], - 'person.birthDate': [ - { - language: 'en_US', - value: '1993' - } - ], - 'person.jobTitle': [ - { - language: 'en_US', - value: 'Developer' - } - ], - 'person.familyName': [ - { - language: 'en_US', - value: 'Doe' - } - ], - 'person.givenName': [ - { - language: 'en_US', - value: 'John' - } - ] - }, - _links: { - self: { - href: 'item-href' - } - } - }); - - const mockResearcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), { - id: 'test-id', - visible: true, - type: 'profile', - _links: { - item: { - href: 'https://rest.api/rest/api/profiles/test-id/item' - }, - self: { - href: 'https://rest.api/rest/api/profiles/test-id' - }, - } - }); - - const notificationsService = new NotificationsServiceStub(); - - const authorizationDataService = jasmine.createSpyObj('authorizationDataService', { - isAuthorized: jasmine.createSpy('isAuthorized') - }); - - const researcherProfileService = jasmine.createSpyObj('researcherProfileService', { - createFromExternalSource: jasmine.createSpy('createFromExternalSource'), - findRelatedItemId: jasmine.createSpy('findRelatedItemId'), - }); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: TranslateLoaderMock - } - }) - ], - declarations: [PersonPageClaimButtonComponent], - providers: [ - { provide: AuthorizationDataService, useValue: authorizationDataService }, - { provide: NotificationsService, useValue: notificationsService }, - { provide: ResearcherProfileDataService, useValue: researcherProfileService }, - { provide: RouteService, useValue: routeServiceStub }, - ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PersonPageClaimButtonComponent); - component = fixture.componentInstance; - component.object = mockItem; - }); - - describe('when item can be claimed', () => { - beforeEach(() => { - authorizationDataService.isAuthorized.and.returnValue(observableOf(true)); - researcherProfileService.createFromExternalSource.calls.reset(); - researcherProfileService.findRelatedItemId.calls.reset(); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should create claim button', () => { - const btn = fixture.debugElement.query(By.css('[data-test="item-claim"]')); - expect(btn).toBeTruthy(); - }); - - describe('claim', () => { - describe('when successfully', () => { - beforeEach(() => { - scheduler = getTestScheduler(); - researcherProfileService.createFromExternalSource.and.returnValue(createSuccessfulRemoteDataObject$(mockResearcherProfile)); - researcherProfileService.findRelatedItemId.and.returnValue(observableOf('test-id')); - }); - - it('should display success notification', () => { - scheduler.schedule(() => component.claim()); - scheduler.flush(); - - expect(researcherProfileService.findRelatedItemId).toHaveBeenCalled(); - expect(notificationsService.success).toHaveBeenCalled(); - }); - }); - - describe('when not successfully', () => { - beforeEach(() => { - scheduler = getTestScheduler(); - researcherProfileService.createFromExternalSource.and.returnValue(createFailedRemoteDataObject$()); - }); - - it('should display success notification', () => { - scheduler.schedule(() => component.claim()); - scheduler.flush(); - - expect(researcherProfileService.findRelatedItemId).not.toHaveBeenCalled(); - expect(notificationsService.error).toHaveBeenCalled(); - }); - }); - }); - - }); - - describe('when item cannot be claimed', () => { - beforeEach(() => { - authorizationDataService.isAuthorized.and.returnValue(observableOf(false)); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should create claim button', () => { - const btn = fixture.debugElement.query(By.css('[data-test="item-claim"]')); - expect(btn).toBeFalsy(); - }); - - }); -}); diff --git a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.ts b/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.ts deleted file mode 100644 index f0071d0a41..0000000000 --- a/src/app/shared/dso-page/person-page-claim-button/person-page-claim-button.component.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; -import { mergeMap, take } from 'rxjs/operators'; -import { TranslateService } from '@ngx-translate/core'; - -import { RouteService } from '../../../core/services/route.service'; -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { ResearcherProfileDataService } from '../../../core/profile/researcher-profile-data.service'; -import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; -import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; -import { RemoteData } from '../../../core/data/remote-data'; -import { ResearcherProfile } from '../../../core/profile/model/researcher-profile.model'; -import { isNotEmpty } from '../../empty.util'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; - -@Component({ - selector: 'ds-person-page-claim-button', - templateUrl: './person-page-claim-button.component.html', - styleUrls: ['./person-page-claim-button.component.scss'] -}) -export class PersonPageClaimButtonComponent implements OnInit { - - /** - * The target person item to claim - */ - @Input() object: DSpaceObject; - - /** - * A boolean representing if item can be claimed or not - */ - claimable$: BehaviorSubject = new BehaviorSubject(false); - - constructor(protected routeService: RouteService, - protected authorizationService: AuthorizationDataService, - protected notificationsService: NotificationsService, - protected translate: TranslateService, - protected researcherProfileService: ResearcherProfileDataService) { - } - - ngOnInit(): void { - this.authorizationService.isAuthorized(FeatureID.CanClaimItem, this.object._links.self.href, null, false).pipe( - take(1) - ).subscribe((isAuthorized: boolean) => { - this.claimable$.next(isAuthorized); - }); - - } - - /** - * Create a new researcher profile claiming the current item. - */ - claim() { - this.researcherProfileService.createFromExternalSource(this.object._links.self.href).pipe( - getFirstCompletedRemoteData(), - mergeMap((rd: RemoteData) => { - if (rd.hasSucceeded) { - return this.researcherProfileService.findRelatedItemId(rd.payload); - } else { - return observableOf(null); - } - })) - .subscribe((id: string) => { - if (isNotEmpty(id)) { - this.notificationsService.success(this.translate.get('researcherprofile.success.claim.title'), - this.translate.get('researcherprofile.success.claim.body')); - this.claimable$.next(false); - } else { - this.notificationsService.error( - this.translate.get('researcherprofile.error.claim.title'), - this.translate.get('researcherprofile.error.claim.body')); - } - }); - } - - /** - * Returns true if the item is claimable, false otherwise. - */ - isClaimable(): Observable { - return this.claimable$; - } - -} diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts index f44ddea649..60f4d6f89a 100644 --- a/src/app/shared/menu/menu.service.ts +++ b/src/app/shared/menu/menu.service.ts @@ -11,9 +11,9 @@ import { DeactivateMenuSectionAction, ExpandMenuAction, ExpandMenuPreviewAction, - HideMenuAction, + HideMenuAction, HideMenuSectionAction, RemoveMenuSectionAction, - ShowMenuAction, + ShowMenuAction, ShowMenuSectionAction, ToggleActiveMenuSectionAction, ToggleMenuAction, } from './menu.actions'; @@ -240,6 +240,15 @@ export class MenuService { this.store.dispatch(new ShowMenuAction(menuID)); } + /** + * Show a given menu section + * @param {MenuID} menuID The ID of the menu + * @param id The ID of the section + */ + showMenuSection(menuID: MenuID, id: string): void { + this.store.dispatch(new ShowMenuSectionAction(menuID, id)); + } + /** * Hide a given menu * @param {MenuID} menuID The ID of the menu @@ -248,6 +257,15 @@ export class MenuService { this.store.dispatch(new HideMenuAction(menuID)); } + /** + * Hide a given menu section + * @param {MenuID} menuID The ID of the menu + * @param id The ID of the section + */ + hideMenuSection(menuID: MenuID, id: string): void { + this.store.dispatch(new HideMenuSectionAction(menuID, id)); + } + /** * Activate a given menu section when it's currently inactive or deactivate it when it's currently active * @param {MenuID} menuID The ID of the menu diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index a341a5178a..90da0bc1dc 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -305,11 +305,9 @@ import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component' import { ThemedItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component'; import { RSSComponent } from './rss-feed/rss.component'; import { ExternalLinkMenuItemComponent } from './menu/menu-item/external-link-menu-item.component'; -import { DsoPageOrcidButtonComponent } from './dso-page/dso-page-orcid-button/dso-page-orcid-button.component'; import { LogInOrcidComponent } from './log-in/methods/orcid/log-in-orcid.component'; import { BrowserOnlyPipe } from './utils/browser-only.pipe'; import { ThemedLoadingComponent } from './loading/themed-loading.component'; -import { PersonPageClaimButtonComponent } from './dso-page/person-page-claim-button/person-page-claim-button.component'; import { SearchExportCsvComponent } from './search/search-export-csv/search-export-csv.component'; import { ItemPageTitleFieldComponent @@ -578,12 +576,10 @@ const ENTRY_COMPONENTS = [ const SHARED_ITEM_PAGE_COMPONENTS = [ MetadataFieldWrapperComponent, MetadataValuesComponent, - PersonPageClaimButtonComponent, ItemAlertsComponent, GenericItemPageFieldComponent, MetadataRepresentationListComponent, RelatedItemsComponent, - DsoPageOrcidButtonComponent, DsoEditMenuSectionComponent, DsoEditMenuComponent, DsoEditMenuExpandableSectionComponent,