diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html
index 7f1e8716ba..0534b7fd92 100644
--- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html
+++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html
@@ -3,7 +3,7 @@
[ngClass]="{ disabled: isDisabled }"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="'sidebarName-' + section.id"
- [title]="('menu.section.icon.' + section.id) | translate"
+ [title]="itemModel.text | translate"
[routerLink]="itemModel.link"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html
index 3edb01d621..85bfce804e 100644
--- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html
+++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html
@@ -6,7 +6,7 @@
role="button" tabindex="0"
[attr.aria-labelledby]="'sidebarName-' + section.id"
[attr.aria-expanded]="expanded | async"
- [title]="('menu.section.icon.' + section.id) | translate"
+ [title]="itemModel.text | translate"
[class.disabled]="section.model?.disabled"
(click)="toggleSection($event)"
(keyup.space)="toggleSection($event)"
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 94298c84a9..4af778433d 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -32,12 +32,10 @@ import { ReloadGuard } from './core/reload/reload.guard';
import { ServerCheckGuard } from './core/server-check/server-check.guard';
import { ThemedForbiddenComponent } from './forbidden/themed-forbidden.component';
import { ENTITY_MODULE_PATH, ITEM_MODULE_PATH } from './item-page/item-page-routing-paths';
-import { MenuResolver } from './menu.resolver';
import { ThemedPageErrorComponent } from './page-error/themed-page-error.component';
import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component';
import { ThemedPageNotFoundComponent } from './pagenotfound/themed-pagenotfound.component';
import { PROCESS_MODULE_PATH } from './process-page/process-page-routing.paths';
-import { MenuProviderService } from './shared/menu/menu-provider.service';
// import { resolveStaticMenus } from './shared/menu/menu.resolver';
@NgModule({
diff --git a/src/app/app.menus.ts b/src/app/app.menus.ts
index c0199fb8fd..7679db4c42 100644
--- a/src/app/app.menus.ts
+++ b/src/app/app.menus.ts
@@ -30,8 +30,7 @@ import { WorkflowMenuProvider } from './shared/menu/providers/workflow.menu';
import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-paths';
import { COLLECTION_MODULE_PATH } from './collection-page/collection-page-routing-paths';
import { ENTITY_MODULE_PATH, ITEM_MODULE_PATH } from './item-page/item-page-routing-paths';
-import { HOME_PAGE_PATH } from './app-routing-paths';
-import { DsoOptionMenu } from './shared/menu/providers/dso-option-menu.service';
+import { DsoOptionMenu } from './shared/menu/providers/dso-option.menu';
export const MENUS = buildMenuStructure({
[MenuID.PUBLIC]: [
@@ -55,12 +54,11 @@ export const MENUS = buildMenuStructure({
],
[MenuID.DSO_EDIT]: [
DsoOptionMenu.withSubs([
+ SubscribeMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH),
DSpaceObjectEditMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH, ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
VersioningMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
OrcidMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
- ClaimMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
- // SubscribeMenuProvider,
+ ClaimMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH, COLLECTION_MODULE_PATH),
]),
- SubscribeMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH),
],
});
diff --git a/src/app/collection-page/collection-page-routing.module.ts b/src/app/collection-page/collection-page-routing.module.ts
index d45b4b12a3..7930c1ae6f 100644
--- a/src/app/collection-page/collection-page-routing.module.ts
+++ b/src/app/collection-page/collection-page-routing.module.ts
@@ -5,9 +5,6 @@ import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-bre
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
import { LinkService } from '../core/cache/builders/link.service';
-import { SubscribeMenuProvider } from '../shared/menu/providers/comcol-subscribe.menu';
-import { DSpaceObjectEditMenuProvider } from '../shared/menu/providers/dso-edit.menu';
-import { StatisticsMenuProvider } from '../shared/menu/providers/statistics.menu';
import { CollectionPageAdministratorGuard } from './collection-page-administrator.guard';
import {
COLLECTION_CREATE_PATH,
diff --git a/src/app/init.service.ts b/src/app/init.service.ts
index ce4055ebde..6dc99126ca 100644
--- a/src/app/init.service.ts
+++ b/src/app/init.service.ts
@@ -21,11 +21,10 @@ import { MetadataService } from './core/metadata/metadata.service';
import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service';
import { ThemeService } from './shared/theme-support/theme.service';
import { isAuthenticationBlocking } from './core/auth/selectors';
-import { distinctUntilChanged, find, switchMap } from 'rxjs/operators';
+import { distinctUntilChanged, find } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { MenuService } from './shared/menu/menu.service';
import { MenuProviderService } from './shared/menu/menu-provider.service';
-import { MenuID } from './shared/menu/menu-id.model';
/**
* Performs the initialization of the app.
@@ -190,18 +189,9 @@ export abstract class InitService {
this.metadata.listenForRouteChange();
this.breadcrumbsService.listenForRouteChanges();
this.themeService.listenForRouteChanges();
- // this.menuService.listenForRouteChanges();
this.menuProviderService.listenForRouteChanges();
}
- protected initPersistentMenus(): void {
- this.menuProviderService.resolvePersistentMenus().subscribe((done) => {
- Object.values(MenuID).forEach((menuID) => {
- this.menuService.buildRouteMenuSections(menuID);
- });
- });
- }
-
/**
* Emits once authentication is ready (no longer blocking)
* @protected
diff --git a/src/app/item-page/item-page-routing.module.ts b/src/app/item-page/item-page-routing.module.ts
index 0a8438f543..1c93dab744 100644
--- a/src/app/item-page/item-page-routing.module.ts
+++ b/src/app/item-page/item-page-routing.module.ts
@@ -5,20 +5,13 @@ import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
import { ItemBreadcrumbResolver } from '../core/breadcrumbs/item-breadcrumb.resolver';
import { LinkService } from '../core/cache/builders/link.service';
-import { DSpaceObjectEditMenuProvider } from '../shared/menu/providers/dso-edit.menu';
-import { ClaimMenuProvider } from '../shared/menu/providers/item-claim.menu';
-import { OrcidMenuProvider } from '../shared/menu/providers/item-orcid.menu';
-import { VersioningMenuProvider } from '../shared/menu/providers/item-versioning.menu';
-import { StatisticsMenuProvider } from '../shared/menu/providers/statistics.menu';
-import { BitstreamRequestACopyPageComponent } from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
+import {
+ BitstreamRequestACopyPageComponent
+} from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
import { ThemedFullItemPageComponent } from './full/themed-full-item-page.component';
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
-import {
- ITEM_EDIT_PATH,
- ORCID_PATH,
- UPLOAD_BITSTREAM_PATH,
-} from './item-page-routing-paths';
+import { ITEM_EDIT_PATH, ORCID_PATH, UPLOAD_BITSTREAM_PATH, } from './item-page-routing-paths';
import { ItemPageResolver } from './item-page.resolver';
import { OrcidPageComponent } from './orcid-page/orcid-page.component';
import { OrcidPageGuard } from './orcid-page/orcid-page.guard';
diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html
index 61ca511674..dd80a992b7 100644
--- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html
+++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts
index f3a2fd627a..a381ad9f66 100644
--- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts
+++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts
@@ -65,6 +65,6 @@ export class DsoEditMenuExpandableSectionComponent extends AbstractMenuSectionCo
this.hasSubSections$ = this.subSections$.pipe(
map((subSections) => isNotEmpty(subSections))
);
-
+
}
}
diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.spec.ts b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.spec.ts
index f0815c5415..bfd881aea2 100644
--- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.spec.ts
+++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.spec.ts
@@ -127,17 +127,17 @@ describe('DsoEditMenuSectionComponent', () => {
stopPropagation: jasmine.createSpy('stopPropagation'),
});
it('should call the item model function when not disabled', () => {
- spyOn(component.section.model as OnClickMenuItemModel, 'function');
+ spyOn((component as any).section.model as OnClickMenuItemModel, 'function');
component.activate(mockEvent);
- expect((component.section.model as OnClickMenuItemModel).function).toHaveBeenCalled();
+ expect(((component as any).section.model as OnClickMenuItemModel).function).toHaveBeenCalled();
});
it('should call not the item model function when disabled', () => {
- spyOn(component.section.model as OnClickMenuItemModel, 'function');
+ spyOn((component as any).section.model as OnClickMenuItemModel, 'function');
component.itemModel.disabled = true;
component.activate(mockEvent);
- expect((component.section.model as OnClickMenuItemModel).function).not.toHaveBeenCalled();
+ expect(((component as any).section.model as OnClickMenuItemModel).function).not.toHaveBeenCalled();
component.itemModel.disabled = false;
});
});
diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu.component.spec.ts b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu.component.spec.ts
index 5616e8ea10..d7f0ead878 100644
--- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu.component.spec.ts
+++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu.component.spec.ts
@@ -16,6 +16,7 @@ import { getMockThemeService } from '../../mocks/theme-service.mock';
import { DsoPageModule } from '../dso-page.module';
+import { TextMenuItemModel } from '../../menu/menu-item/models/text.model';
describe('DsoEditMenuComponent', () => {
let comp: DsoEditMenuComponent;
@@ -32,9 +33,10 @@ describe('DsoEditMenuComponent', () => {
active: false,
visible: true,
model: {
+ text: 'section-text',
type: null,
disabled: false,
- } as MenuItemModel,
+ } as TextMenuItemModel,
icon: 'pencil-alt',
index: 1
};
diff --git a/src/app/shared/menu/menu-provider.service.ts b/src/app/shared/menu/menu-provider.service.ts
index b749c9f5a0..a984e594f8 100644
--- a/src/app/shared/menu/menu-provider.service.ts
+++ b/src/app/shared/menu/menu-provider.service.ts
@@ -66,12 +66,8 @@ export class MenuProviderService {
}
- public resolvePersistentMenus(
- // route: ActivatedRouteSnapshot,
- // state: RouterStateSnapshot
- ): Observable {
-
- return combineLatest([
+ public initPersistentMenus() {
+ combineLatest([
...this.providers
.map((provider) => {
return provider;
@@ -98,63 +94,69 @@ export class MenuProviderService {
return [waitForMenus];
}),
map(done => done.every(Boolean)),
- );
+ ).subscribe((done) => {
+ Object.values(MenuID).forEach((menuID) => {
+ this.menuService.buildRouteMenuSections(menuID);
+ });
+ });
}
public resolveRouteMenus(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable {
- return combineLatest([
+ const currentNonPersistentMenuSections$ = combineLatest([
...Object.values(MenuID).map((menuID) => {
return this.menuService.getNonPersistentMenuSections(menuID).pipe(
take(1),
map((sections) => {
return {menuId: menuID, sections: sections};
}));
- })])
- .pipe(
- switchMap((menuSectionsPerMenu) => {
- this.removeNonPersistentSections(menuSectionsPerMenu);
- return combineLatest([
- ...this.providers
- .filter(provider => {
- let shouldUpdate = false;
- if (!provider.shouldPersistOnRouteChange && isNotEmpty(provider.activePaths)) {
- provider.activePaths.forEach((path) => {
- if (state.url.includes(path)) {
- shouldUpdate = true;
- }
- });
- } else if (!provider.shouldPersistOnRouteChange) {
- shouldUpdate = true;
- }
- return shouldUpdate;
- })
- .map(provider => provider.getSections(route, state)
- .pipe(
- map((sections) => {
- return {provider: provider, sections: sections};
- }),
- )
- )
- ]);
- }),
- switchMap((providerWithSections: { provider: AbstractMenuProvider, sections: PartialMenuSection[] }[]) => {
- const waitForMenus = providerWithSections.map((providerWithSection: {
- provider: AbstractMenuProvider,
- sections: PartialMenuSection[]
- }, sectionIndex) => {
- providerWithSection.sections.forEach((section) => {
- this.addSection(providerWithSection, section);
+ })]);
+
+ const routeDependentMenuSections$ = combineLatest([
+ ...this.providers
+ .filter(provider => {
+ let shouldUpdate = false;
+ if (!provider.shouldPersistOnRouteChange && isNotEmpty(provider.activePaths)) {
+ provider.activePaths.forEach((path) => {
+ if (state.url.includes(path)) {
+ shouldUpdate = true;
+ }
});
- return this.waitForMenu$(providerWithSection.provider.menuID);
+ } else if (!provider.shouldPersistOnRouteChange) {
+ shouldUpdate = true;
+ }
+ return shouldUpdate;
+ })
+ .map(provider => provider.getSections(route, state)
+ .pipe(
+ map((sections) => {
+ return {provider: provider, sections: sections};
+ }),
+ )
+ )
+ ]);
+
+ return combineLatest([
+ currentNonPersistentMenuSections$,
+ routeDependentMenuSections$
+ ]).pipe(
+ switchMap(([currentMenusWithSections, providerWithSections]) => {
+ this.removeNonPersistentSections(currentMenusWithSections);
+ const waitForMenus = providerWithSections.map((providerWithSection: {
+ provider: AbstractMenuProvider,
+ sections: PartialMenuSection[]
+ }) => {
+ providerWithSection.sections.forEach((section) => {
+ this.addSection(providerWithSection, section);
});
- return [waitForMenus];
- }),
- map(done => done.every(Boolean)),
- );
- // }
+ return this.waitForMenu$(providerWithSection.provider.menuID);
+ });
+ return [waitForMenus];
+ }),
+ map(done => done.every(Boolean)),
+ );
}
private addSection(providerWithSection: {
@@ -167,7 +169,7 @@ export class MenuProviderService {
parentID: section.parentID ?? providerWithSection.provider.parentID,
index: section.index ?? providerWithSection.provider.index,
shouldPersistOnRouteChange: section.shouldPersistOnRouteChange ?? providerWithSection.provider.shouldPersistOnRouteChange,
- isExpandable: section.isExpandable ?? providerWithSection.provider.isExpandable,
+ alwaysRenderExpandable: section.alwaysRenderExpandable ?? providerWithSection.provider.alwaysRenderExpandable,
});
}
diff --git a/src/app/shared/menu/menu-provider.ts b/src/app/shared/menu/menu-provider.ts
index f13d323744..7044870f17 100644
--- a/src/app/shared/menu/menu-provider.ts
+++ b/src/app/shared/menu/menu-provider.ts
@@ -5,28 +5,15 @@
*
* http://www.dspace.org/license/
*/
-
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import { Omit } from '@material-ui/core';
+/* eslint-disable max-classes-per-file */
+import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
import flatten from 'lodash/flatten';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
import { MenuID } from './menu-id.model';
-import { MenuItemModels, MenuSection } from './menu-section.model';
-import { APP_INITIALIZER, Provider, Type } from '@angular/core';
-import { APP_CONFIG } from '../../../config/app-config.interface';
-import { TransferState } from '@angular/platform-browser';
-import { environment } from '../../../environments/environment';
-import { HOME_PAGE_PATH } from '../../app-routing-paths';
-import { MENU_PROVIDER } from './menu.structure';
+import { MenuItemModels } from './menu-section.model';
+import { Type } from '@angular/core';
-// export type PartialMenuSection = Omit;
export interface PartialMenuSection {
id?: string;
visible: boolean;
@@ -36,11 +23,10 @@ export interface PartialMenuSection {
active?: boolean;
shouldPersistOnRouteChange?: boolean;
icon?: string;
- isExpandable?: boolean;
+ alwaysRenderExpandable?: boolean;
}
-
export interface MenuProvider {
shouldPersistOnRouteChange?: boolean,
menuID?: MenuID;
@@ -49,35 +35,37 @@ export interface MenuProvider {
getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable;
}
-export class MenuProviderTypeWithPaths {
+export class MenuProviderTypeWithOptions {
providerType: Type;
- paths: string[];
-}
+ paths?: string[];
+ childProviderTypes?: (Type | MenuProviderTypeWithOptions)[];
-export class MenuProviderTypeWithSubs {
- providerType: Type;
- childProviderTypes: (Type | MenuProviderTypeWithPaths)[];
}
export abstract class AbstractMenuProvider implements MenuProvider {
- shouldPersistOnRouteChange = true;
+
+ /**
+ * ID of the menu this provider is part of
+ * If not set up, this will be set based on the provider class name
+ */
menuID?: MenuID;
+
+ /**
+ * Whether the sections of this menu should be set on the
+ */
+ shouldPersistOnRouteChange = true;
menuProviderId?: string;
index?: number;
activePaths?: string[];
parentID?: string;
- isExpandable = false;
+
+ /**
+ * Whether the menu section or top section of this provider will always be rendered as expandable and hidden when no children are present
+ */
+ alwaysRenderExpandable? = false;
- abstract getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable;
-
- protected concat(...sections$: Observable[]): Observable {
- return combineLatest(sections$).pipe(
- map(sections => flatten(sections)),
- );
- }
-
- public static onRoute(...paths: string[]) {
+ public static onRoute(...paths: string[]): MenuProviderTypeWithOptions {
if (!AbstractMenuProvider.isPrototypeOf(this)) {
throw new Error(
'onRoute should only be called from concrete subclasses of AbstractMenuProvider'
@@ -87,6 +75,29 @@ export abstract class AbstractMenuProvider implements MenuProvider {
const providerType = this as unknown as Type;
return {providerType: providerType, paths: paths};
}
+
+ /**
+ * Method to add sub menu providers to this top provider
+ * @param childProviders - the list of sub providers that will provide subsections for this provider
+ */
+ public static withSubs(childProviders: (Type | MenuProviderTypeWithOptions)[]): MenuProviderTypeWithOptions {
+ if (!AbstractMenuProvider.isPrototypeOf(this)) {
+ throw new Error(
+ 'withSubs should only be called from concrete subclasses of AbstractMenuProvider'
+ );
+ }
+
+ const providerType = this as unknown as Type;
+ return {providerType: providerType, childProviderTypes: childProviders};
+ }
+
+ abstract getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable;
+
+ protected concat(...sections$: Observable[]): Observable {
+ return combineLatest(sections$).pipe(
+ map(sections => flatten(sections)),
+ );
+ }
}
diff --git a/src/app/shared/menu/menu-section.model.ts b/src/app/shared/menu/menu-section.model.ts
index 5c53364889..700f179a3f 100644
--- a/src/app/shared/menu/menu-section.model.ts
+++ b/src/app/shared/menu/menu-section.model.ts
@@ -80,5 +80,5 @@ export interface MenuSection {
*/
icon?: string;
- isExpandable?: boolean;
+ alwaysRenderExpandable?: boolean;
}
diff --git a/src/app/shared/menu/menu-section/menu-section.component.spec.ts b/src/app/shared/menu/menu-section/menu-section.component.spec.ts
index 8949c6c1b0..9f2deae0e9 100644
--- a/src/app/shared/menu/menu-section/menu-section.component.spec.ts
+++ b/src/app/shared/menu/menu-section/menu-section.component.spec.ts
@@ -1,6 +1,5 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-import { Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import {
ChangeDetectionStrategy,
diff --git a/src/app/shared/menu/menu.component.spec.ts b/src/app/shared/menu/menu.component.spec.ts
index f0660fab4a..707b1c0746 100644
--- a/src/app/shared/menu/menu.component.spec.ts
+++ b/src/app/shared/menu/menu.component.spec.ts
@@ -15,6 +15,8 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/
import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
import { ThemeService } from '../theme-support/theme.service';
import { getMockThemeService } from '../mocks/theme-service.mock';
+import { MenuItemType } from './menu-item-type.model';
+import { TextMenuItemModel } from './menu-item/models/text.model';
describe('MenuComponent', () => {
let comp: MenuComponent;
@@ -22,6 +24,16 @@ describe('MenuComponent', () => {
let menuService: MenuService;
let router: any;
+ const menuSection: MenuSection = {
+ id: 'browse',
+ model: {
+ type: MenuItemType.TEXT,
+ text: 'menu.section.browse_global',
+ } as TextMenuItemModel,
+ icon: 'globe',
+ visible: true,
+ }
+
const mockMenuID = 'mock-menuID' as MenuID;
const mockStatisticSection = { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } };
@@ -76,7 +88,7 @@ describe('MenuComponent', () => {
comp.menuID = mockMenuID;
menuService = (comp as any).menuService;
router = TestBed.inject(Router);
- spyOn(comp as any, 'getSectionDataInjector').and.returnValue(MenuSection);
+ spyOn(comp as any, 'getSectionDataInjector').and.returnValue(menuSection);
spyOn(comp as any, 'getSectionComponent').and.returnValue(observableOf({}));
fixture.detectChanges();
});
diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts
index f3b04a26b7..89f6fb3e73 100644
--- a/src/app/shared/menu/menu.component.ts
+++ b/src/app/shared/menu/menu.component.ts
@@ -218,7 +218,7 @@ export class MenuComponent implements OnInit, OnDestroy {
private getSectionComponent(section: MenuSection): Observable> {
return this.menuService.hasSubSections(this.menuID, section.id).pipe(
map((expandable: boolean) => {
- return getComponentForMenu(this.menuID, expandable || section.isExpandable, this.themeService.getThemeName());
+ return getComponentForMenu(this.menuID, expandable || section.alwaysRenderExpandable, this.themeService.getThemeName());
}
),
);
diff --git a/src/app/shared/menu/menu.resolver.ts b/src/app/shared/menu/menu.resolver.ts
index 15e0dc9803..9f01934670 100644
--- a/src/app/shared/menu/menu.resolver.ts
+++ b/src/app/shared/menu/menu.resolver.ts
@@ -5,17 +5,10 @@
*
* http://www.dspace.org/license/
*/
-import {
- inject,
- Type,
-} from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import { Observable } from 'rxjs';
-import { AbstractMenuProvider } from './menu-provider';
-import { MenuProviderService } from './menu-provider.service';
+
+
+
+
// export function resolveStaticMenus(): (ActivatedRouteSnapshot, RouterStateSnapshot, ProviderMenuService) => Observable {
// return (
diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts
index df6b246ec3..ed367a1fc3 100644
--- a/src/app/shared/menu/menu.service.ts
+++ b/src/app/shared/menu/menu.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
import { AppState, keySelector } from '../../app.reducer';
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
-import { filter, map, switchMap, take, tap } from 'rxjs/operators';
+import { filter, map, switchMap, take } from 'rxjs/operators';
import {
ActivateMenuSectionAction,
AddMenuSectionAction,
diff --git a/src/app/shared/menu/menu.structure.ts b/src/app/shared/menu/menu.structure.ts
index 9eaca8d400..bc58f70391 100644
--- a/src/app/shared/menu/menu.structure.ts
+++ b/src/app/shared/menu/menu.structure.ts
@@ -5,48 +5,22 @@
*
* http://www.dspace.org/license/
*/
-import {
- InjectionToken,
- Provider,
- Type,
-} from '@angular/core';
+import { InjectionToken, Provider, Type, } from '@angular/core';
import { MenuID } from './menu-id.model';
-import { AbstractMenuProvider } from './menu-provider';
+import { AbstractMenuProvider, MenuProviderTypeWithOptions } from './menu-provider';
import { MenuProviderService } from './menu-provider.service';
import { hasValue, isNotEmpty } from '../empty.util';
export const MENU_PROVIDER = new InjectionToken('MENU_PROVIDER');
type MenuStructure = {
- [key in MenuID]: (Type | {providerType: Type, paths: string[]} | {providerType: Type, childProviderTypes: any[]})[];
+ [key in MenuID]: (Type | MenuProviderTypeWithOptions)[];
};
-function resolveProvider(providerType: Type , menuID: string, index: number, paths?: string[], parentID?: string, childProviders? : Type[]) {
- return {
- provide: MENU_PROVIDER,
- multi: true,
- useFactory(provider: AbstractMenuProvider): AbstractMenuProvider {
- provider.menuID = menuID as MenuID;
- provider.index = provider.index ?? index;
- if (hasValue(parentID)) {
- provider.menuProviderId = `${parentID}_${provider.constructor.name}-${provider.index}`
- provider.parentID = parentID;
- } else {
- provider.menuProviderId = `${provider.constructor.name}-${provider.index}`;
- }
- if (isNotEmpty(paths)) {
- provider.activePaths = paths;
- provider.shouldPersistOnRouteChange = false;
- }
- if (isNotEmpty(childProviders)) {
- provider.shouldPersistOnRouteChange = false;
- }
- return provider;
- },
- deps: [providerType],
- };
-}
-
+/**
+ * Builds the menu structure by converting the provider types into resolved providers
+ * @param structure - The app menus structure
+ */
export function buildMenuStructure(structure: MenuStructure): Provider[] {
const providers: Provider[] = [
MenuProviderService,
@@ -54,44 +28,77 @@ export function buildMenuStructure(structure: MenuStructure): Provider[] {
Object.entries(structure).forEach(([menuID, providerTypes]) => {
for (const [index, providerType] of providerTypes.entries()) {
- // todo: should complain if not injectable!
-
- if (providerType.hasOwnProperty('providerType') && providerType.hasOwnProperty('paths')) {
- const providerPart = (providerType as any).providerType;
- const paths = (providerType as any).paths;
- providers.push(providerPart);
- providers.push(resolveProvider(providerPart, menuID, index, paths));
- } else if (providerType.hasOwnProperty('providerType') && providerType.hasOwnProperty('childProviderTypes')){
- const providerPart = (providerType as any).providerType;
-
- const childProviderList = [];
- const childProviderTypes = (providerType as any).childProviderTypes;
- childProviderTypes.forEach((childProviderType, childIndex: number) => {
-
-
- if (childProviderType.hasOwnProperty('providerType') && childProviderType.hasOwnProperty('paths')) {
- const childProviderTypePart = (childProviderType as any).providerType;
- const paths = (childProviderType as any).paths;
- providers.push(childProviderTypePart);
- providers.push(resolveProvider(childProviderTypePart, menuID, childIndex, paths, `${providerPart.name}-${index}`))
- childProviderList.push(childProviderTypePart);
- } else {
- providers.push(childProviderType)
- providers.push(resolveProvider(childProviderType, menuID, childIndex, undefined, `${providerPart.name}-${index}`))
- childProviderList.push(childProviderType);
- }
- })
-
- providers.push(providerPart);
- providers.push(resolveProvider(providerPart, menuID, index, undefined, undefined, childProviderList));
-
-
- } else {
- providers.push(providerType as Type );
- providers.push(resolveProvider(providerType as Type, menuID, index));
- }
+ processProviderType(providers, menuID, providerType, index);
}
});
return providers;
}
+
+/**
+ * Process a single provider type and add it to the list of providers
+ * When the provider type contains paths, the paths will be added to resolved provider
+ * When the provider type has sub provider, the sub providers will be processed with the current provider type as parent
+ * @param providers - The list of providers
+ * @param providerType - The provider to resolve and add to the list
+ * @param menuID - The ID of the menu to which the provider belongs
+ * @param index - The index of the provider
+ * @param parentID - The ID of the parent provider if relevant
+ * @param hasSubProviders - Whether this provider has sub providers
+ */
+function processProviderType(providers: Provider[], menuID: string, providerType: Type | MenuProviderTypeWithOptions, index: number, parentID?: string, hasSubProviders?: boolean) {
+ if (providerType.hasOwnProperty('providerType') && providerType.hasOwnProperty('childProviderTypes')) {
+ const providerPart = (providerType as any).providerType;
+ const childProviderTypes = (providerType as any).childProviderTypes;
+
+ childProviderTypes.forEach((childProviderType, childIndex: number) => {
+ processProviderType(providers, menuID, childProviderType, childIndex, `${providerPart.name}`, hasSubProviders);
+ });
+ processProviderType(providers, menuID, providerPart, index, parentID, true);
+
+ } else if (providerType.hasOwnProperty('providerType') && providerType.hasOwnProperty('paths')) {
+ const providerPart = (providerType as any).providerType;
+ const paths = (providerType as any).paths;
+ addProviderToList(providers, providerPart, menuID, index, parentID, hasSubProviders, paths);
+ } else {
+ addProviderToList(providers, providerType as Type, menuID, index, parentID, hasSubProviders);
+ }
+}
+
+/**
+ * Resolves and adds a provider to a list of providers
+ * @param providers - The list of providers
+ * @param providerType - The provider to resolve and add to the list
+ * @param menuID - The ID of the menu to which the provider belongs
+ * @param index - The index of the provider
+ * @param parentID - The ID of the parent provider if relevant
+ * @param hasSubProviders - Whether this provider has sub providers
+ * @param paths - The paths this provider should be active on if relevant
+ */
+function addProviderToList(providers: Provider[], providerType: Type, menuID: string, index: number, parentID?: string, hasSubProviders?: boolean, paths?: string[]) {
+ const resolvedProvider = {
+ provide: MENU_PROVIDER,
+ multi: true,
+ useFactory(provider: AbstractMenuProvider): AbstractMenuProvider {
+ provider.menuID = menuID as MenuID;
+ provider.index = provider.index ?? index;
+ if (hasValue(parentID)) {
+ provider.menuProviderId = `${parentID}_${provider.constructor.name}`;
+ provider.parentID = parentID;
+ } else {
+ provider.menuProviderId = `${provider.constructor.name}`;
+ }
+ if (isNotEmpty(paths)) {
+ provider.activePaths = paths;
+ provider.shouldPersistOnRouteChange = false;
+ }
+ if (hasSubProviders) {
+ provider.shouldPersistOnRouteChange = false;
+ }
+ return provider;
+ },
+ deps: [providerType],
+ };
+ providers.push(resolvedProvider);
+ providers.push(providerType);
+}
diff --git a/src/app/shared/menu/providers/access-control.menu.ts b/src/app/shared/menu/providers/access-control.menu.ts
index 311fc49777..312ad2d065 100644
--- a/src/app/shared/menu/providers/access-control.menu.ts
+++ b/src/app/shared/menu/providers/access-control.menu.ts
@@ -8,24 +8,17 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest as observableCombineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
+
constructor(
protected authorizationService: AuthorizationDataService,
protected scriptDataService: ScriptDataService,
@@ -34,17 +27,18 @@ export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf({
- model: {
- type: MenuItemType.TEXT,
- text: 'menu.section.access_control',
- },
- icon: 'key'
+ model: {
+ type: MenuItemType.TEXT,
+ text: 'menu.section.access_control',
+ },
+ icon: 'key',
+ visible: true,
});
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return observableCombineLatest([
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
this.authorizationService.isAuthorized(FeatureID.CanManageGroups),
@@ -87,7 +81,7 @@ export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
// link: ''
// } as LinkMenuItemModel,
// },
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/admin-search.menu.ts b/src/app/shared/menu/providers/admin-search.menu.ts
index 9d5e2cdb98..dbc288b4c6 100644
--- a/src/app/shared/menu/providers/admin-search.menu.ts
+++ b/src/app/shared/menu/providers/admin-search.menu.ts
@@ -7,18 +7,11 @@
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- map,
- Observable,
-} from 'rxjs';
+import { combineLatest, map, Observable, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
@Injectable()
export class AdminSearchMenuProvider extends AbstractMenuProvider {
diff --git a/src/app/shared/menu/providers/browse.menu.ts b/src/app/shared/menu/providers/browse.menu.ts
index 06a6cf3dbe..e6ca1f3db5 100644
--- a/src/app/shared/menu/providers/browse.menu.ts
+++ b/src/app/shared/menu/providers/browse.menu.ts
@@ -7,10 +7,7 @@
*/
import { Injectable } from '@angular/core';
-import {
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { Observable, of as observableOf, } from 'rxjs';
import { map } from 'rxjs/operators';
import { BrowseService } from '../../../core/browse/browse.service';
import { PaginatedList } from '../../../core/data/paginated-list.model';
@@ -19,11 +16,8 @@ import { BrowseDefinition } from '../../../core/shared/browse-definition.model';
import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { MenuItemType } from '../menu-item-type.model';
import { TextMenuItemModel } from '../menu-item/models/text.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
@@ -33,7 +27,7 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- getTopSection(): Observable {
+ getTopSection(): Observable {
return observableOf(
{
model: {
@@ -41,11 +35,12 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.browse_global',
} as TextMenuItemModel,
icon: 'globe',
+ visible: true,
},
);
}
- getSubSections(): Observable {
+ getSubSections(): Observable {
return this.browseService.getBrowseDefinitions().pipe(
getFirstSucceededRemoteData(),
map((rd: RemoteData>) => {
@@ -60,7 +55,7 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
},
};
}),
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/comcol-subscribe.menu.ts b/src/app/shared/menu/providers/comcol-subscribe.menu.ts
index 77a4b86cfe..9c17aa3952 100644
--- a/src/app/shared/menu/providers/comcol-subscribe.menu.ts
+++ b/src/app/shared/menu/providers/comcol-subscribe.menu.ts
@@ -7,40 +7,27 @@
*/
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import { Collection } from '../../../core/shared/collection.model';
-import { COLLECTION } from '../../../core/shared/collection.resource-type';
-import { Community } from '../../../core/shared/community.model';
-import { COMMUNITY } from '../../../core/shared/community.resource-type';
import { SubscriptionModalComponent } from '../../subscriptions/subscription-modal/subscription-modal.component';
import { MenuItemType } from '../menu-item-type.model';
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
import { PartialMenuSection } from '../menu-provider';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
+import { DSpaceObject } from '../../../core/shared/dspace-object.model';
@Injectable()
-export class SubscribeMenuProvider extends DSpaceObjectPageMenuProvider {
+export class SubscribeMenuProvider extends DSpaceObjectPageMenuProvider {
constructor(
protected authorizationService: AuthorizationDataService,
protected modalService: NgbModal,
- protected dsoDataService: DSpaceObjectDataService,
) {
- super(dsoDataService);
+ super();
}
- // protected isApplicable(dso: Community | Collection): boolean {
- // // @ts-ignore
- // return dso?.type === COMMUNITY.value || dso?.type === COLLECTION.value;
- // }
-
- public getSectionsForContext(dso: Community | Collection): Observable {
+ public getSectionsForContext(dso: DSpaceObject): Observable {
return combineLatest([
this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self),
]).pipe(
diff --git a/src/app/shared/menu/providers/community-list.menu.ts b/src/app/shared/menu/providers/community-list.menu.ts
index 5637db8ff7..028d5618af 100644
--- a/src/app/shared/menu/providers/community-list.menu.ts
+++ b/src/app/shared/menu/providers/community-list.menu.ts
@@ -7,15 +7,9 @@
*/
import { Injectable } from '@angular/core';
-import {
- Observable,
- of,
-} from 'rxjs';
+import { Observable, of, } from 'rxjs';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
@Injectable()
export class CommunityListMenuProvider extends AbstractMenuProvider {
diff --git a/src/app/shared/menu/providers/curation.menu.ts b/src/app/shared/menu/providers/curation.menu.ts
index 16b4501048..1c35e3fcd8 100644
--- a/src/app/shared/menu/providers/curation.menu.ts
+++ b/src/app/shared/menu/providers/curation.menu.ts
@@ -7,19 +7,12 @@
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- map,
- Observable,
-} from 'rxjs';
+import { combineLatest, map, Observable, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { MenuItemType } from '../menu-item-type.model';
import { LinkMenuItemModel } from '../menu-item/models/link.model';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
@Injectable()
export class CurationMenuProvider extends AbstractMenuProvider {
diff --git a/src/app/shared/menu/providers/dso-edit.menu.ts b/src/app/shared/menu/providers/dso-edit.menu.ts
index 35eccf7e24..5d5a480a92 100644
--- a/src/app/shared/menu/providers/dso-edit.menu.ts
+++ b/src/app/shared/menu/providers/dso-edit.menu.ts
@@ -6,13 +6,9 @@
* http://www.dspace.org/license/
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
import { getDSORoute } from '../../../app-routing-paths';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
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';
@@ -20,15 +16,14 @@ import { URLCombiner } from '../../../core/url-combiner/url-combiner';
import { MenuItemType } from '../menu-item-type.model';
import { LinkMenuItemModel } from '../menu-item/models/link.model';
import { PartialMenuSection } from '../menu-provider';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
@Injectable()
-export class DSpaceObjectEditMenuProvider extends DSpaceObjectPageMenuProvider {
+export class DSpaceObjectEditMenuProvider extends DSpaceObjectPageMenuProvider {
constructor(
protected authorizationDataService: AuthorizationDataService,
- protected dsoDataService: DSpaceObjectDataService,
) {
- super(dsoDataService);
+ super();
}
public getSectionsForContext(dso: DSpaceObject): Observable {
diff --git a/src/app/shared/menu/providers/dso-option-menu.service.ts b/src/app/shared/menu/providers/dso-option.menu.ts
similarity index 51%
rename from src/app/shared/menu/providers/dso-option-menu.service.ts
rename to src/app/shared/menu/providers/dso-option.menu.ts
index 5cf657bca4..4c5ab9c625 100644
--- a/src/app/shared/menu/providers/dso-option-menu.service.ts
+++ b/src/app/shared/menu/providers/dso-option.menu.ts
@@ -9,21 +9,29 @@
import { Injectable } from '@angular/core';
import { Observable, of, } from 'rxjs';
import { MenuItemType } from '../menu-item-type.model';
-import { AbstractExpandableParentMenuProvider } from './expandable-parent-menu-provider';
import { PartialMenuSection } from '../menu-provider';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
+import { DSpaceObject } from 'src/app/core/shared/dspace-object.model';
+import { hasValue } from '../../empty.util';
@Injectable()
-export class DsoOptionMenu extends AbstractExpandableParentMenuProvider {
+export class DsoOptionMenu extends DSpaceObjectPageMenuProvider {
- public getSections(): Observable {
+ alwaysRenderExpandable = true;
+
+ protected isApplicable(dso: DSpaceObject): boolean {
+ return hasValue(dso);
+ }
+
+ getSectionsForContext(dso: DSpaceObject): Observable {
return of([
{
visible: true,
model: {
type: MenuItemType.TEXT,
- text: `menu.section.browse_global_communities_and_collections`,
+ text: this.getDsoType(dso) + '.page.options',
},
- icon: 'diagram-project'
+ icon: 'ellipsis-vertical'
},
] as PartialMenuSection[]);
}
diff --git a/src/app/shared/menu/providers/dso.menu.ts b/src/app/shared/menu/providers/dso.menu.ts
deleted file mode 100644
index 0545b7cd6f..0000000000
--- a/src/app/shared/menu/providers/dso.menu.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
-import { DSpaceObject } from '../../../core/shared/dspace-object.model';
-import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
-import { AbstractRouteContextMenuProvider } from './route-context.menu';
-
-export abstract class DSpaceObjectPageMenuProvider extends AbstractRouteContextMenuProvider {
- allRoutes = false;
-
- protected constructor(
- protected dsoDataService: DSpaceObjectDataService,
- ) {
- super();
- }
-
-
- public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
- // todo: would be cool to automatically switch to cached version of specific DSO
- // ...but we can't really know which is which because the other resolver may run _after_
- // we could refactor the resolver to a function though; then it's less problematic to just call it here
- return this.dsoDataService.findById(route.params.id, true, false).pipe(
- getFirstCompletedRemoteData(),
- map((dsoRD) => {
- if (dsoRD.hasSucceeded) {
- return dsoRD.payload as T;
- } else {
- return undefined;
- }
- })
- );
- }
-
- /**
- * Retrieve the dso or entity type for an object to be used in generic messages
- */
- protected getDsoType(dso: T) {
- const renderType = dso.getRenderTypes()[0];
- if (typeof renderType === 'string' || renderType instanceof String) {
- return renderType.toLowerCase();
- } else {
- return dso.type.toString().toLowerCase();
- }
- }
-}
diff --git a/src/app/shared/menu/providers/edit.menu.ts b/src/app/shared/menu/providers/edit.menu.ts
index cc003aa259..d72b00ac15 100644
--- a/src/app/shared/menu/providers/edit.menu.ts
+++ b/src/app/shared/menu/providers/edit.menu.ts
@@ -8,23 +8,21 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import { ThemedEditCollectionSelectorComponent } from '../../dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component';
-import { ThemedEditCommunitySelectorComponent } from '../../dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component';
-import { ThemedEditItemSelectorComponent } from '../../dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component';
-import { MenuItemType } from '../menu-item-type.model';
import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+ ThemedEditCollectionSelectorComponent
+} from '../../dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component';
+import {
+ ThemedEditCommunitySelectorComponent
+} from '../../dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component';
+import {
+ ThemedEditItemSelectorComponent
+} from '../../dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component';
+import { MenuItemType } from '../menu-item-type.model';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class EditMenuProvider extends AbstractExpandableMenuProvider {
@@ -35,7 +33,7 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf(
{
model: {
@@ -43,11 +41,12 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.edit',
},
icon: 'pencil',
+ visible: true,
},
);
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return combineLatest([
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
@@ -85,7 +84,7 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
},
},
},
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/expandable-parent-menu-provider.ts b/src/app/shared/menu/providers/expandable-parent-menu-provider.ts
deleted file mode 100644
index 0ee2735d56..0000000000
--- a/src/app/shared/menu/providers/expandable-parent-menu-provider.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-import { combineLatest, Observable, of as observableOf, } from 'rxjs';
-import { map } from 'rxjs/operators';
-import {
- AbstractMenuProvider,
- MenuProvider,
- MenuProviderTypeWithPaths,
- MenuProviderTypeWithSubs,
-} from '../menu-provider';
-import { Inject, Injector, Optional, Type } from '@angular/core';
-import { AbstractExpandableMenuProvider, MenuSubSection } from './expandable-menu-provider';
-import { ActivatedRoute, ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
-import { isEmpty } from '../../empty.util';
-import { MENU_PROVIDER } from '../menu.structure';
-import { MenuService } from '../menu.service';
-
-
-export abstract class AbstractExpandableParentMenuProvider extends AbstractMenuProvider {
- isExpandable = true;
-
- public static withSubs(childProviders: (Type| MenuProviderTypeWithPaths)[]) {
- if (!AbstractMenuProvider.isPrototypeOf(this)) {
- throw new Error(
- 'onRoute should only be called from concrete subclasses of AbstractMenuProvider'
- );
- }
-
- const providerType = this as unknown as Type;
- return {providerType: providerType, childProviderTypes: childProviders};
- }
-}
diff --git a/src/app/shared/menu/providers/export.menu.ts b/src/app/shared/menu/providers/export.menu.ts
index 50f6667b38..77f7504a8e 100644
--- a/src/app/shared/menu/providers/export.menu.ts
+++ b/src/app/shared/menu/providers/export.menu.ts
@@ -8,26 +8,19 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest as observableCombineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
+import { METADATA_EXPORT_SCRIPT_NAME, ScriptDataService, } from '../../../core/data/processes/script-data.service';
import {
- METADATA_EXPORT_SCRIPT_NAME,
- ScriptDataService,
-} from '../../../core/data/processes/script-data.service';
-import { ExportBatchSelectorComponent } from '../../dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component';
-import { ExportMetadataSelectorComponent } from '../../dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component';
+ ExportBatchSelectorComponent
+} from '../../dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component';
+import {
+ ExportMetadataSelectorComponent
+} from '../../dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class ExportMenuProvider extends AbstractExpandableMenuProvider {
@@ -39,7 +32,7 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf(
{
model: {
@@ -47,12 +40,12 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.export',
},
icon: 'file-export',
- shouldPersistOnRouteChange: true,
+ visible: true,
},
);
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return observableCombineLatest([
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME),
@@ -68,7 +61,6 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
this.modalService.open(ExportMetadataSelectorComponent);
},
},
- shouldPersistOnRouteChange: true,
},
{
visible: authorized && metadataExportScriptExists,
@@ -79,9 +71,8 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
this.modalService.open(ExportBatchSelectorComponent);
},
},
- shouldPersistOnRouteChange: true,
},
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/health.menu.ts b/src/app/shared/menu/providers/health.menu.ts
index b3db57b3ac..bc7eef597e 100644
--- a/src/app/shared/menu/providers/health.menu.ts
+++ b/src/app/shared/menu/providers/health.menu.ts
@@ -7,18 +7,11 @@
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- map,
- Observable,
-} from 'rxjs';
+import { combineLatest, map, Observable, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
@Injectable()
export class HealthMenuProvider extends AbstractMenuProvider {
diff --git a/src/app/shared/menu/providers/helper-providers/dso.menu.ts b/src/app/shared/menu/providers/helper-providers/dso.menu.ts
new file mode 100644
index 0000000000..f88e452aff
--- /dev/null
+++ b/src/app/shared/menu/providers/helper-providers/dso.menu.ts
@@ -0,0 +1,37 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
+import { AbstractRouteContextMenuProvider } from './route-context.menu';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { hasValue } from '../../../empty.util';
+
+export abstract class DSpaceObjectPageMenuProvider extends AbstractRouteContextMenuProvider {
+
+ public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
+ const dsoRD: RemoteData = route.data.dso;
+ if (hasValue(dsoRD) && dsoRD.hasSucceeded && hasValue(dsoRD.payload)) {
+ return of(dsoRD.payload);
+ } else {
+ return of(undefined);
+ }
+ }
+
+ /**
+ * Retrieve the dso or entity type for an object to be used in generic messages
+ */
+ protected getDsoType(dso: DSpaceObject) {
+ const renderType = dso.getRenderTypes()[0];
+ if (typeof renderType === 'string' || renderType instanceof String) {
+ return renderType.toLowerCase();
+ } else {
+ return dso.type.toString().toLowerCase();
+ }
+ }
+}
diff --git a/src/app/shared/menu/providers/expandable-menu-provider.ts b/src/app/shared/menu/providers/helper-providers/expandable-menu-provider.ts
similarity index 59%
rename from src/app/shared/menu/providers/expandable-menu-provider.ts
rename to src/app/shared/menu/providers/helper-providers/expandable-menu-provider.ts
index 4671a1c1c5..276b892e6e 100644
--- a/src/app/shared/menu/providers/expandable-menu-provider.ts
+++ b/src/app/shared/menu/providers/helper-providers/expandable-menu-provider.ts
@@ -5,29 +5,18 @@
*
* http://www.dspace.org/license/
*/
-import { Omit } from '@material-ui/core';
-import {
- combineLatest,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest, Observable, of as observableOf, } from 'rxjs';
import { map } from 'rxjs/operators';
-import { v4 as uuidv4 } from 'uuid';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
-import { Type } from '@angular/core';
-
-export type MenuTopSection = Omit;
-export type MenuSubSection = Omit;
+import { AbstractMenuProvider, PartialMenuSection, } from '../../menu-provider';
export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvider {
- protected showWithoutSubsections = false;
- abstract getTopSection(): Observable;
+ alwaysRenderExpandable = true;
- abstract getSubSections(): Observable;
+
+ abstract getTopSection(): Observable;
+
+ abstract getSubSections(): Observable;
protected includeSubSections(): boolean {
return true;
@@ -41,7 +30,7 @@ export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvide
full ? this.getSubSections() : observableOf([]),
]).pipe(
map((
- [partialTopSection, partialSubSections]: [MenuTopSection, MenuSubSection[]]
+ [partialTopSection, partialSubSections]: [PartialMenuSection, PartialMenuSection[]]
) => {
const subSections = partialSubSections.map((partialSub, index) => {
return {
@@ -56,7 +45,6 @@ export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvide
{
...partialTopSection,
id: this.menuProviderId,
- visible: full ? subSections.some(sub => sub.visible) : this.showWithoutSubsections,
},
];
})
diff --git a/src/app/shared/menu/providers/route-context.menu.ts b/src/app/shared/menu/providers/helper-providers/route-context.menu.ts
similarity index 75%
rename from src/app/shared/menu/providers/route-context.menu.ts
rename to src/app/shared/menu/providers/helper-providers/route-context.menu.ts
index 03e9c219f5..2ffc97ac5e 100644
--- a/src/app/shared/menu/providers/route-context.menu.ts
+++ b/src/app/shared/menu/providers/helper-providers/route-context.menu.ts
@@ -5,23 +5,14 @@
*
* http://www.dspace.org/license/
*/
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import {
- Observable,
- of as observableOf,
-} from 'rxjs';
-import { switchMap, tap } from 'rxjs/operators';
-import { hasValue } from '../../empty.util';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
+import { Observable, of as observableOf, } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+import { AbstractMenuProvider, PartialMenuSection, } from '../../menu-provider';
export abstract class AbstractRouteContextMenuProvider extends AbstractMenuProvider {
shouldPersistOnRouteChange = false;
+
abstract getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable;
abstract getSectionsForContext(routeContext: T): Observable;
@@ -29,10 +20,8 @@ export abstract class AbstractRouteContextMenuProvider extends AbstractMenuPr
getSections(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
return this.getRouteContext(route, state).pipe(
-
switchMap((routeContext: T) => {
if (this.isApplicable(routeContext)) {
-
return this.getSectionsForContext(routeContext);
} else {
return observableOf([]);
diff --git a/src/app/shared/menu/providers/import.menu.ts b/src/app/shared/menu/providers/import.menu.ts
index 5b1cfc0d0e..3e0cf3228e 100644
--- a/src/app/shared/menu/providers/import.menu.ts
+++ b/src/app/shared/menu/providers/import.menu.ts
@@ -8,24 +8,13 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest as observableCombineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import {
- METADATA_IMPORT_SCRIPT_NAME,
- ScriptDataService,
-} from '../../../core/data/processes/script-data.service';
+import { METADATA_IMPORT_SCRIPT_NAME, ScriptDataService, } from '../../../core/data/processes/script-data.service';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class ImportMenuProvider extends AbstractExpandableMenuProvider {
@@ -37,7 +26,7 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf(
{
model: {
@@ -45,12 +34,12 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.import',
},
icon: 'file-import',
- shouldPersistOnRouteChange: true,
+ visible: true,
},
);
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return observableCombineLatest([
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME),
@@ -73,7 +62,7 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
link: '/admin/batch-import',
},
},
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/item-claim.menu.ts b/src/app/shared/menu/providers/item-claim.menu.ts
index 4b1bf0ccfd..f2afb70ea7 100644
--- a/src/app/shared/menu/providers/item-claim.menu.ts
+++ b/src/app/shared/menu/providers/item-claim.menu.ts
@@ -8,12 +8,8 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { ResearcherProfileDataService } from '../../../core/profile/researcher-profile-data.service';
@@ -25,26 +21,28 @@ import { MenuItemType } from '../menu-item-type.model';
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
import { PartialMenuSection } from '../menu-provider';
import { MenuService } from '../menu.service';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
+import { DSpaceObject } from '../../../core/shared/dspace-object.model';
@Injectable()
-// todo: the "Item-ness" of this class is basically unenforced though...
-export class ClaimMenuProvider extends DSpaceObjectPageMenuProvider- {
+export class ClaimMenuProvider extends DSpaceObjectPageMenuProvider {
constructor(
protected authorizationService: AuthorizationDataService,
protected menuService: MenuService,
- protected dsoDataService: DSpaceObjectDataService,
protected translate: TranslateService,
protected notificationsService: NotificationsService,
protected researcherProfileService: ResearcherProfileDataService,
protected modalService: NgbModal,
) {
- super(dsoDataService);
+ super();
}
- protected isApplicable(item: Item): boolean {
- return this.getDsoType(item) === 'person';
+ protected isApplicable(item: DSpaceObject): boolean {
+ if (item instanceof Item) {
+ return this.getDsoType(item) === 'person';
+ }
+ return false;
}
public getSectionsForContext(item: Item): Observable {
diff --git a/src/app/shared/menu/providers/item-orcid.menu.ts b/src/app/shared/menu/providers/item-orcid.menu.ts
index b1a9c6d9e7..1416b54a34 100644
--- a/src/app/shared/menu/providers/item-orcid.menu.ts
+++ b/src/app/shared/menu/providers/item-orcid.menu.ts
@@ -6,13 +6,9 @@
* http://www.dspace.org/license/
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
import { getDSORoute } from '../../../app-routing-paths';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { Item } from '../../../core/shared/item.model';
@@ -20,19 +16,21 @@ import { URLCombiner } from '../../../core/url-combiner/url-combiner';
import { MenuItemType } from '../menu-item-type.model';
import { LinkMenuItemModel } from '../menu-item/models/link.model';
import { PartialMenuSection } from '../menu-provider';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
@Injectable()
-export class OrcidMenuProvider extends DSpaceObjectPageMenuProvider
- {
+export class OrcidMenuProvider extends DSpaceObjectPageMenuProvider {
constructor(
protected authorizationService: AuthorizationDataService,
- protected dsoDataService: DSpaceObjectDataService,
) {
- super(dsoDataService);
+ super();
}
protected isApplicable(item: Item): boolean {
- return this.getDsoType(item) === 'person';
+ if (item instanceof Item) {
+ return this.getDsoType(item) === 'person';
+ }
+ return false;
}
public getSectionsForContext(item: Item): Observable {
diff --git a/src/app/shared/menu/providers/item-versioning.menu.ts b/src/app/shared/menu/providers/item-versioning.menu.ts
index 60766f5cbf..15349a7016 100644
--- a/src/app/shared/menu/providers/item-versioning.menu.ts
+++ b/src/app/shared/menu/providers/item-versioning.menu.ts
@@ -6,12 +6,8 @@
* http://www.dspace.org/license/
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- Observable,
-} from 'rxjs';
+import { combineLatest, Observable, } from 'rxjs';
import { map } from 'rxjs/operators';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { Item } from '../../../core/shared/item.model';
@@ -19,16 +15,15 @@ import { DsoVersioningModalService } from '../../dso-page/dso-versioning-modal-s
import { MenuItemType } from '../menu-item-type.model';
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
import { PartialMenuSection } from '../menu-provider';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
+import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
@Injectable()
-export class VersioningMenuProvider extends DSpaceObjectPageMenuProvider
- {
+export class VersioningMenuProvider extends DSpaceObjectPageMenuProvider {
constructor(
protected authorizationService: AuthorizationDataService,
protected dsoVersioningModalService: DsoVersioningModalService,
- protected dsoDataService: DSpaceObjectDataService,
) {
- super(dsoDataService);
+ super();
}
public getSectionsForContext(item: Item): Observable {
diff --git a/src/app/shared/menu/providers/item.menu.ts b/src/app/shared/menu/providers/item.menu.ts
deleted file mode 100644
index 5f889077af..0000000000
--- a/src/app/shared/menu/providers/item.menu.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-import { Optional } from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import {
- Observable,
- of,
-} from 'rxjs';
-import { map } from 'rxjs/operators';
-import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
-import { RemoteData } from '../../../core/data/remote-data';
-import { Item } from '../../../core/shared/item.model';
-import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
-import { ItemPageResolver } from '../../../item-page/item-page.resolver';
-import { DSpaceObjectPageMenuProvider } from './dso.menu';
-
-export abstract class ItemPageMenuProvider extends DSpaceObjectPageMenuProvider
- {
- allRoutes = false;
-
- protected constructor(
- protected dsoDataService: DSpaceObjectDataService,
- @Optional() protected resolver?: ItemPageResolver,
- ) {
- super(dsoDataService);
- }
-
- public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable
- {
- if (this.resolver === null) {
- return of(undefined);
- }
-
- // todo: it should be better to reuse the exact resolver that the page uses already, since the RD is guaranteed to be cached already
- return (this.resolver.resolve(route, state) as Observable>).pipe(
- getFirstCompletedRemoteData(),
- map((dsoRD) => {
- if (dsoRD.hasSucceeded) {
- return dsoRD.payload;
- } else {
- return undefined;
- }
- })
- );
- }
-}
diff --git a/src/app/shared/menu/providers/new.menu.ts b/src/app/shared/menu/providers/new.menu.ts
index e77f5535f9..07c54fa9cb 100644
--- a/src/app/shared/menu/providers/new.menu.ts
+++ b/src/app/shared/menu/providers/new.menu.ts
@@ -8,24 +8,22 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import { ThemedCreateCollectionParentSelectorComponent } from '../../dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component';
-import { ThemedCreateCommunityParentSelectorComponent } from '../../dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component';
-import { ThemedCreateItemParentSelectorComponent } from '../../dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component';
+import {
+ ThemedCreateCollectionParentSelectorComponent
+} from '../../dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component';
+import {
+ ThemedCreateCommunityParentSelectorComponent
+} from '../../dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component';
+import {
+ ThemedCreateItemParentSelectorComponent
+} from '../../dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component';
import { MenuItemType } from '../menu-item-type.model';
import { TextMenuItemModel } from '../menu-item/models/text.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class NewMenuProvider extends AbstractExpandableMenuProvider {
@@ -36,7 +34,7 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf(
{
model: {
@@ -44,11 +42,12 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.new'
} as TextMenuItemModel,
icon: 'plus',
+ visible: true,
},
);
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return combineLatest([
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
@@ -95,7 +94,7 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
link: '/processes/new'
},
},
- ] as MenuSubSection[];
+ ];
}));
}
}
diff --git a/src/app/shared/menu/providers/notifications.menu.ts b/src/app/shared/menu/providers/notifications.menu.ts
deleted file mode 100644
index 7c189b8018..0000000000
--- a/src/app/shared/menu/providers/notifications.menu.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-
-import { Injectable } from '@angular/core';
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
-import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
-import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
-import { ScriptDataService } from '../../../core/data/processes/script-data.service';
-import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
-
-@Injectable()
-export class NotificationsMenuProvider extends AbstractExpandableMenuProvider {
- constructor(
- protected authorizationService: AuthorizationDataService,
- protected scriptDataService: ScriptDataService,
- protected modalService: NgbModal,
- ) {
- super();
- }
-
- public getTopSection(): Observable {
- return observableOf(
- {
- model: {
- type: MenuItemType.TEXT,
- text: 'menu.section.notifications',
- },
- icon: 'bell',
- },
- );
- }
-
- public getSubSections(): Observable {
- return combineLatest([
- this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
- this.authorizationService.isAuthorized(FeatureID.CanSeeQA),
- ]).pipe(
- map(([authorized, canSeeQA]) => {
- return [
- {
- visible: authorized && canSeeQA,
- model: {
- type: MenuItemType.LINK,
- text: 'menu.section.quality-assurance',
- link: '/admin/notifications/quality-assurance',
- },
- },
- ] as MenuSubSection[];
- }),
- );
- }
-}
diff --git a/src/app/shared/menu/providers/processes.menu.ts b/src/app/shared/menu/providers/processes.menu.ts
index 244c1b4f8e..6943572beb 100644
--- a/src/app/shared/menu/providers/processes.menu.ts
+++ b/src/app/shared/menu/providers/processes.menu.ts
@@ -7,18 +7,11 @@
*/
import { Injectable } from '@angular/core';
-import {
- combineLatest,
- map,
- Observable,
-} from 'rxjs';
+import { combineLatest, map, Observable, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractMenuProvider,
- PartialMenuSection,
-} from '../menu-provider';
+import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
@Injectable()
export class ProcessesMenuProvider extends AbstractMenuProvider {
diff --git a/src/app/shared/menu/providers/registries.menu.ts b/src/app/shared/menu/providers/registries.menu.ts
index d2e7e2835d..d69aa79d0e 100644
--- a/src/app/shared/menu/providers/registries.menu.ts
+++ b/src/app/shared/menu/providers/registries.menu.ts
@@ -8,21 +8,13 @@
import { Injectable } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import {
- combineLatest,
- map,
- Observable,
- of as observableOf,
-} from 'rxjs';
+import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
import { MenuItemType } from '../menu-item-type.model';
-import {
- AbstractExpandableMenuProvider,
- MenuSubSection,
- MenuTopSection,
-} from './expandable-menu-provider';
+import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
+import { PartialMenuSection } from '../menu-provider';
@Injectable()
export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
@@ -34,7 +26,7 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
super();
}
- public getTopSection(): Observable {
+ public getTopSection(): Observable {
return observableOf(
{
model: {
@@ -42,11 +34,12 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
text: 'menu.section.registries',
},
icon: 'list',
+ visible: true,
},
);
}
- public getSubSections(): Observable {
+ public getSubSections(): Observable {
return combineLatest([
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
]).pipe(
@@ -68,7 +61,7 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
link: 'admin/registries/bitstream-formats',
},
},
- ] as MenuSubSection[];
+ ];
}),
);
}
diff --git a/src/app/shared/menu/providers/statistics.menu.ts b/src/app/shared/menu/providers/statistics.menu.ts
index c3705fb77b..2d29cc575c 100644
--- a/src/app/shared/menu/providers/statistics.menu.ts
+++ b/src/app/shared/menu/providers/statistics.menu.ts
@@ -7,29 +7,15 @@
*/
import { Injectable } from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- RouterStateSnapshot,
-} from '@angular/router';
-import {
- Observable,
- of,
-} from 'rxjs';
+import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
+import { Observable, of, } from 'rxjs';
import { hasNoValue, hasValue } from '../../empty.util';
import { MenuItemType } from '../menu-item-type.model';
import { PartialMenuSection } from '../menu-provider';
-import { AbstractRouteContextMenuProvider } from './route-context.menu';
+import { AbstractRouteContextMenuProvider } from './helper-providers/route-context.menu';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { RemoteData } from '../../../core/data/remote-data';
-import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
import { getDSORoute } from '../../../app-routing-paths';
-import { Community } from '../../../core/shared/community.model';
-import { getCommunityPageRoute } from '../../../community-page/community-page-routing-paths';
-import { Collection } from '../../../core/shared/collection.model';
-import { getCollectionPageRoute } from '../../../collection-page/collection-page-routing-paths';
-import { Item } from '../../../core/shared/item.model';
-import { getItemModuleRoute, getItemPageRoute } from '../../../item-page/item-page-routing-paths';
-import { URLCombiner } from '../../../core/url-combiner/url-combiner';
interface StatisticsLink {
id: string,
@@ -40,9 +26,9 @@ interface StatisticsLink {
export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider {
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
-
- let dsoRD: RemoteData = route.data.dso
- while (hasValue(route.parent) && hasNoValue(dsoRD) ) {
+ let dsoRD: RemoteData = route.data.dso;
+ // Check if one of the parent routes has a DSO
+ while (hasValue(route.parent) && hasNoValue(dsoRD)) {
route = route.parent;
dsoRD = route.data.dso;
}
@@ -52,32 +38,6 @@ export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider {
@@ -86,29 +46,12 @@ export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider