95632: Refactor orcid/claim person buttons to dso-menu-resolver

This commit is contained in:
Kristof De Langhe
2022-10-11 15:05:06 +02:00
parent be8a3d278c
commit 964371066a
13 changed files with 142 additions and 422 deletions

View File

@@ -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<Resear
return this.rdbService.buildFromRequestUUID(requestId, followLink('item'));
}
/**
* Creates a researcher profile starting from an external source URI and returns the related item's ID
* Emits null if the researcher profile doesn't exist after sending out the request
* @param sourceUri
*/
createFromExternalSourceAndReturnRelatedItemId(sourceUri: string): Observable<string> {
return this.createFromExternalSource(sourceUri).pipe(
getFirstCompletedRemoteData(),
mergeMap((rd: RemoteData<ResearcherProfile>) => {
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

View File

@@ -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();
});

View File

@@ -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<MenuSection[]> {
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
*/

View File

@@ -1,6 +0,0 @@
<a *ngIf="isAuthorized | async"
[ngbTooltip]="'item.page.orcid.tooltip' | translate"
[routerLink]="[pageRoute, 'orcid']"
class="btn btn-dark btn-sm"
role="button" ><i class="fab fa-orcid fa-lg"></i>
</a>

View File

@@ -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<DsoPageOrcidButtonComponent>;
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();
});
});
});

View File

@@ -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<boolean> = 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);
});
}
}

View File

@@ -1,7 +0,0 @@
<button *ngIf="(isClaimable() | async)"
[ngbTooltip]="'item.page.claim.tooltip' | translate"
class="edit-button btn btn-dark btn-sm"
data-test="item-claim"
(click)="claim()">
{{'item.page.claim.button' | translate }}
</button>

View File

@@ -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<PersonPageClaimButtonComponent>;
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();
});
});
});

View File

@@ -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<boolean> = new BehaviorSubject<boolean>(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<ResearcherProfile>) => {
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<boolean> {
return this.claimable$;
}
}

View File

@@ -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

View File

@@ -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,