mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
Continue the menu refactor and cleanup
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
[ngClass]="{ disabled: isDisabled }"
|
[ngClass]="{ disabled: isDisabled }"
|
||||||
[attr.aria-disabled]="isDisabled"
|
[attr.aria-disabled]="isDisabled"
|
||||||
[attr.aria-labelledby]="'sidebarName-' + section.id"
|
[attr.aria-labelledby]="'sidebarName-' + section.id"
|
||||||
[title]="('menu.section.icon.' + section.id) | translate"
|
[title]="itemModel.text | translate"
|
||||||
[routerLink]="itemModel.link"
|
[routerLink]="itemModel.link"
|
||||||
(keyup.space)="navigate($event)"
|
(keyup.space)="navigate($event)"
|
||||||
(keyup.enter)="navigate($event)"
|
(keyup.enter)="navigate($event)"
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
role="button" tabindex="0"
|
role="button" tabindex="0"
|
||||||
[attr.aria-labelledby]="'sidebarName-' + section.id"
|
[attr.aria-labelledby]="'sidebarName-' + section.id"
|
||||||
[attr.aria-expanded]="expanded | async"
|
[attr.aria-expanded]="expanded | async"
|
||||||
[title]="('menu.section.icon.' + section.id) | translate"
|
[title]="itemModel.text | translate"
|
||||||
[class.disabled]="section.model?.disabled"
|
[class.disabled]="section.model?.disabled"
|
||||||
(click)="toggleSection($event)"
|
(click)="toggleSection($event)"
|
||||||
(keyup.space)="toggleSection($event)"
|
(keyup.space)="toggleSection($event)"
|
||||||
|
@@ -32,12 +32,10 @@ import { ReloadGuard } from './core/reload/reload.guard';
|
|||||||
import { ServerCheckGuard } from './core/server-check/server-check.guard';
|
import { ServerCheckGuard } from './core/server-check/server-check.guard';
|
||||||
import { ThemedForbiddenComponent } from './forbidden/themed-forbidden.component';
|
import { ThemedForbiddenComponent } from './forbidden/themed-forbidden.component';
|
||||||
import { ENTITY_MODULE_PATH, ITEM_MODULE_PATH } from './item-page/item-page-routing-paths';
|
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 { ThemedPageErrorComponent } from './page-error/themed-page-error.component';
|
||||||
import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component';
|
import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component';
|
||||||
import { ThemedPageNotFoundComponent } from './pagenotfound/themed-pagenotfound.component';
|
import { ThemedPageNotFoundComponent } from './pagenotfound/themed-pagenotfound.component';
|
||||||
import { PROCESS_MODULE_PATH } from './process-page/process-page-routing.paths';
|
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';
|
// import { resolveStaticMenus } from './shared/menu/menu.resolver';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -30,8 +30,7 @@ import { WorkflowMenuProvider } from './shared/menu/providers/workflow.menu';
|
|||||||
import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-paths';
|
import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-paths';
|
||||||
import { COLLECTION_MODULE_PATH } from './collection-page/collection-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 { 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';
|
||||||
import { DsoOptionMenu } from './shared/menu/providers/dso-option-menu.service';
|
|
||||||
|
|
||||||
export const MENUS = buildMenuStructure({
|
export const MENUS = buildMenuStructure({
|
||||||
[MenuID.PUBLIC]: [
|
[MenuID.PUBLIC]: [
|
||||||
@@ -55,12 +54,11 @@ export const MENUS = buildMenuStructure({
|
|||||||
],
|
],
|
||||||
[MenuID.DSO_EDIT]: [
|
[MenuID.DSO_EDIT]: [
|
||||||
DsoOptionMenu.withSubs([
|
DsoOptionMenu.withSubs([
|
||||||
|
SubscribeMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH),
|
||||||
DSpaceObjectEditMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH, ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
DSpaceObjectEditMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH, ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
||||||
VersioningMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
VersioningMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
||||||
OrcidMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
OrcidMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
||||||
ClaimMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH),
|
ClaimMenuProvider.onRoute(ITEM_MODULE_PATH, ENTITY_MODULE_PATH, COLLECTION_MODULE_PATH),
|
||||||
// SubscribeMenuProvider,
|
|
||||||
]),
|
]),
|
||||||
SubscribeMenuProvider.onRoute(COMMUNITY_MODULE_PATH, COLLECTION_MODULE_PATH),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@@ -5,9 +5,6 @@ import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-bre
|
|||||||
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
||||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
import { LinkService } from '../core/cache/builders/link.service';
|
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 { CollectionPageAdministratorGuard } from './collection-page-administrator.guard';
|
||||||
import {
|
import {
|
||||||
COLLECTION_CREATE_PATH,
|
COLLECTION_CREATE_PATH,
|
||||||
|
@@ -21,11 +21,10 @@ import { MetadataService } from './core/metadata/metadata.service';
|
|||||||
import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service';
|
import { BreadcrumbsService } from './breadcrumbs/breadcrumbs.service';
|
||||||
import { ThemeService } from './shared/theme-support/theme.service';
|
import { ThemeService } from './shared/theme-support/theme.service';
|
||||||
import { isAuthenticationBlocking } from './core/auth/selectors';
|
import { isAuthenticationBlocking } from './core/auth/selectors';
|
||||||
import { distinctUntilChanged, find, switchMap } from 'rxjs/operators';
|
import { distinctUntilChanged, find } from 'rxjs/operators';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { MenuService } from './shared/menu/menu.service';
|
import { MenuService } from './shared/menu/menu.service';
|
||||||
import { MenuProviderService } from './shared/menu/menu-provider.service';
|
import { MenuProviderService } from './shared/menu/menu-provider.service';
|
||||||
import { MenuID } from './shared/menu/menu-id.model';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the initialization of the app.
|
* Performs the initialization of the app.
|
||||||
@@ -190,18 +189,9 @@ export abstract class InitService {
|
|||||||
this.metadata.listenForRouteChange();
|
this.metadata.listenForRouteChange();
|
||||||
this.breadcrumbsService.listenForRouteChanges();
|
this.breadcrumbsService.listenForRouteChanges();
|
||||||
this.themeService.listenForRouteChanges();
|
this.themeService.listenForRouteChanges();
|
||||||
// this.menuService.listenForRouteChanges();
|
|
||||||
this.menuProviderService.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)
|
* Emits once authentication is ready (no longer blocking)
|
||||||
* @protected
|
* @protected
|
||||||
|
@@ -5,20 +5,13 @@ import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
|||||||
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
|
||||||
import { ItemBreadcrumbResolver } from '../core/breadcrumbs/item-breadcrumb.resolver';
|
import { ItemBreadcrumbResolver } from '../core/breadcrumbs/item-breadcrumb.resolver';
|
||||||
import { LinkService } from '../core/cache/builders/link.service';
|
import { LinkService } from '../core/cache/builders/link.service';
|
||||||
import { DSpaceObjectEditMenuProvider } from '../shared/menu/providers/dso-edit.menu';
|
import {
|
||||||
import { ClaimMenuProvider } from '../shared/menu/providers/item-claim.menu';
|
BitstreamRequestACopyPageComponent
|
||||||
import { OrcidMenuProvider } from '../shared/menu/providers/item-orcid.menu';
|
} from './bitstreams/request-a-copy/bitstream-request-a-copy-page.component';
|
||||||
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 { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
|
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
|
||||||
import { ThemedFullItemPageComponent } from './full/themed-full-item-page.component';
|
import { ThemedFullItemPageComponent } from './full/themed-full-item-page.component';
|
||||||
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
|
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
|
||||||
import {
|
import { ITEM_EDIT_PATH, ORCID_PATH, UPLOAD_BITSTREAM_PATH, } from './item-page-routing-paths';
|
||||||
ITEM_EDIT_PATH,
|
|
||||||
ORCID_PATH,
|
|
||||||
UPLOAD_BITSTREAM_PATH,
|
|
||||||
} from './item-page-routing-paths';
|
|
||||||
import { ItemPageResolver } from './item-page.resolver';
|
import { ItemPageResolver } from './item-page.resolver';
|
||||||
import { OrcidPageComponent } from './orcid-page/orcid-page.component';
|
import { OrcidPageComponent } from './orcid-page/orcid-page.component';
|
||||||
import { OrcidPageGuard } from './orcid-page/orcid-page.guard';
|
import { OrcidPageGuard } from './orcid-page/orcid-page.guard';
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div *ngIf="hasSubSections$ | async">
|
<ng-container *ngIf="hasSubSections$ | async">
|
||||||
<div class="nav-item dropdown expandable-navbar-section text-md-center"
|
<div class="nav-item dropdown expandable-navbar-section text-md-center"
|
||||||
*ngVar="(active | async) as isActive"
|
*ngVar="(active | async) as isActive"
|
||||||
(keyup.enter)="isActive ? deactivateSection($event) : activateSection($event)"
|
(keyup.enter)="isActive ? deactivateSection($event) : activateSection($event)"
|
||||||
@@ -21,4 +21,4 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ng-container>
|
||||||
|
@@ -65,6 +65,6 @@ export class DsoEditMenuExpandableSectionComponent extends AbstractMenuSectionCo
|
|||||||
this.hasSubSections$ = this.subSections$.pipe(
|
this.hasSubSections$ = this.subSections$.pipe(
|
||||||
map((subSections) => isNotEmpty(subSections))
|
map((subSections) => isNotEmpty(subSections))
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -127,17 +127,17 @@ describe('DsoEditMenuSectionComponent', () => {
|
|||||||
stopPropagation: jasmine.createSpy('stopPropagation'),
|
stopPropagation: jasmine.createSpy('stopPropagation'),
|
||||||
});
|
});
|
||||||
it('should call the item model function when not disabled', () => {
|
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);
|
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', () => {
|
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.itemModel.disabled = true;
|
||||||
component.activate(mockEvent);
|
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;
|
component.itemModel.disabled = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -16,6 +16,7 @@ import { getMockThemeService } from '../../mocks/theme-service.mock';
|
|||||||
|
|
||||||
|
|
||||||
import { DsoPageModule } from '../dso-page.module';
|
import { DsoPageModule } from '../dso-page.module';
|
||||||
|
import { TextMenuItemModel } from '../../menu/menu-item/models/text.model';
|
||||||
|
|
||||||
describe('DsoEditMenuComponent', () => {
|
describe('DsoEditMenuComponent', () => {
|
||||||
let comp: DsoEditMenuComponent;
|
let comp: DsoEditMenuComponent;
|
||||||
@@ -32,9 +33,10 @@ describe('DsoEditMenuComponent', () => {
|
|||||||
active: false,
|
active: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
model: {
|
model: {
|
||||||
|
text: 'section-text',
|
||||||
type: null,
|
type: null,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
} as MenuItemModel,
|
} as TextMenuItemModel,
|
||||||
icon: 'pencil-alt',
|
icon: 'pencil-alt',
|
||||||
index: 1
|
index: 1
|
||||||
};
|
};
|
||||||
|
@@ -66,12 +66,8 @@ export class MenuProviderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public resolvePersistentMenus(
|
public initPersistentMenus() {
|
||||||
// route: ActivatedRouteSnapshot,
|
combineLatest([
|
||||||
// state: RouterStateSnapshot
|
|
||||||
): Observable<boolean> {
|
|
||||||
|
|
||||||
return combineLatest([
|
|
||||||
...this.providers
|
...this.providers
|
||||||
.map((provider) => {
|
.map((provider) => {
|
||||||
return provider;
|
return provider;
|
||||||
@@ -98,63 +94,69 @@ export class MenuProviderService {
|
|||||||
return [waitForMenus];
|
return [waitForMenus];
|
||||||
}),
|
}),
|
||||||
map(done => done.every(Boolean)),
|
map(done => done.every(Boolean)),
|
||||||
);
|
).subscribe((done) => {
|
||||||
|
Object.values(MenuID).forEach((menuID) => {
|
||||||
|
this.menuService.buildRouteMenuSections(menuID);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolveRouteMenus(
|
public resolveRouteMenus(
|
||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot
|
state: RouterStateSnapshot
|
||||||
): Observable<boolean> {
|
): Observable<boolean> {
|
||||||
return combineLatest([
|
const currentNonPersistentMenuSections$ = combineLatest([
|
||||||
...Object.values(MenuID).map((menuID) => {
|
...Object.values(MenuID).map((menuID) => {
|
||||||
return this.menuService.getNonPersistentMenuSections(menuID).pipe(
|
return this.menuService.getNonPersistentMenuSections(menuID).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
map((sections) => {
|
map((sections) => {
|
||||||
return {menuId: menuID, sections: sections};
|
return {menuId: menuID, sections: sections};
|
||||||
}));
|
}));
|
||||||
})])
|
})]);
|
||||||
.pipe(
|
|
||||||
switchMap((menuSectionsPerMenu) => {
|
const routeDependentMenuSections$ = combineLatest([
|
||||||
this.removeNonPersistentSections(menuSectionsPerMenu);
|
...this.providers
|
||||||
return combineLatest([
|
.filter(provider => {
|
||||||
...this.providers
|
let shouldUpdate = false;
|
||||||
.filter(provider => {
|
if (!provider.shouldPersistOnRouteChange && isNotEmpty(provider.activePaths)) {
|
||||||
let shouldUpdate = false;
|
provider.activePaths.forEach((path) => {
|
||||||
if (!provider.shouldPersistOnRouteChange && isNotEmpty(provider.activePaths)) {
|
if (state.url.includes(path)) {
|
||||||
provider.activePaths.forEach((path) => {
|
shouldUpdate = true;
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
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];
|
return this.waitForMenu$(providerWithSection.provider.menuID);
|
||||||
}),
|
});
|
||||||
map(done => done.every(Boolean)),
|
return [waitForMenus];
|
||||||
);
|
}),
|
||||||
// }
|
map(done => done.every(Boolean)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSection(providerWithSection: {
|
private addSection(providerWithSection: {
|
||||||
@@ -167,7 +169,7 @@ export class MenuProviderService {
|
|||||||
parentID: section.parentID ?? providerWithSection.provider.parentID,
|
parentID: section.parentID ?? providerWithSection.provider.parentID,
|
||||||
index: section.index ?? providerWithSection.provider.index,
|
index: section.index ?? providerWithSection.provider.index,
|
||||||
shouldPersistOnRouteChange: section.shouldPersistOnRouteChange ?? providerWithSection.provider.shouldPersistOnRouteChange,
|
shouldPersistOnRouteChange: section.shouldPersistOnRouteChange ?? providerWithSection.provider.shouldPersistOnRouteChange,
|
||||||
isExpandable: section.isExpandable ?? providerWithSection.provider.isExpandable,
|
alwaysRenderExpandable: section.alwaysRenderExpandable ?? providerWithSection.provider.alwaysRenderExpandable,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,28 +5,15 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
|
/* eslint-disable max-classes-per-file */
|
||||||
import {
|
import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
|
||||||
ActivatedRouteSnapshot,
|
|
||||||
RouterStateSnapshot,
|
|
||||||
} from '@angular/router';
|
|
||||||
import { Omit } from '@material-ui/core';
|
|
||||||
import flatten from 'lodash/flatten';
|
import flatten from 'lodash/flatten';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { MenuID } from './menu-id.model';
|
import { MenuID } from './menu-id.model';
|
||||||
import { MenuItemModels, MenuSection } from './menu-section.model';
|
import { MenuItemModels } from './menu-section.model';
|
||||||
import { APP_INITIALIZER, Provider, Type } from '@angular/core';
|
import { 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';
|
|
||||||
|
|
||||||
// export type PartialMenuSection = Omit<MenuSection, 'id' | 'active'>;
|
|
||||||
export interface PartialMenuSection {
|
export interface PartialMenuSection {
|
||||||
id?: string;
|
id?: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -36,11 +23,10 @@ export interface PartialMenuSection {
|
|||||||
active?: boolean;
|
active?: boolean;
|
||||||
shouldPersistOnRouteChange?: boolean;
|
shouldPersistOnRouteChange?: boolean;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
isExpandable?: boolean;
|
alwaysRenderExpandable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface MenuProvider {
|
export interface MenuProvider {
|
||||||
shouldPersistOnRouteChange?: boolean,
|
shouldPersistOnRouteChange?: boolean,
|
||||||
menuID?: MenuID;
|
menuID?: MenuID;
|
||||||
@@ -49,35 +35,37 @@ export interface MenuProvider {
|
|||||||
getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable<PartialMenuSection[]>;
|
getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable<PartialMenuSection[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MenuProviderTypeWithPaths {
|
export class MenuProviderTypeWithOptions {
|
||||||
providerType: Type<MenuProvider>;
|
providerType: Type<MenuProvider>;
|
||||||
paths: string[];
|
paths?: string[];
|
||||||
}
|
childProviderTypes?: (Type<MenuProvider> | MenuProviderTypeWithOptions)[];
|
||||||
|
|
||||||
export class MenuProviderTypeWithSubs {
|
|
||||||
providerType: Type<MenuProvider>;
|
|
||||||
childProviderTypes: (Type<MenuProvider> | MenuProviderTypeWithPaths)[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class AbstractMenuProvider implements MenuProvider {
|
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;
|
menuID?: MenuID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the sections of this menu should be set on the
|
||||||
|
*/
|
||||||
|
shouldPersistOnRouteChange = true;
|
||||||
menuProviderId?: string;
|
menuProviderId?: string;
|
||||||
index?: number;
|
index?: number;
|
||||||
activePaths?: string[];
|
activePaths?: string[];
|
||||||
parentID?: 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<PartialMenuSection[]>;
|
public static onRoute(...paths: string[]): MenuProviderTypeWithOptions {
|
||||||
|
|
||||||
protected concat(...sections$: Observable<PartialMenuSection[]>[]): Observable<PartialMenuSection[]> {
|
|
||||||
return combineLatest(sections$).pipe(
|
|
||||||
map(sections => flatten(sections)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static onRoute(...paths: string[]) {
|
|
||||||
if (!AbstractMenuProvider.isPrototypeOf(this)) {
|
if (!AbstractMenuProvider.isPrototypeOf(this)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'onRoute should only be called from concrete subclasses of AbstractMenuProvider'
|
'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<AbstractMenuProvider>;
|
const providerType = this as unknown as Type<AbstractMenuProvider>;
|
||||||
return {providerType: providerType, paths: paths};
|
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<MenuProvider> | 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<AbstractMenuProvider>;
|
||||||
|
return {providerType: providerType, childProviderTypes: childProviders};
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getSections(route?: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Observable<PartialMenuSection[]>;
|
||||||
|
|
||||||
|
protected concat(...sections$: Observable<PartialMenuSection[]>[]): Observable<PartialMenuSection[]> {
|
||||||
|
return combineLatest(sections$).pipe(
|
||||||
|
map(sections => flatten(sections)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -80,5 +80,5 @@ export interface MenuSection {
|
|||||||
*/
|
*/
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
|
||||||
isExpandable?: boolean;
|
alwaysRenderExpandable?: boolean;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
|
@@ -15,6 +15,8 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/
|
|||||||
import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
|
import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
|
||||||
import { ThemeService } from '../theme-support/theme.service';
|
import { ThemeService } from '../theme-support/theme.service';
|
||||||
import { getMockThemeService } from '../mocks/theme-service.mock';
|
import { getMockThemeService } from '../mocks/theme-service.mock';
|
||||||
|
import { MenuItemType } from './menu-item-type.model';
|
||||||
|
import { TextMenuItemModel } from './menu-item/models/text.model';
|
||||||
|
|
||||||
describe('MenuComponent', () => {
|
describe('MenuComponent', () => {
|
||||||
let comp: MenuComponent;
|
let comp: MenuComponent;
|
||||||
@@ -22,6 +24,16 @@ describe('MenuComponent', () => {
|
|||||||
let menuService: MenuService;
|
let menuService: MenuService;
|
||||||
let router: any;
|
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 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' } };
|
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;
|
comp.menuID = mockMenuID;
|
||||||
menuService = (comp as any).menuService;
|
menuService = (comp as any).menuService;
|
||||||
router = TestBed.inject(Router);
|
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({}));
|
spyOn(comp as any, 'getSectionComponent').and.returnValue(observableOf({}));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
@@ -218,7 +218,7 @@ export class MenuComponent implements OnInit, OnDestroy {
|
|||||||
private getSectionComponent(section: MenuSection): Observable<GenericConstructor<AbstractMenuSectionComponent>> {
|
private getSectionComponent(section: MenuSection): Observable<GenericConstructor<AbstractMenuSectionComponent>> {
|
||||||
return this.menuService.hasSubSections(this.menuID, section.id).pipe(
|
return this.menuService.hasSubSections(this.menuID, section.id).pipe(
|
||||||
map((expandable: boolean) => {
|
map((expandable: boolean) => {
|
||||||
return getComponentForMenu(this.menuID, expandable || section.isExpandable, this.themeService.getThemeName());
|
return getComponentForMenu(this.menuID, expandable || section.alwaysRenderExpandable, this.themeService.getThemeName());
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@@ -5,17 +5,10 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* 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<boolean> {
|
// export function resolveStaticMenus(): (ActivatedRouteSnapshot, RouterStateSnapshot, ProviderMenuService) => Observable<boolean> {
|
||||||
// return (
|
// return (
|
||||||
|
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||||
import { AppState, keySelector } from '../../app.reducer';
|
import { AppState, keySelector } from '../../app.reducer';
|
||||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
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 {
|
import {
|
||||||
ActivateMenuSectionAction,
|
ActivateMenuSectionAction,
|
||||||
AddMenuSectionAction,
|
AddMenuSectionAction,
|
||||||
|
@@ -5,48 +5,22 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
import {
|
import { InjectionToken, Provider, Type, } from '@angular/core';
|
||||||
InjectionToken,
|
|
||||||
Provider,
|
|
||||||
Type,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { MenuID } from './menu-id.model';
|
import { MenuID } from './menu-id.model';
|
||||||
import { AbstractMenuProvider } from './menu-provider';
|
import { AbstractMenuProvider, MenuProviderTypeWithOptions } from './menu-provider';
|
||||||
import { MenuProviderService } from './menu-provider.service';
|
import { MenuProviderService } from './menu-provider.service';
|
||||||
import { hasValue, isNotEmpty } from '../empty.util';
|
import { hasValue, isNotEmpty } from '../empty.util';
|
||||||
|
|
||||||
export const MENU_PROVIDER = new InjectionToken<AbstractMenuProvider>('MENU_PROVIDER');
|
export const MENU_PROVIDER = new InjectionToken<AbstractMenuProvider>('MENU_PROVIDER');
|
||||||
|
|
||||||
type MenuStructure = {
|
type MenuStructure = {
|
||||||
[key in MenuID]: (Type<AbstractMenuProvider> | {providerType: Type<AbstractMenuProvider>, paths: string[]} | {providerType: Type<AbstractMenuProvider>, childProviderTypes: any[]})[];
|
[key in MenuID]: (Type<AbstractMenuProvider> | MenuProviderTypeWithOptions)[];
|
||||||
};
|
};
|
||||||
|
|
||||||
function resolveProvider(providerType: Type<AbstractMenuProvider> , menuID: string, index: number, paths?: string[], parentID?: string, childProviders? : Type<AbstractMenuProvider>[]) {
|
/**
|
||||||
return {
|
* Builds the menu structure by converting the provider types into resolved providers
|
||||||
provide: MENU_PROVIDER,
|
* @param structure - The app menus structure
|
||||||
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],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildMenuStructure(structure: MenuStructure): Provider[] {
|
export function buildMenuStructure(structure: MenuStructure): Provider[] {
|
||||||
const providers: Provider[] = [
|
const providers: Provider[] = [
|
||||||
MenuProviderService,
|
MenuProviderService,
|
||||||
@@ -54,44 +28,77 @@ export function buildMenuStructure(structure: MenuStructure): Provider[] {
|
|||||||
|
|
||||||
Object.entries(structure).forEach(([menuID, providerTypes]) => {
|
Object.entries(structure).forEach(([menuID, providerTypes]) => {
|
||||||
for (const [index, providerType] of providerTypes.entries()) {
|
for (const [index, providerType] of providerTypes.entries()) {
|
||||||
// todo: should complain if not injectable!
|
processProviderType(providers, menuID, providerType, index);
|
||||||
|
|
||||||
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<AbstractMenuProvider> );
|
|
||||||
providers.push(resolveProvider(providerType as Type<AbstractMenuProvider>, menuID, index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return providers;
|
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<AbstractMenuProvider> | 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<AbstractMenuProvider>, 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<AbstractMenuProvider>, 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);
|
||||||
|
}
|
||||||
|
@@ -8,24 +8,17 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest as observableCombineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
|
export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected scriptDataService: ScriptDataService,
|
protected scriptDataService: ScriptDataService,
|
||||||
@@ -34,17 +27,18 @@ export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf({
|
return observableOf({
|
||||||
model: {
|
model: {
|
||||||
type: MenuItemType.TEXT,
|
type: MenuItemType.TEXT,
|
||||||
text: 'menu.section.access_control',
|
text: 'menu.section.access_control',
|
||||||
},
|
},
|
||||||
icon: 'key'
|
icon: 'key',
|
||||||
|
visible: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return observableCombineLatest([
|
return observableCombineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
this.authorizationService.isAuthorized(FeatureID.CanManageGroups),
|
this.authorizationService.isAuthorized(FeatureID.CanManageGroups),
|
||||||
@@ -87,7 +81,7 @@ export class AccessControlMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
// link: ''
|
// link: ''
|
||||||
// } as LinkMenuItemModel,
|
// } as LinkMenuItemModel,
|
||||||
// },
|
// },
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -7,18 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminSearchMenuProvider extends AbstractMenuProvider {
|
export class AdminSearchMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -7,10 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { Observable, of as observableOf, } from 'rxjs';
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { BrowseService } from '../../../core/browse/browse.service';
|
import { BrowseService } from '../../../core/browse/browse.service';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
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 { getFirstSucceededRemoteData } from '../../../core/shared/operators';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import { TextMenuItemModel } from '../menu-item/models/text.model';
|
import { TextMenuItemModel } from '../menu-item/models/text.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
|
export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -33,7 +27,7 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
getTopSection(): Observable<MenuTopSection> {
|
getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -41,11 +35,12 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.browse_global',
|
text: 'menu.section.browse_global',
|
||||||
} as TextMenuItemModel,
|
} as TextMenuItemModel,
|
||||||
icon: 'globe',
|
icon: 'globe',
|
||||||
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSubSections(): Observable<MenuSubSection[]> {
|
getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return this.browseService.getBrowseDefinitions().pipe(
|
return this.browseService.getBrowseDefinitions().pipe(
|
||||||
getFirstSucceededRemoteData(),
|
getFirstSucceededRemoteData(),
|
||||||
map((rd: RemoteData<PaginatedList<BrowseDefinition>>) => {
|
map((rd: RemoteData<PaginatedList<BrowseDefinition>>) => {
|
||||||
@@ -60,7 +55,7 @@ export class BrowseMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -7,40 +7,27 @@
|
|||||||
*/
|
*/
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
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 { SubscriptionModalComponent } from '../../subscriptions/subscription-modal/subscription-modal.component';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
|
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
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()
|
@Injectable()
|
||||||
export class SubscribeMenuProvider extends DSpaceObjectPageMenuProvider<Community | Collection> {
|
export class SubscribeMenuProvider extends DSpaceObjectPageMenuProvider {
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected modalService: NgbModal,
|
protected modalService: NgbModal,
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
) {
|
) {
|
||||||
super(dsoDataService);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
// protected isApplicable(dso: Community | Collection): boolean {
|
public getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
||||||
// // @ts-ignore
|
|
||||||
// return dso?.type === COMMUNITY.value || dso?.type === COLLECTION.value;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public getSectionsForContext(dso: Community | Collection): Observable<PartialMenuSection[]> {
|
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self),
|
this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
|
@@ -7,15 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { Observable, of, } from 'rxjs';
|
||||||
Observable,
|
|
||||||
of,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommunityListMenuProvider extends AbstractMenuProvider {
|
export class CommunityListMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -7,19 +7,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CurationMenuProvider extends AbstractMenuProvider {
|
export class CurationMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -6,13 +6,9 @@
|
|||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { getDSORoute } from '../../../app-routing-paths';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
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 { MenuItemType } from '../menu-item-type.model';
|
||||||
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
import { DSpaceObjectPageMenuProvider } from './dso.menu';
|
import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DSpaceObjectEditMenuProvider extends DSpaceObjectPageMenuProvider<DSpaceObject> {
|
export class DSpaceObjectEditMenuProvider extends DSpaceObjectPageMenuProvider {
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationDataService: AuthorizationDataService,
|
protected authorizationDataService: AuthorizationDataService,
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
) {
|
) {
|
||||||
super(dsoDataService);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
public getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
||||||
|
@@ -9,21 +9,29 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, of, } from 'rxjs';
|
import { Observable, of, } from 'rxjs';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import { AbstractExpandableParentMenuProvider } from './expandable-parent-menu-provider';
|
|
||||||
import { PartialMenuSection } from '../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()
|
@Injectable()
|
||||||
export class DsoOptionMenu extends AbstractExpandableParentMenuProvider {
|
export class DsoOptionMenu extends DSpaceObjectPageMenuProvider {
|
||||||
|
|
||||||
public getSections(): Observable<PartialMenuSection[]> {
|
alwaysRenderExpandable = true;
|
||||||
|
|
||||||
|
protected isApplicable(dso: DSpaceObject): boolean {
|
||||||
|
return hasValue(dso);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
||||||
return of([
|
return of([
|
||||||
{
|
{
|
||||||
visible: true,
|
visible: true,
|
||||||
model: {
|
model: {
|
||||||
type: MenuItemType.TEXT,
|
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[]);
|
] as PartialMenuSection[]);
|
||||||
}
|
}
|
@@ -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<T extends DSpaceObject> extends AbstractRouteContextMenuProvider<T> {
|
|
||||||
allRoutes = false;
|
|
||||||
|
|
||||||
protected constructor(
|
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T | undefined> {
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,23 +8,21 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
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 {
|
import {
|
||||||
AbstractExpandableMenuProvider,
|
ThemedEditCollectionSelectorComponent
|
||||||
MenuSubSection,
|
} from '../../dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component';
|
||||||
MenuTopSection,
|
import {
|
||||||
} from './expandable-menu-provider';
|
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()
|
@Injectable()
|
||||||
export class EditMenuProvider extends AbstractExpandableMenuProvider {
|
export class EditMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -35,7 +33,7 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -43,11 +41,12 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.edit',
|
text: 'menu.section.edit',
|
||||||
},
|
},
|
||||||
icon: 'pencil',
|
icon: 'pencil',
|
||||||
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
|
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
|
||||||
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
|
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
|
||||||
@@ -85,7 +84,7 @@ export class EditMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -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<MenuProvider>| 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<AbstractMenuProvider>;
|
|
||||||
return {providerType: providerType, childProviderTypes: childProviders};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,26 +8,19 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest as observableCombineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
|
import { METADATA_EXPORT_SCRIPT_NAME, ScriptDataService, } from '../../../core/data/processes/script-data.service';
|
||||||
import {
|
import {
|
||||||
METADATA_EXPORT_SCRIPT_NAME,
|
ExportBatchSelectorComponent
|
||||||
ScriptDataService,
|
} from '../../dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component';
|
||||||
} from '../../../core/data/processes/script-data.service';
|
import {
|
||||||
import { ExportBatchSelectorComponent } from '../../dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component';
|
ExportMetadataSelectorComponent
|
||||||
import { ExportMetadataSelectorComponent } from '../../dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component';
|
} from '../../dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -39,7 +32,7 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -47,12 +40,12 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.export',
|
text: 'menu.section.export',
|
||||||
},
|
},
|
||||||
icon: 'file-export',
|
icon: 'file-export',
|
||||||
shouldPersistOnRouteChange: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return observableCombineLatest([
|
return observableCombineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME),
|
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME),
|
||||||
@@ -68,7 +61,6 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
this.modalService.open(ExportMetadataSelectorComponent);
|
this.modalService.open(ExportMetadataSelectorComponent);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shouldPersistOnRouteChange: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
visible: authorized && metadataExportScriptExists,
|
visible: authorized && metadataExportScriptExists,
|
||||||
@@ -79,9 +71,8 @@ export class ExportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
this.modalService.open(ExportBatchSelectorComponent);
|
this.modalService.open(ExportBatchSelectorComponent);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shouldPersistOnRouteChange: true,
|
|
||||||
},
|
},
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -7,18 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HealthMenuProvider extends AbstractMenuProvider {
|
export class HealthMenuProvider extends AbstractMenuProvider {
|
||||||
|
37
src/app/shared/menu/providers/helper-providers/dso.menu.ts
Normal file
37
src/app/shared/menu/providers/helper-providers/dso.menu.ts
Normal file
@@ -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<DSpaceObject> {
|
||||||
|
|
||||||
|
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<DSpaceObject | undefined> {
|
||||||
|
const dsoRD: RemoteData<DSpaceObject> = 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,29 +5,18 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* 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 { map } from 'rxjs/operators';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { AbstractMenuProvider, PartialMenuSection, } from '../../menu-provider';
|
||||||
import {
|
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
import { Type } from '@angular/core';
|
|
||||||
|
|
||||||
export type MenuTopSection = Omit<PartialMenuSection, 'visible'>;
|
|
||||||
export type MenuSubSection = Omit<PartialMenuSection, 'parentID'>;
|
|
||||||
|
|
||||||
export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvider {
|
export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvider {
|
||||||
protected showWithoutSubsections = false;
|
|
||||||
|
|
||||||
abstract getTopSection(): Observable<MenuTopSection>;
|
alwaysRenderExpandable = true;
|
||||||
|
|
||||||
abstract getSubSections(): Observable<MenuSubSection[]>;
|
|
||||||
|
abstract getTopSection(): Observable<PartialMenuSection>;
|
||||||
|
|
||||||
|
abstract getSubSections(): Observable<PartialMenuSection[]>;
|
||||||
|
|
||||||
protected includeSubSections(): boolean {
|
protected includeSubSections(): boolean {
|
||||||
return true;
|
return true;
|
||||||
@@ -41,7 +30,7 @@ export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvide
|
|||||||
full ? this.getSubSections() : observableOf([]),
|
full ? this.getSubSections() : observableOf([]),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map((
|
map((
|
||||||
[partialTopSection, partialSubSections]: [MenuTopSection, MenuSubSection[]]
|
[partialTopSection, partialSubSections]: [PartialMenuSection, PartialMenuSection[]]
|
||||||
) => {
|
) => {
|
||||||
const subSections = partialSubSections.map((partialSub, index) => {
|
const subSections = partialSubSections.map((partialSub, index) => {
|
||||||
return {
|
return {
|
||||||
@@ -56,7 +45,6 @@ export abstract class AbstractExpandableMenuProvider extends AbstractMenuProvide
|
|||||||
{
|
{
|
||||||
...partialTopSection,
|
...partialTopSection,
|
||||||
id: this.menuProviderId,
|
id: this.menuProviderId,
|
||||||
visible: full ? subSections.some(sub => sub.visible) : this.showWithoutSubsections,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
})
|
})
|
@@ -5,23 +5,14 @@
|
|||||||
*
|
*
|
||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
import {
|
import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
|
||||||
ActivatedRouteSnapshot,
|
import { Observable, of as observableOf, } from 'rxjs';
|
||||||
RouterStateSnapshot,
|
import { switchMap } from 'rxjs/operators';
|
||||||
} from '@angular/router';
|
import { AbstractMenuProvider, PartialMenuSection, } from '../../menu-provider';
|
||||||
import {
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { switchMap, tap } from 'rxjs/operators';
|
|
||||||
import { hasValue } from '../../empty.util';
|
|
||||||
import {
|
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
export abstract class AbstractRouteContextMenuProvider<T> extends AbstractMenuProvider {
|
export abstract class AbstractRouteContextMenuProvider<T> extends AbstractMenuProvider {
|
||||||
shouldPersistOnRouteChange = false;
|
shouldPersistOnRouteChange = false;
|
||||||
|
|
||||||
abstract getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T | undefined>;
|
abstract getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T | undefined>;
|
||||||
|
|
||||||
abstract getSectionsForContext(routeContext: T): Observable<PartialMenuSection[]>;
|
abstract getSectionsForContext(routeContext: T): Observable<PartialMenuSection[]>;
|
||||||
@@ -29,10 +20,8 @@ export abstract class AbstractRouteContextMenuProvider<T> extends AbstractMenuPr
|
|||||||
getSections(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<PartialMenuSection[]> {
|
getSections(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<PartialMenuSection[]> {
|
||||||
|
|
||||||
return this.getRouteContext(route, state).pipe(
|
return this.getRouteContext(route, state).pipe(
|
||||||
|
|
||||||
switchMap((routeContext: T) => {
|
switchMap((routeContext: T) => {
|
||||||
if (this.isApplicable(routeContext)) {
|
if (this.isApplicable(routeContext)) {
|
||||||
|
|
||||||
return this.getSectionsForContext(routeContext);
|
return this.getSectionsForContext(routeContext);
|
||||||
} else {
|
} else {
|
||||||
return observableOf([]);
|
return observableOf([]);
|
@@ -8,24 +8,13 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest as observableCombineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest as observableCombineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import {
|
import { METADATA_IMPORT_SCRIPT_NAME, ScriptDataService, } from '../../../core/data/processes/script-data.service';
|
||||||
METADATA_IMPORT_SCRIPT_NAME,
|
|
||||||
ScriptDataService,
|
|
||||||
} from '../../../core/data/processes/script-data.service';
|
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImportMenuProvider extends AbstractExpandableMenuProvider {
|
export class ImportMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -37,7 +26,7 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -45,12 +34,12 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.import',
|
text: 'menu.section.import',
|
||||||
},
|
},
|
||||||
icon: 'file-import',
|
icon: 'file-import',
|
||||||
shouldPersistOnRouteChange: true,
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return observableCombineLatest([
|
return observableCombineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME),
|
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME),
|
||||||
@@ -73,7 +62,7 @@ export class ImportMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
link: '/admin/batch-import',
|
link: '/admin/batch-import',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -8,12 +8,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { ResearcherProfileDataService } from '../../../core/profile/researcher-profile-data.service';
|
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 { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
import { MenuService } from '../menu.service';
|
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()
|
@Injectable()
|
||||||
// todo: the "Item-ness" of this class is basically unenforced though...
|
export class ClaimMenuProvider extends DSpaceObjectPageMenuProvider {
|
||||||
export class ClaimMenuProvider extends DSpaceObjectPageMenuProvider<Item> {
|
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected menuService: MenuService,
|
protected menuService: MenuService,
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected researcherProfileService: ResearcherProfileDataService,
|
protected researcherProfileService: ResearcherProfileDataService,
|
||||||
protected modalService: NgbModal,
|
protected modalService: NgbModal,
|
||||||
) {
|
) {
|
||||||
super(dsoDataService);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected isApplicable(item: Item): boolean {
|
protected isApplicable(item: DSpaceObject): boolean {
|
||||||
return this.getDsoType(item) === 'person';
|
if (item instanceof Item) {
|
||||||
|
return this.getDsoType(item) === 'person';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSectionsForContext(item: Item): Observable<PartialMenuSection[]> {
|
public getSectionsForContext(item: Item): Observable<PartialMenuSection[]> {
|
||||||
|
@@ -6,13 +6,9 @@
|
|||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { getDSORoute } from '../../../app-routing-paths';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
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 { MenuItemType } from '../menu-item-type.model';
|
||||||
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
import { LinkMenuItemModel } from '../menu-item/models/link.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
import { DSpaceObjectPageMenuProvider } from './dso.menu';
|
import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrcidMenuProvider extends DSpaceObjectPageMenuProvider<Item> {
|
export class OrcidMenuProvider extends DSpaceObjectPageMenuProvider {
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
) {
|
) {
|
||||||
super(dsoDataService);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected isApplicable(item: Item): boolean {
|
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<PartialMenuSection[]> {
|
public getSectionsForContext(item: Item): Observable<PartialMenuSection[]> {
|
||||||
|
@@ -6,12 +6,8 @@
|
|||||||
* http://www.dspace.org/license/
|
* http://www.dspace.org/license/
|
||||||
*/
|
*/
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
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 { MenuItemType } from '../menu-item-type.model';
|
||||||
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
|
import { OnClickMenuItemModel } from '../menu-item/models/onclick.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
import { DSpaceObjectPageMenuProvider } from './dso.menu';
|
import { DSpaceObjectPageMenuProvider } from './helper-providers/dso.menu';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VersioningMenuProvider extends DSpaceObjectPageMenuProvider<Item> {
|
export class VersioningMenuProvider extends DSpaceObjectPageMenuProvider {
|
||||||
constructor(
|
constructor(
|
||||||
protected authorizationService: AuthorizationDataService,
|
protected authorizationService: AuthorizationDataService,
|
||||||
protected dsoVersioningModalService: DsoVersioningModalService,
|
protected dsoVersioningModalService: DsoVersioningModalService,
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
) {
|
) {
|
||||||
super(dsoDataService);
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSectionsForContext(item: Item): Observable<PartialMenuSection[]> {
|
public getSectionsForContext(item: Item): Observable<PartialMenuSection[]> {
|
||||||
|
@@ -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<Item> {
|
|
||||||
allRoutes = false;
|
|
||||||
|
|
||||||
protected constructor(
|
|
||||||
protected dsoDataService: DSpaceObjectDataService,
|
|
||||||
@Optional() protected resolver?: ItemPageResolver,
|
|
||||||
) {
|
|
||||||
super(dsoDataService);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Item | undefined> {
|
|
||||||
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<RemoteData<Item>>).pipe(
|
|
||||||
getFirstCompletedRemoteData(),
|
|
||||||
map((dsoRD) => {
|
|
||||||
if (dsoRD.hasSucceeded) {
|
|
||||||
return dsoRD.payload;
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,24 +8,22 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
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 {
|
||||||
import { ThemedCreateCommunityParentSelectorComponent } from '../../dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component';
|
ThemedCreateCollectionParentSelectorComponent
|
||||||
import { ThemedCreateItemParentSelectorComponent } from '../../dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component';
|
} 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 { MenuItemType } from '../menu-item-type.model';
|
||||||
import { TextMenuItemModel } from '../menu-item/models/text.model';
|
import { TextMenuItemModel } from '../menu-item/models/text.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NewMenuProvider extends AbstractExpandableMenuProvider {
|
export class NewMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -36,7 +34,7 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -44,11 +42,12 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.new'
|
text: 'menu.section.new'
|
||||||
} as TextMenuItemModel,
|
} as TextMenuItemModel,
|
||||||
icon: 'plus',
|
icon: 'plus',
|
||||||
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
|
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
|
||||||
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
|
this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin),
|
||||||
@@ -95,7 +94,7 @@ export class NewMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
link: '/processes/new'
|
link: '/processes/new'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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<MenuTopSection> {
|
|
||||||
return observableOf(
|
|
||||||
{
|
|
||||||
model: {
|
|
||||||
type: MenuItemType.TEXT,
|
|
||||||
text: 'menu.section.notifications',
|
|
||||||
},
|
|
||||||
icon: 'bell',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
|
||||||
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[];
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -7,18 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProcessesMenuProvider extends AbstractMenuProvider {
|
export class ProcessesMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -8,21 +8,13 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import {
|
import { combineLatest, map, Observable, of as observableOf, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
of as observableOf,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractExpandableMenuProvider, } from './helper-providers/expandable-menu-provider';
|
||||||
AbstractExpandableMenuProvider,
|
import { PartialMenuSection } from '../menu-provider';
|
||||||
MenuSubSection,
|
|
||||||
MenuTopSection,
|
|
||||||
} from './expandable-menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
|
export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
|
||||||
@@ -34,7 +26,7 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTopSection(): Observable<MenuTopSection> {
|
public getTopSection(): Observable<PartialMenuSection> {
|
||||||
return observableOf(
|
return observableOf(
|
||||||
{
|
{
|
||||||
model: {
|
model: {
|
||||||
@@ -42,11 +34,12 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
text: 'menu.section.registries',
|
text: 'menu.section.registries',
|
||||||
},
|
},
|
||||||
icon: 'list',
|
icon: 'list',
|
||||||
|
visible: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSubSections(): Observable<MenuSubSection[]> {
|
public getSubSections(): Observable<PartialMenuSection[]> {
|
||||||
return combineLatest([
|
return combineLatest([
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
@@ -68,7 +61,7 @@ export class RegistriesMenuProvider extends AbstractExpandableMenuProvider {
|
|||||||
link: 'admin/registries/bitstream-formats',
|
link: 'admin/registries/bitstream-formats',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as MenuSubSection[];
|
];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -7,29 +7,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { ActivatedRouteSnapshot, RouterStateSnapshot, } from '@angular/router';
|
||||||
ActivatedRouteSnapshot,
|
import { Observable, of, } from 'rxjs';
|
||||||
RouterStateSnapshot,
|
|
||||||
} from '@angular/router';
|
|
||||||
import {
|
|
||||||
Observable,
|
|
||||||
of,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { hasNoValue, hasValue } from '../../empty.util';
|
import { hasNoValue, hasValue } from '../../empty.util';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import { PartialMenuSection } from '../menu-provider';
|
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 { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
|
|
||||||
import { getDSORoute } from '../../../app-routing-paths';
|
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 {
|
interface StatisticsLink {
|
||||||
id: string,
|
id: string,
|
||||||
@@ -40,9 +26,9 @@ interface StatisticsLink {
|
|||||||
export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider<DSpaceObject> {
|
export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider<DSpaceObject> {
|
||||||
|
|
||||||
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<DSpaceObject> {
|
public getRouteContext(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<DSpaceObject> {
|
||||||
|
let dsoRD: RemoteData<DSpaceObject> = route.data.dso;
|
||||||
let dsoRD: RemoteData<DSpaceObject> = route.data.dso
|
// Check if one of the parent routes has a DSO
|
||||||
while (hasValue(route.parent) && hasNoValue(dsoRD) ) {
|
while (hasValue(route.parent) && hasNoValue(dsoRD)) {
|
||||||
route = route.parent;
|
route = route.parent;
|
||||||
dsoRD = route.data.dso;
|
dsoRD = route.data.dso;
|
||||||
}
|
}
|
||||||
@@ -52,32 +38,6 @@ export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider<DSp
|
|||||||
} else {
|
} else {
|
||||||
return of(undefined);
|
return of(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// let page = state.url.split('/')[1];
|
|
||||||
// let uuid = route.params.id;
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// // todo: wow
|
|
||||||
// if (page === 'entities') {
|
|
||||||
// page = 'items';
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (['items', 'communities', 'collections'].includes(page)) {
|
|
||||||
// while (hasValue(route.parent) && hasNoValue(uuid) ) {
|
|
||||||
// route = route.parent;
|
|
||||||
// uuid = route.params.id;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (hasNoValue(uuid)) {
|
|
||||||
// return of(undefined);
|
|
||||||
// } else {
|
|
||||||
// return of(`statistics/${page}/${uuid}`);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return of(`statistics`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
public getSectionsForContext(dso: DSpaceObject): Observable<PartialMenuSection[]> {
|
||||||
@@ -86,29 +46,12 @@ export class StatisticsMenuProvider extends AbstractRouteContextMenuProvider<DSp
|
|||||||
|
|
||||||
let dsoRoute;
|
let dsoRoute;
|
||||||
if (hasValue(dso)) {
|
if (hasValue(dso)) {
|
||||||
// const dsoRoute = getDSORoute(dso) todo maybe have the stats page work on entity url so we can just use the getDSORoute thing 🙄
|
dsoRoute = getDSORoute(dso);
|
||||||
if (hasValue(dso)) {
|
|
||||||
console.log('DSO',dso);
|
|
||||||
switch ((dso as any).type) {
|
|
||||||
case Community.type.value:
|
|
||||||
dsoRoute = getCommunityPageRoute(dso.uuid);
|
|
||||||
break;
|
|
||||||
case Collection.type.value:
|
|
||||||
dsoRoute = getCollectionPageRoute(dso.uuid);
|
|
||||||
break;
|
|
||||||
case Item.type.value:
|
|
||||||
dsoRoute = new URLCombiner(getItemModuleRoute(), dso.uuid).toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (hasValue(dsoRoute)) {
|
if (hasValue(dsoRoute)) {
|
||||||
link = `statistics/${dsoRoute}`
|
link = `statistics/${dsoRoute}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return of([
|
return of([
|
||||||
{
|
{
|
||||||
visible: true,
|
visible: true,
|
||||||
|
@@ -7,18 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemWideAlertMenuProvider extends AbstractMenuProvider {
|
export class SystemWideAlertMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -7,18 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { combineLatest, map, Observable, } from 'rxjs';
|
||||||
combineLatest,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
} from 'rxjs';
|
|
||||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||||
import { MenuItemType } from '../menu-item-type.model';
|
import { MenuItemType } from '../menu-item-type.model';
|
||||||
import {
|
import { AbstractMenuProvider, PartialMenuSection, } from '../menu-provider';
|
||||||
AbstractMenuProvider,
|
|
||||||
PartialMenuSection,
|
|
||||||
} from '../menu-provider';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowMenuProvider extends AbstractMenuProvider {
|
export class WorkflowMenuProvider extends AbstractMenuProvider {
|
||||||
|
@@ -11,6 +11,7 @@ import { ThemedItemStatisticsPageComponent } from './item-statistics-page/themed
|
|||||||
import { ThemedSiteStatisticsPageComponent } from './site-statistics-page/themed-site-statistics-page.component';
|
import { ThemedSiteStatisticsPageComponent } from './site-statistics-page/themed-site-statistics-page.component';
|
||||||
import { ItemResolver } from '../item-page/item.resolver';
|
import { ItemResolver } from '../item-page/item.resolver';
|
||||||
import { StatisticsAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard';
|
import { StatisticsAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard';
|
||||||
|
import { ENTITY_MODULE_PATH } from '../item-page/item-page-routing-paths';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -46,6 +47,19 @@ import { StatisticsAdministratorGuard } from '../core/data/feature-authorization
|
|||||||
component: ThemedItemStatisticsPageComponent,
|
component: ThemedItemStatisticsPageComponent,
|
||||||
canActivate: [StatisticsAdministratorGuard]
|
canActivate: [StatisticsAdministratorGuard]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `${ENTITY_MODULE_PATH}/:entity-type/:id`,
|
||||||
|
resolve: {
|
||||||
|
scope: ItemResolver,
|
||||||
|
breadcrumb: I18nBreadcrumbResolver
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
title: 'statistics.title',
|
||||||
|
breadcrumbKey: 'statistics'
|
||||||
|
},
|
||||||
|
component: ThemedItemStatisticsPageComponent,
|
||||||
|
canActivate: [StatisticsAdministratorGuard]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `collections/:id`,
|
path: `collections/:id`,
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@@ -2854,36 +2854,8 @@
|
|||||||
|
|
||||||
"menu.section.export_batch": "Batch Export (ZIP)",
|
"menu.section.export_batch": "Batch Export (ZIP)",
|
||||||
|
|
||||||
"menu.section.icon.access_control": "Access Control menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.admin_search": "Admin search menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.control_panel": "Control Panel menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.curation_tasks": "Curation Task menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.edit": "Edit menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.export": "Export menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.find": "Find menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.health": "Health check menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.import": "Import menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.new": "New menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.pin": "Pin sidebar",
|
"menu.section.icon.pin": "Pin sidebar",
|
||||||
|
|
||||||
"menu.section.icon.processes": "Processes Health",
|
|
||||||
|
|
||||||
"menu.section.icon.registries": "Registries menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.statistics_task": "Statistics Task menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.workflow": "Administer workflow menu section",
|
|
||||||
|
|
||||||
"menu.section.icon.unpin": "Unpin sidebar",
|
"menu.section.icon.unpin": "Unpin sidebar",
|
||||||
|
|
||||||
"menu.section.import": "Import",
|
"menu.section.import": "Import",
|
||||||
|
@@ -106,7 +106,7 @@ export class BrowserInitService extends InitService {
|
|||||||
this.initKlaro();
|
this.initKlaro();
|
||||||
|
|
||||||
await this.authenticationReady$().toPromise();
|
await this.authenticationReady$().toPromise();
|
||||||
this.initPersistentMenus();
|
this.menuProviderService.initPersistentMenus();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user