Skip to content

Commit 18512bd

Browse files
[DURACOM-508] make explore pages configurable
1 parent 938d71c commit 18512bd

8 files changed

Lines changed: 142 additions & 12 deletions

File tree

config/config.example.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,9 @@ accessibility:
711711
# Configuration for layout customization of metadata rendering in Item page
712712
# Currently only the authority reference config is available, more will follow with the integration of the so called CRIS layout.
713713
layout:
714+
# Enable or disable the explore pages feature (/explore/:id routes and their navbar menu entries).
715+
# When false, explore routes redirect to 404 and the explore menu is hidden.
716+
enableExplorePages: true
714717
# Configuration of icons and styles to be used for each authority controlled link
715718
authorityRef:
716719
- entityType: DEFAULT
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { inject } from '@angular/core';
2+
import {
3+
ActivatedRouteSnapshot,
4+
CanActivateFn,
5+
Router,
6+
RouterStateSnapshot,
7+
UrlTree,
8+
} from '@angular/router';
9+
import {
10+
APP_CONFIG,
11+
AppConfig,
12+
} from '@dspace/config/app-config.interface';
13+
14+
import { getPageNotFoundRoute } from '../core/router/core-routing-paths';
15+
16+
/**
17+
* Route guard that checks whether explore pages are enabled in the application config.
18+
* When `layout.enableExplorePages` is false, navigating to any explore route
19+
* will redirect to the 404 page.
20+
*/
21+
export const explorePagesEnabledGuard: CanActivateFn = (
22+
route: ActivatedRouteSnapshot,
23+
state: RouterStateSnapshot,
24+
appConfig: AppConfig = inject(APP_CONFIG),
25+
router: Router = inject(Router),
26+
): boolean | UrlTree => {
27+
if (appConfig.layout.enableExplorePages) {
28+
return true;
29+
}
30+
return router.parseUrl(getPageNotFoundRoute());
31+
};

src/app/explore-page/explore-routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import { Route } from '@angular/router';
88
import { endUserAgreementCurrentUserGuard } from '../core/end-user-agreement/end-user-agreement-current-user.guard';
99
import { exploreI18nBreadcrumbResolver } from './explore-i18n-breadcrumb.resolver';
1010
import { ExplorePageComponent } from './explore-page.component';
11+
import { explorePagesEnabledGuard } from './explore-pages-enabled.guard';
1112

1213
export const ROUTES: Route[] = [
1314
{
1415
path: ':id',
1516
component: ExplorePageComponent,
1617
resolve: { breadcrumb: exploreI18nBreadcrumbResolver },
1718
data: { title: 'explore.title', breadcrumbKey: 'explore', showSocialButtons: true },
18-
canActivate: [endUserAgreementCurrentUserGuard],
19+
canActivate: [explorePagesEnabledGuard, endUserAgreementCurrentUserGuard],
1920
},
2021
];

src/app/shared/menu/providers/explore.menu.spec.ts

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,101 @@ import { SectionDataService } from '@dspace/core/data/section-data.service';
1212
import { createPaginatedList } from '@dspace/core/testing/utils.test';
1313
import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils';
1414

15-
import { environment } from '../../../../environments/environment';
15+
import { MenuItemType } from '../menu-item-type.model';
16+
import { PartialMenuSection } from '../menu-provider.model';
1617
import { ExploreMenuProvider } from './explore.menu';
1718

1819
describe('ExploreMenuProvider', () => {
1920

2021
let provider: ExploreMenuProvider;
21-
let sectionDataServiceStub = {
22-
findVisibleSections: () => createSuccessfulRemoteDataObject$(createPaginatedList([])),
23-
};
22+
let sectionDataServiceStub: any;
23+
24+
const mockSections = [
25+
{ id: 'publications', componentRows: [], nestedSections: [] },
26+
{ id: 'researchers', componentRows: [], nestedSections: [] },
27+
];
28+
29+
function configureTestingModule(enableExplorePages: boolean) {
30+
sectionDataServiceStub = {
31+
findVisibleSections: jasmine.createSpy('findVisibleSections').and.returnValue(
32+
createSuccessfulRemoteDataObject$(createPaginatedList(mockSections)),
33+
),
34+
};
2435

25-
beforeEach(() => {
2636
TestBed.configureTestingModule({
2737
providers: [
2838
ExploreMenuProvider,
29-
{ provide: APP_CONFIG, useValue: environment },
39+
{ provide: APP_CONFIG, useValue: { layout: { enableExplorePages } } },
3040
{ provide: SectionDataService, useValue: sectionDataServiceStub },
3141
],
3242
});
3343
provider = TestBed.inject(ExploreMenuProvider);
44+
}
45+
46+
describe('when enableExplorePages is true', () => {
47+
beforeEach(() => {
48+
configureTestingModule(true);
49+
});
50+
51+
it('should be created', () => {
52+
expect(provider).toBeTruthy();
53+
});
54+
55+
it('should call findVisibleSections on the SectionDataService', (done) => {
56+
provider.getSections().subscribe(() => {
57+
expect(sectionDataServiceStub.findVisibleSections).toHaveBeenCalled();
58+
done();
59+
});
60+
});
61+
62+
it('should return menu sections for each visible section', (done) => {
63+
const expectedSections: PartialMenuSection[] = [
64+
{
65+
visible: true,
66+
model: {
67+
type: MenuItemType.LINK,
68+
text: 'menu.section.explore_publications',
69+
link: '/explore/publications',
70+
},
71+
},
72+
{
73+
visible: true,
74+
model: {
75+
type: MenuItemType.LINK,
76+
text: 'menu.section.explore_researchers',
77+
link: '/explore/researchers',
78+
},
79+
},
80+
];
81+
82+
provider.getSections().subscribe((sections) => {
83+
expect(sections).toEqual(expectedSections);
84+
done();
85+
});
86+
});
3487
});
3588

36-
it('should be created', () => {
37-
expect(provider).toBeTruthy();
89+
describe('when enableExplorePages is false', () => {
90+
beforeEach(() => {
91+
configureTestingModule(false);
92+
});
93+
94+
it('should be created', () => {
95+
expect(provider).toBeTruthy();
96+
});
97+
98+
it('should return an empty array', (done) => {
99+
provider.getSections().subscribe((sections) => {
100+
expect(sections).toEqual([]);
101+
done();
102+
});
103+
});
104+
105+
it('should not call findVisibleSections on the SectionDataService', (done) => {
106+
provider.getSections().subscribe(() => {
107+
expect(sectionDataServiceStub.findVisibleSections).not.toHaveBeenCalled();
108+
done();
109+
});
110+
});
38111
});
39112
});

src/app/shared/menu/providers/explore.menu.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66
* http://www.dspace.org/license/
77
*/
88

9-
import { Injectable } from '@angular/core';
9+
import {
10+
inject,
11+
Injectable,
12+
} from '@angular/core';
13+
import { APP_CONFIG } from '@dspace/config/app-config.interface';
1014
import { PaginatedList } from '@dspace/core/data/paginated-list.model';
1115
import { RemoteData } from '@dspace/core/data/remote-data';
1216
import { SectionDataService } from '@dspace/core/data/section-data.service';
1317
import { Section } from '@dspace/core/layout/models/section.model';
1418
import { getFirstSucceededRemoteData } from '@dspace/core/shared/operators';
15-
import { Observable } from 'rxjs';
19+
import {
20+
Observable,
21+
of,
22+
} from 'rxjs';
1623
import { map } from 'rxjs/operators';
1724

1825
import { MenuItemType } from '../menu-item-type.model';
@@ -22,10 +29,13 @@ import {
2229
} from '../menu-provider.model';
2330

2431
/**
25-
* Menu provider to create the explore menu sections in the public navbar
32+
* Menu provider to create the explore menu sections in the public navbar.
33+
* Returns an empty menu when `layout.enableExplorePages` is false.
2634
*/
2735
@Injectable()
2836
export class ExploreMenuProvider extends AbstractMenuProvider {
37+
protected appConfig = inject(APP_CONFIG);
38+
2939
constructor(
3040
protected sectionDataService: SectionDataService,
3141
) {
@@ -34,8 +44,12 @@ export class ExploreMenuProvider extends AbstractMenuProvider {
3444

3545
/**
3646
* Retrieves subsections by fetching the browse definitions from the backend and mapping them to partial menu sections.
47+
* Returns an empty array when explore pages are disabled in the app configuration.
3748
*/
3849
getSections(): Observable<PartialMenuSection[]> {
50+
if (!this.appConfig.layout.enableExplorePages) {
51+
return of([]);
52+
}
3953
return this.sectionDataService.findVisibleSections().pipe(
4054
getFirstSucceededRemoteData(),
4155
map((rd: RemoteData<PaginatedList<Section>>) => {

src/config/default-app-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ export class DefaultAppConfig implements AppConfig {
746746
// These styles are used in components like MetadataLinkViewComponent to display entity type indicators
747747
// alongside metadata values, providing visual cues about the type of referenced entity.
748748
layout: LayoutConfig = {
749+
enableExplorePages: true,
749750
authorityRef: [
750751
{
751752
entityType: 'DEFAULT',

src/config/layout-config.interfaces.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export interface AuthorityRefConfig extends Config {
6262
* @see AppConfig
6363
*/
6464
export interface LayoutConfig extends Config {
65+
/**
66+
* Whether explore pages (e.g., /explore/:id) and the explore menu in the navbar are enabled.
67+
* When false, explore routes will redirect to 404 and menu entries will be hidden.
68+
*/
69+
enableExplorePages: boolean;
70+
6571
/**
6672
* Array of authority reference configurations for different entity types.
6773
* Each entry defines how entities of a specific type should be visually represented with icons and styles.

src/environments/environment.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ export const environment: BuildConfig = {
535535

536536
// Configuration for layout customization of metadata rendering in Item page
537537
layout: {
538+
enableExplorePages: true,
538539
authorityRef: [
539540
{
540541
entityType: 'DEFAULT',

0 commit comments

Comments
 (0)