Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,48 @@
<div>
<a class="sidebar-section-wrapper"
[ngClass]="{ disabled: isDisabled }"
role="menuitem"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="adminMenuSectionTitleAccessibilityHandle(section)"
[routerLink]="itemModel.link"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
href="javascript:void(0);"
>
<div class="sidebar-fixed-element-wrapper" data-test="sidebar-section-icon" aria-hidden="true">
<i class="fas fa-{{section.icon}} fa-fw"></i>
</div>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
<span [id]="adminMenuSectionTitleAccessibilityHandle(section)" [attr.data-test]="adminMenuSectionTitleAccessibilityHandle(section) | dsBrowserOnly">
{{itemModel.text | translate}}
</span>
@if (isExternalLink) {
<a class="sidebar-section-wrapper"
[ngClass]="{ disabled: isDisabled }"
role="menuitem"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="adminMenuSectionTitleAccessibilityHandle(section)"
[href]="itemModel.href"
target="_blank"
rel="noopener noreferrer"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
>
<div class="sidebar-fixed-element-wrapper" data-test="sidebar-section-icon" aria-hidden="true">
<i class="fas fa-{{section.icon}} fa-fw"></i>
</div>
</div>
</a>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
<span [id]="adminMenuSectionTitleAccessibilityHandle(section)" [attr.data-test]="adminMenuSectionTitleAccessibilityHandle(section) | dsBrowserOnly">
{{itemModel.text | translate}}
</span>
</div>
</div>
</a>
} @else {
<a class="sidebar-section-wrapper"
[ngClass]="{ disabled: isDisabled }"
role="menuitem"
[attr.aria-disabled]="isDisabled"
[attr.aria-labelledby]="adminMenuSectionTitleAccessibilityHandle(section)"
[routerLink]="itemModel.link"
(keyup.space)="navigate($event)"
(keyup.enter)="navigate($event)"
href="javascript:void(0);"
>
<div class="sidebar-fixed-element-wrapper" data-test="sidebar-section-icon" aria-hidden="true">
<i class="fas fa-{{section.icon}} fa-fw"></i>
</div>
<div class="sidebar-collapsible-element-outer-wrapper">
<div class="sidebar-collapsible-element-inner-wrapper sidebar-item">
<span [id]="adminMenuSectionTitleAccessibilityHandle(section)" [attr.data-test]="adminMenuSectionTitleAccessibilityHandle(section) | dsBrowserOnly">
{{itemModel.text | translate}}
</span>
</div>
</div>
</a>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -47,26 +49,43 @@ 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,
protected injector: Injector,
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);
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/app/app.menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -75,6 +76,7 @@ export const MENUS = buildMenuStructure({
SystemWideAlertMenuProvider,
CoarNotifyMenuProvider,
AuditOverviewMenuProvider,
DocumentationMenuProvider,
],
[MenuID.DSO_EDIT]: [
DsoOptionMenuProvider.withSubs([
Expand Down
80 changes: 80 additions & 0 deletions src/app/shared/menu/providers/documentation.menu.ts
Original file line number Diff line number Diff line change
@@ -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<PartialMenuSection[]> {
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`;
}
}
2 changes: 2 additions & 0 deletions src/assets/i18n/en.json5
Original file line number Diff line number Diff line change
Expand Up @@ -3621,6 +3621,8 @@

"menu.section.health": "Health",

"menu.section.documentation": "Documentation",

"menu.section.registries": "Registries",

"menu.section.registries_format": "Format",
Expand Down
Loading