diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html index 8d0ac83c32e..0ccf96328d6 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html @@ -1,23 +1,48 @@
- - - diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts index 5634b1c2620..bf770d11251 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts @@ -14,7 +14,9 @@ import { TranslateModule } from '@ngx-translate/core'; import { MenuService } from '../../../shared/menu/menu.service'; import { MenuID } from '../../../shared/menu/menu-id.model'; +import { ExternalLinkMenuItemModel } from '../../../shared/menu/menu-item/models/external-link.model'; import { LinkMenuItemModel } from '../../../shared/menu/menu-item/models/link.model'; +import { MenuItemType } from '../../../shared/menu/menu-item-type.model'; import { MenuSection } from '../../../shared/menu/menu-section.model'; import { AbstractMenuSectionComponent } from '../../../shared/menu/menu-section/abstract-menu-section.component'; import { BrowserOnlyPipe } from '../../../shared/utils/browser-only.pipe'; @@ -47,6 +49,11 @@ export class AdminSidebarSectionComponent extends AbstractMenuSectionComponent i */ isDisabled: boolean; + /** + * Whether this section links to an external URL + */ + isExternalLink: boolean; + constructor( @Inject('sectionDataProvider') protected section: MenuSection, protected menuService: MenuService, @@ -54,19 +61,31 @@ export class AdminSidebarSectionComponent extends AbstractMenuSectionComponent i protected router: Router, ) { super(menuService, injector); - this.itemModel = section.model as LinkMenuItemModel; + this.isExternalLink = section.model.type === MenuItemType.EXTERNAL; + if (this.isExternalLink) { + this.itemModel = section.model as ExternalLinkMenuItemModel; + } else { + this.itemModel = section.model as LinkMenuItemModel; + } } ngOnInit(): void { - // todo: should support all menu entries? - this.isDisabled = this.itemModel?.disabled || isEmpty(this.itemModel?.link); + if (this.isExternalLink) { + this.isDisabled = this.itemModel?.disabled || isEmpty((this.itemModel as ExternalLinkMenuItemModel)?.href); + } else { + this.isDisabled = this.itemModel?.disabled || isEmpty(this.itemModel?.link); + } super.ngOnInit(); } navigate(event: any): void { event.preventDefault(); if (!this.isDisabled) { - this.router.navigate(this.itemModel.link); + if (this.isExternalLink) { + window.open((this.itemModel as ExternalLinkMenuItemModel).href, '_blank'); + } else { + this.router.navigate(this.itemModel.link); + } } } diff --git a/src/app/app.menus.ts b/src/app/app.menus.ts index e230b039719..96fffe9c0ce 100644 --- a/src/app/app.menus.ts +++ b/src/app/app.menus.ts @@ -18,6 +18,7 @@ import { SubscribeMenuProvider } from './shared/menu/providers/comcol-subscribe. import { CommunityListMenuProvider } from './shared/menu/providers/community-list.menu'; import { CreateReportMenuProvider } from './shared/menu/providers/create-report.menu'; import { CurationMenuProvider } from './shared/menu/providers/curation.menu'; +import { DocumentationMenuProvider } from './shared/menu/providers/documentation.menu'; import { DSpaceObjectEditMenuProvider } from './shared/menu/providers/dso-edit.menu'; import { DsoOptionMenuProvider } from './shared/menu/providers/dso-option.menu'; import { EditMenuProvider } from './shared/menu/providers/edit.menu'; @@ -75,6 +76,7 @@ export const MENUS = buildMenuStructure({ SystemWideAlertMenuProvider, CoarNotifyMenuProvider, AuditOverviewMenuProvider, + DocumentationMenuProvider, ], [MenuID.DSO_EDIT]: [ DsoOptionMenuProvider.withSubs([ diff --git a/src/app/shared/menu/providers/documentation.menu.ts b/src/app/shared/menu/providers/documentation.menu.ts new file mode 100644 index 00000000000..9f1ebcc743f --- /dev/null +++ b/src/app/shared/menu/providers/documentation.menu.ts @@ -0,0 +1,80 @@ +/** + * 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 { AuthorizationDataService } from '@dspace/core/data/feature-authorization/authorization-data.service'; +import { FeatureID } from '@dspace/core/data/feature-authorization/feature-id'; +import { RootDataService } from '@dspace/core/data/root-data.service'; +import { getFirstSucceededRemoteDataPayload } from '@dspace/core/shared/operators'; +import { + catchError, + combineLatest, + map, + Observable, + of, +} from 'rxjs'; + +import { MenuItemType } from '../menu-item-type.model'; +import { + AbstractMenuProvider, + PartialMenuSection, +} from '../menu-provider.model'; + +const DSDOC_BASE_URL = 'https://wiki.lyrasis.org/display/DSDOC'; +const DSDOC_FALLBACK_URL = `${DSDOC_BASE_URL}/`; + +/** + * Menu provider to create the "Documentation" link in the admin sidebar. + * The URL is automatically built from the DSpace backend version. + * Falls back to the generic documentation URL if the version cannot be determined. + */ +@Injectable() +export class DocumentationMenuProvider extends AbstractMenuProvider { + constructor( + protected authorizationService: AuthorizationDataService, + protected rootDataService: RootDataService, + ) { + super(); + } + + public getSections(): Observable { + return combineLatest([ + this.authorizationService.isAuthorized(FeatureID.AdministratorOf), + this.rootDataService.findRoot().pipe( + getFirstSucceededRemoteDataPayload(), + catchError(() => of(null)), + ), + ]).pipe( + map(([isSiteAdmin, root]) => { + const docsUrl = this.buildDocsUrl(root?.dspaceVersion); + return [ + { + visible: isSiteAdmin, + model: { + type: MenuItemType.EXTERNAL, + text: 'menu.section.documentation', + href: docsUrl, + }, + icon: 'book', + }, + ] as PartialMenuSection[]; + }), + ); + } + + private buildDocsUrl(dspaceVersion?: string): string { + if (!dspaceVersion) { + return DSDOC_FALLBACK_URL; + } + const majorVersion = dspaceVersion.replace(/[^\d.]/g, '').split('.')[0]; + if (!majorVersion) { + return DSDOC_FALLBACK_URL; + } + return `${DSDOC_BASE_URL}${majorVersion}x`; + } +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index c3bdb7b0374..76962cd7fab 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3621,6 +3621,8 @@ "menu.section.health": "Health", + "menu.section.documentation": "Documentation", + "menu.section.registries": "Registries", "menu.section.registries_format": "Format",