From fc6678515a62c4d1d1b05eeb0dd85c1f633489f1 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Thu, 4 Nov 2021 14:21:12 +0100 Subject: [PATCH 01/77] [DSC-287] Created new page error 500, added guard to check for initial api request, redirect to page 500 --- src/app/app-routing-paths.ts | 6 ++ src/app/app-routing.module.ts | 58 +++++++++++-------- src/app/app.module.ts | 6 +- .../server-check/server-check.guard.spec.ts | 16 +++++ .../core/server-check/server-check.guard.ts | 30 ++++++++++ .../page-internal-server-error.component.html | 10 ++++ .../page-internal-server-error.component.scss | 0 .../page-internal-server-error.component.ts | 33 +++++++++++ ...ed-page-internal-server-error.component.ts | 26 +++++++++ src/assets/i18n/en.json5 | 5 ++ 10 files changed, 164 insertions(+), 26 deletions(-) create mode 100644 src/app/core/server-check/server-check.guard.spec.ts create mode 100644 src/app/core/server-check/server-check.guard.ts create mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.html create mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.scss create mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.ts create mode 100644 src/app/page-internal-server-error/themed-page-internal-server-error.component.ts diff --git a/src/app/app-routing-paths.ts b/src/app/app-routing-paths.ts index db6b22a023..d9c3410931 100644 --- a/src/app/app-routing-paths.ts +++ b/src/app/app-routing-paths.ts @@ -89,6 +89,12 @@ export function getPageNotFoundRoute() { return `/${PAGE_NOT_FOUND_PATH}`; } +export const INTERNAL_SERVER_ERROR = '500'; + +export function getPageInternalServerErrorRoute() { + return `/${INTERNAL_SERVER_ERROR}`; +} + export const INFO_MODULE_PATH = 'info'; export function getInfoModulePath() { return `/${INFO_MODULE_PATH}`; diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 157ada622d..7941adc35c 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -26,6 +26,9 @@ import { SiteRegisterGuard } from './core/data/feature-authorization/feature-aut import { ThemedPageNotFoundComponent } from './pagenotfound/themed-pagenotfound.component'; import { ThemedForbiddenComponent } from './forbidden/themed-forbidden.component'; import { GroupAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/group-administrator.guard'; +import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component'; +import { ServerCheckGuard } from './core/server-check/server-check.guard'; + @NgModule({ imports: [ @@ -33,157 +36,160 @@ import { GroupAdministratorGuard } from './core/data/feature-authorization/featu path: '', canActivate: [AuthBlockingGuard], children: [ { path: '', redirectTo: '/home', pathMatch: 'full' }, - { path: 'reload/:rnd', component: ThemedPageNotFoundComponent, pathMatch: 'full', canActivate: [ReloadGuard] }, + { path: 'reload/:rnd', component: ThemedPageNotFoundComponent, pathMatch: 'full', canActivate: [ServerCheckGuard, ReloadGuard] }, { path: 'home', loadChildren: () => import('./home-page/home-page.module') .then((m) => m.HomePageModule), data: { showBreadcrumbs: false }, - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'community-list', loadChildren: () => import('./community-list-page/community-list-page.module') .then((m) => m.CommunityListPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'id', loadChildren: () => import('./lookup-by-id/lookup-by-id.module') .then((m) => m.LookupIdModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'handle', loadChildren: () => import('./lookup-by-id/lookup-by-id.module') .then((m) => m.LookupIdModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: REGISTER_PATH, loadChildren: () => import('./register-page/register-page.module') .then((m) => m.RegisterPageModule), - canActivate: [SiteRegisterGuard] + canActivate: [ServerCheckGuard, SiteRegisterGuard] }, { path: FORGOT_PASSWORD_PATH, loadChildren: () => import('./forgot-password/forgot-password.module') .then((m) => m.ForgotPasswordModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: COMMUNITY_MODULE_PATH, loadChildren: () => import('./community-page/community-page.module') .then((m) => m.CommunityPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: COLLECTION_MODULE_PATH, loadChildren: () => import('./collection-page/collection-page.module') .then((m) => m.CollectionPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: ITEM_MODULE_PATH, loadChildren: () => import('./item-page/item-page.module') .then((m) => m.ItemPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'entities/:entity-type', loadChildren: () => import('./item-page/item-page.module') .then((m) => m.ItemPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: LEGACY_BITSTREAM_MODULE_PATH, loadChildren: () => import('./bitstream-page/bitstream-page.module') .then((m) => m.BitstreamPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: BITSTREAM_MODULE_PATH, loadChildren: () => import('./bitstream-page/bitstream-page.module') .then((m) => m.BitstreamPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'mydspace', loadChildren: () => import('./my-dspace-page/my-dspace-page.module') .then((m) => m.MyDSpacePageModule), - canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] }, { path: 'search', loadChildren: () => import('./search-page/search-page-routing.module') .then((m) => m.SearchPageRoutingModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'browse', loadChildren: () => import('./browse-by/browse-by-page.module') .then((m) => m.BrowseByPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: ADMIN_MODULE_PATH, loadChildren: () => import('./admin/admin.module') .then((m) => m.AdminModule), - canActivate: [SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] }, { path: 'login', loadChildren: () => import('./login-page/login-page.module') .then((m) => m.LoginPageModule), + canActivate: [ServerCheckGuard] }, { path: 'logout', loadChildren: () => import('./logout-page/logout-page.module') .then((m) => m.LogoutPageModule), + canActivate: [ServerCheckGuard] }, { path: 'submit', loadChildren: () => import('./submit-page/submit-page.module') .then((m) => m.SubmitPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'import-external', loadChildren: () => import('./import-external-page/import-external-page.module') .then((m) => m.ImportExternalPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: 'workspaceitems', loadChildren: () => import('./workspaceitems-edit-page/workspaceitems-edit-page.module') .then((m) => m.WorkspaceitemsEditPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: WORKFLOW_ITEM_MODULE_PATH, loadChildren: () => import('./workflowitems-edit-page/workflowitems-edit-page.module') .then((m) => m.WorkflowItemsEditPageModule), - canActivate: [EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] }, { path: PROFILE_MODULE_PATH, loadChildren: () => import('./profile-page/profile-page.module') .then((m) => m.ProfilePageModule), - canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] }, { path: PROCESS_MODULE_PATH, loadChildren: () => import('./process-page/process-page.module') .then((m) => m.ProcessPageModule), - canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] }, { path: INFO_MODULE_PATH, loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), + canActivate: [ServerCheckGuard] }, { path: REQUEST_COPY_MODULE_PATH, loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), - canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] }, { path: FORBIDDEN_PATH, @@ -193,12 +199,14 @@ import { GroupAdministratorGuard } from './core/data/feature-authorization/featu path: 'statistics', loadChildren: () => import('./statistics-page/statistics-page-routing.module') .then((m) => m.StatisticsPageRoutingModule), + canActivate: [ServerCheckGuard] }, { path: ACCESS_CONTROL_MODULE_PATH, loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), - canActivate: [GroupAdministratorGuard], + canActivate: [ServerCheckGuard, GroupAdministratorGuard], }, + { path: '500', component: ThemedPageInternalServerErrorComponent }, { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, ]} ],{ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e2cb10691b..d288721014 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -53,6 +53,8 @@ import { ThemedFooterComponent } from './footer/themed-footer.component'; import { ThemedBreadcrumbsComponent } from './breadcrumbs/themed-breadcrumbs.component'; import { ThemedHeaderNavbarWrapperComponent } from './header-nav-wrapper/themed-header-navbar-wrapper.component'; import { IdleModalComponent } from './shared/idle-modal/idle-modal.component'; +import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component'; +import { PageInternalServerErrorComponent } from './page-internal-server-error/page-internal-server-error.component'; import { UUIDService } from './core/shared/uuid.service'; import { CookieService } from './core/services/cookie.service'; @@ -187,7 +189,9 @@ const DECLARATIONS = [ ThemedBreadcrumbsComponent, ForbiddenComponent, ThemedForbiddenComponent, - IdleModalComponent + IdleModalComponent, + ThemedPageInternalServerErrorComponent, + PageInternalServerErrorComponent ]; const EXPORTS = [ diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts new file mode 100644 index 0000000000..fc072cd73c --- /dev/null +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ServerCheckGuard } from './server-check.guard'; + +describe('ServerCheckGuard', () => { + let guard: ServerCheckGuard; + + beforeEach(() => { + TestBed.configureTestingModule({}); + guard = TestBed.inject(ServerCheckGuard); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); +}); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts new file mode 100644 index 0000000000..32ff57ebb3 --- /dev/null +++ b/src/app/core/server-check/server-check.guard.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { Observable } from 'rxjs'; +import { RootDataService } from '../data/root-data.service'; +import { map, tap } from 'rxjs/operators'; +import { RemoteData } from '../data/remote-data'; +import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; +import { Router } from '@angular/router'; + +@Injectable({ + providedIn: 'root' +}) +export class ServerCheckGuard implements CanActivate { + constructor(private router: Router,private rootDataService: RootDataService) {} + + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + + return this.rootDataService.findRoot().pipe( + map( (res: RemoteData) => res.hasSucceeded ), + tap( (responsehasSucceeded: boolean) => { + if (!responsehasSucceeded) { + this.router.navigateByUrl(getPageInternalServerErrorRoute()); + } + }), + ); + + } +} diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.html b/src/app/page-internal-server-error/page-internal-server-error.component.html new file mode 100644 index 0000000000..ab4f3788f3 --- /dev/null +++ b/src/app/page-internal-server-error/page-internal-server-error.component.html @@ -0,0 +1,10 @@ +
+

500

+

{{"500.page-internal-server-error" | translate}}

+
+

{{"500.help" | translate}}

+
+ +
\ No newline at end of file diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.scss b/src/app/page-internal-server-error/page-internal-server-error.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts new file mode 100644 index 0000000000..2c4e37d30f --- /dev/null +++ b/src/app/page-internal-server-error/page-internal-server-error.component.ts @@ -0,0 +1,33 @@ +import { ServerResponseService } from '../core/services/server-response.service'; +import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { AuthService } from '../core/auth/auth.service'; + +/** + * This component representing the `PageNotFound` DSpace page. + */ +@Component({ + selector: 'ds-page-internal-server-error', + styleUrls: ['./page-internal-server-error.component.scss'], + templateUrl: './page-internal-server-error.component.html', + changeDetection: ChangeDetectionStrategy.Default +}) +export class PageInternalServerErrorComponent implements OnInit { + + /** + * Initialize instance variables + * + * @param {AuthService} authservice + * @param {ServerResponseService} responseService + */ + constructor(private authservice: AuthService, private responseService: ServerResponseService) { + this.responseService.setNotFound(); + } + + /** + * Remove redirect url from the state + */ + ngOnInit(): void { + this.authservice.clearRedirectUrl(); + } + +} diff --git a/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts b/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts new file mode 100644 index 0000000000..e8792c4789 --- /dev/null +++ b/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { ThemedComponent } from '../shared/theme-support/themed.component'; +import { PageInternalServerErrorComponent } from './page-internal-server-error.component'; + +/** + * Themed wrapper for PageInternalServerErrorComponent + */ +@Component({ + selector: 'ds-themed-search-page', + styleUrls: [], + templateUrl: '../shared/theme-support/themed.component.html', +}) +export class ThemedPageInternalServerErrorComponent extends ThemedComponent { + + protected getComponentName(): string { + return 'PageInternalServerErrorComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../themes/${themeName}/app/page-internal-server-error/page-internal-server-error.component`); + } + + protected importUnthemedComponent(): Promise { + return import(`./page-internal-server-error.component`); + } +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 4b06895664..61c5ec77cc 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -14,6 +14,11 @@ "403.forbidden": "forbidden", + "500.page-internal-server-error": "Internal Server Error", + + "500.help": "There was an error with the server.", + + "500.link.home-page": "Take me to the home page", "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", From 04548237fd08fc1a856af86e0b59988662cd481f Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Thu, 4 Nov 2021 14:50:26 +0100 Subject: [PATCH 02/77] [DSC-287] Fixes UI and changed the texts in i18n --- .../page-internal-server-error.component.html | 3 --- src/assets/i18n/en.json5 | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.html b/src/app/page-internal-server-error/page-internal-server-error.component.html index ab4f3788f3..8e30236c4f 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.html +++ b/src/app/page-internal-server-error/page-internal-server-error.component.html @@ -4,7 +4,4 @@

{{"500.help" | translate}}


- \ No newline at end of file diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 61c5ec77cc..6eca2c1f5d 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -14,9 +14,9 @@ "403.forbidden": "forbidden", - "500.page-internal-server-error": "Internal Server Error", + "500.page-internal-server-error": "Service Unavailable", - "500.help": "There was an error with the server.", + "500.help": "The server is temporarily unable to service yourrequest due to maintenance downtime or capacityproblems. Please try again later.", "500.link.home-page": "Take me to the home page", From 2151d1af58d7f1acaaefa95d6127d2d2dd0fcdd8 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 15 Nov 2021 18:49:13 +0100 Subject: [PATCH 03/77] [DSC-287] Fix error message --- src/assets/i18n/en.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index ebdb2ef4bc..fede29a047 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -16,7 +16,7 @@ "500.page-internal-server-error": "Service Unavailable", - "500.help": "The server is temporarily unable to service yourrequest due to maintenance downtime or capacityproblems. Please try again later.", + "500.help": "The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.", "500.link.home-page": "Take me to the home page", From 25a51c97644a81cef0504faf11859074711a477b Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 15 Nov 2021 18:52:33 +0100 Subject: [PATCH 04/77] [DSC-287] Add test to guard --- .../server-check/server-check.guard.spec.ts | 47 +++++++++++++++++-- .../core/server-check/server-check.guard.ts | 20 ++++---- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts index fc072cd73c..976021dcdb 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -1,16 +1,55 @@ -import { TestBed } from '@angular/core/testing'; - import { ServerCheckGuard } from './server-check.guard'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; +import { first } from 'rxjs/operators'; +import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; describe('ServerCheckGuard', () => { let guard: ServerCheckGuard; + let router; + let rootDataServiceStub: any; + + rootDataServiceStub = jasmine.createSpyObj('RootDataService', { + findRoot: jasmine.createSpy('findRoot') + }); + router = jasmine.createSpyObj('Router', { + navigateByUrl: jasmine.createSpy('navigateByUrl') + }); beforeEach(() => { - TestBed.configureTestingModule({}); - guard = TestBed.inject(ServerCheckGuard); + guard = new ServerCheckGuard(router, rootDataServiceStub); }); it('should be created', () => { expect(guard).toBeTruthy(); }); + + describe('when root endpoint has succeeded', () => { + beforeEach(() => { + rootDataServiceStub.findRoot.and.returnValue(createSuccessfulRemoteDataObject$({})); + }); + + it('should not redirect to error page', () => { + guard.canActivate({} as any, {} as any).pipe( + first() + ).subscribe((canActivate: boolean) => { + expect(canActivate).toEqual(true); + expect(router.navigateByUrl).not.toHaveBeenCalled(); + }); + }); + }); + + describe('when root endpoint has not succeeded', () => { + beforeEach(() => { + rootDataServiceStub.findRoot.and.returnValue(createFailedRemoteDataObject$()); + }); + + it('should redirect to error page', () => { + guard.canActivate({} as any, {} as any).pipe( + first() + ).subscribe((canActivate: boolean) => { + expect(canActivate).toEqual(false); + expect(router.navigateByUrl).toHaveBeenCalledWith(getPageInternalServerErrorRoute()); + }); + }); + }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 32ff57ebb3..478a710567 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -1,26 +1,30 @@ import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; + import { Observable } from 'rxjs'; -import { RootDataService } from '../data/root-data.service'; import { map, tap } from 'rxjs/operators'; + +import { RootDataService } from '../data/root-data.service'; import { RemoteData } from '../data/remote-data'; import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; -import { Router } from '@angular/router'; +import { getFirstCompletedRemoteData } from '../shared/operators'; @Injectable({ providedIn: 'root' }) export class ServerCheckGuard implements CanActivate { - constructor(private router: Router,private rootDataService: RootDataService) {} + constructor(private router: Router, private rootDataService: RootDataService) { + } canActivate( route: ActivatedRouteSnapshot, - state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + state: RouterStateSnapshot): Observable { return this.rootDataService.findRoot().pipe( - map( (res: RemoteData) => res.hasSucceeded ), - tap( (responsehasSucceeded: boolean) => { - if (!responsehasSucceeded) { + getFirstCompletedRemoteData(), + map((res: RemoteData) => res.hasSucceeded), + tap((hasSucceeded: boolean) => { + if (!hasSucceeded) { this.router.navigateByUrl(getPageInternalServerErrorRoute()); } }), From 81c4403ee6c6a37ab5ce99974e997446aca4edca Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 15 Nov 2021 19:02:10 +0100 Subject: [PATCH 05/77] [DSC-287] reformat app-routing.module code --- src/app/app-routing.module.ts | 363 +++++++++++++++++----------------- 1 file changed, 185 insertions(+), 178 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7941adc35c..fcf9cd034a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -11,10 +11,11 @@ import { FORBIDDEN_PATH, FORGOT_PASSWORD_PATH, INFO_MODULE_PATH, + LEGACY_BITSTREAM_MODULE_PATH, PROFILE_MODULE_PATH, REGISTER_PATH, + REQUEST_COPY_MODULE_PATH, WORKFLOW_ITEM_MODULE_PATH, - LEGACY_BITSTREAM_MODULE_PATH, REQUEST_COPY_MODULE_PATH, } from './app-routing-paths'; import { COLLECTION_MODULE_PATH } from './collection-page/collection-page-routing-paths'; import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-paths'; @@ -29,187 +30,193 @@ import { GroupAdministratorGuard } from './core/data/feature-authorization/featu import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component'; import { ServerCheckGuard } from './core/server-check/server-check.guard'; - @NgModule({ imports: [ RouterModule.forRoot([{ path: '', canActivate: [AuthBlockingGuard], - children: [ - { path: '', redirectTo: '/home', pathMatch: 'full' }, - { path: 'reload/:rnd', component: ThemedPageNotFoundComponent, pathMatch: 'full', canActivate: [ServerCheckGuard, ReloadGuard] }, - { - path: 'home', - loadChildren: () => import('./home-page/home-page.module') - .then((m) => m.HomePageModule), - data: { showBreadcrumbs: false }, - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'community-list', - loadChildren: () => import('./community-list-page/community-list-page.module') - .then((m) => m.CommunityListPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'id', - loadChildren: () => import('./lookup-by-id/lookup-by-id.module') - .then((m) => m.LookupIdModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'handle', - loadChildren: () => import('./lookup-by-id/lookup-by-id.module') - .then((m) => m.LookupIdModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: REGISTER_PATH, - loadChildren: () => import('./register-page/register-page.module') - .then((m) => m.RegisterPageModule), - canActivate: [ServerCheckGuard, SiteRegisterGuard] - }, - { - path: FORGOT_PASSWORD_PATH, - loadChildren: () => import('./forgot-password/forgot-password.module') - .then((m) => m.ForgotPasswordModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: COMMUNITY_MODULE_PATH, - loadChildren: () => import('./community-page/community-page.module') - .then((m) => m.CommunityPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: COLLECTION_MODULE_PATH, - loadChildren: () => import('./collection-page/collection-page.module') - .then((m) => m.CollectionPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: ITEM_MODULE_PATH, - loadChildren: () => import('./item-page/item-page.module') - .then((m) => m.ItemPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { path: 'entities/:entity-type', - loadChildren: () => import('./item-page/item-page.module') - .then((m) => m.ItemPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: LEGACY_BITSTREAM_MODULE_PATH, - loadChildren: () => import('./bitstream-page/bitstream-page.module') - .then((m) => m.BitstreamPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: BITSTREAM_MODULE_PATH, - loadChildren: () => import('./bitstream-page/bitstream-page.module') - .then((m) => m.BitstreamPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'mydspace', - loadChildren: () => import('./my-dspace-page/my-dspace-page.module') - .then((m) => m.MyDSpacePageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'search', - loadChildren: () => import('./search-page/search-page-routing.module') - .then((m) => m.SearchPageRoutingModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'browse', - loadChildren: () => import('./browse-by/browse-by-page.module') - .then((m) => m.BrowseByPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: ADMIN_MODULE_PATH, - loadChildren: () => import('./admin/admin.module') - .then((m) => m.AdminModule), - canActivate: [ServerCheckGuard, SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'login', - loadChildren: () => import('./login-page/login-page.module') - .then((m) => m.LoginPageModule), - canActivate: [ServerCheckGuard] - }, - { - path: 'logout', - loadChildren: () => import('./logout-page/logout-page.module') - .then((m) => m.LogoutPageModule), - canActivate: [ServerCheckGuard] - }, - { - path: 'submit', - loadChildren: () => import('./submit-page/submit-page.module') - .then((m) => m.SubmitPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'import-external', - loadChildren: () => import('./import-external-page/import-external-page.module') - .then((m) => m.ImportExternalPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'workspaceitems', - loadChildren: () => import('./workspaceitems-edit-page/workspaceitems-edit-page.module') - .then((m) => m.WorkspaceitemsEditPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: WORKFLOW_ITEM_MODULE_PATH, - loadChildren: () => import('./workflowitems-edit-page/workflowitems-edit-page.module') - .then((m) => m.WorkflowItemsEditPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: PROFILE_MODULE_PATH, - loadChildren: () => import('./profile-page/profile-page.module') - .then((m) => m.ProfilePageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: PROCESS_MODULE_PATH, - loadChildren: () => import('./process-page/process-page.module') - .then((m) => m.ProcessPageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: INFO_MODULE_PATH, - loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), - canActivate: [ServerCheckGuard] - }, - { - path: REQUEST_COPY_MODULE_PATH, - loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: FORBIDDEN_PATH, - component: ThemedForbiddenComponent - }, - { - path: 'statistics', - loadChildren: () => import('./statistics-page/statistics-page-routing.module') - .then((m) => m.StatisticsPageRoutingModule), - canActivate: [ServerCheckGuard] - }, - { - path: ACCESS_CONTROL_MODULE_PATH, - loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), - canActivate: [ServerCheckGuard, GroupAdministratorGuard], - }, - { path: '500', component: ThemedPageInternalServerErrorComponent }, - { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, - ]} - ],{ + children: [ + { path: '', redirectTo: '/home', pathMatch: 'full' }, + { + path: 'reload/:rnd', + component: ThemedPageNotFoundComponent, + pathMatch: 'full', + canActivate: [ServerCheckGuard, ReloadGuard] + }, + { + path: 'home', + loadChildren: () => import('./home-page/home-page.module') + .then((m) => m.HomePageModule), + data: { showBreadcrumbs: false }, + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'community-list', + loadChildren: () => import('./community-list-page/community-list-page.module') + .then((m) => m.CommunityListPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'id', + loadChildren: () => import('./lookup-by-id/lookup-by-id.module') + .then((m) => m.LookupIdModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'handle', + loadChildren: () => import('./lookup-by-id/lookup-by-id.module') + .then((m) => m.LookupIdModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: REGISTER_PATH, + loadChildren: () => import('./register-page/register-page.module') + .then((m) => m.RegisterPageModule), + canActivate: [ServerCheckGuard, SiteRegisterGuard] + }, + { + path: FORGOT_PASSWORD_PATH, + loadChildren: () => import('./forgot-password/forgot-password.module') + .then((m) => m.ForgotPasswordModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: COMMUNITY_MODULE_PATH, + loadChildren: () => import('./community-page/community-page.module') + .then((m) => m.CommunityPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: COLLECTION_MODULE_PATH, + loadChildren: () => import('./collection-page/collection-page.module') + .then((m) => m.CollectionPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: ITEM_MODULE_PATH, + loadChildren: () => import('./item-page/item-page.module') + .then((m) => m.ItemPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'entities/:entity-type', + loadChildren: () => import('./item-page/item-page.module') + .then((m) => m.ItemPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: LEGACY_BITSTREAM_MODULE_PATH, + loadChildren: () => import('./bitstream-page/bitstream-page.module') + .then((m) => m.BitstreamPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: BITSTREAM_MODULE_PATH, + loadChildren: () => import('./bitstream-page/bitstream-page.module') + .then((m) => m.BitstreamPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'mydspace', + loadChildren: () => import('./my-dspace-page/my-dspace-page.module') + .then((m) => m.MyDSpacePageModule), + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'search', + loadChildren: () => import('./search-page/search-page-routing.module') + .then((m) => m.SearchPageRoutingModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'browse', + loadChildren: () => import('./browse-by/browse-by-page.module') + .then((m) => m.BrowseByPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: ADMIN_MODULE_PATH, + loadChildren: () => import('./admin/admin.module') + .then((m) => m.AdminModule), + canActivate: [ServerCheckGuard, SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'login', + loadChildren: () => import('./login-page/login-page.module') + .then((m) => m.LoginPageModule), + canActivate: [ServerCheckGuard] + }, + { + path: 'logout', + loadChildren: () => import('./logout-page/logout-page.module') + .then((m) => m.LogoutPageModule), + canActivate: [ServerCheckGuard] + }, + { + path: 'submit', + loadChildren: () => import('./submit-page/submit-page.module') + .then((m) => m.SubmitPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'import-external', + loadChildren: () => import('./import-external-page/import-external-page.module') + .then((m) => m.ImportExternalPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'workspaceitems', + loadChildren: () => import('./workspaceitems-edit-page/workspaceitems-edit-page.module') + .then((m) => m.WorkspaceitemsEditPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: WORKFLOW_ITEM_MODULE_PATH, + loadChildren: () => import('./workflowitems-edit-page/workflowitems-edit-page.module') + .then((m) => m.WorkflowItemsEditPageModule), + canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: PROFILE_MODULE_PATH, + loadChildren: () => import('./profile-page/profile-page.module') + .then((m) => m.ProfilePageModule), + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: PROCESS_MODULE_PATH, + loadChildren: () => import('./process-page/process-page.module') + .then((m) => m.ProcessPageModule), + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: INFO_MODULE_PATH, + loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), + canActivate: [ServerCheckGuard] + }, + { + path: REQUEST_COPY_MODULE_PATH, + loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), + canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: FORBIDDEN_PATH, + component: ThemedForbiddenComponent + }, + { + path: 'statistics', + loadChildren: () => import('./statistics-page/statistics-page-routing.module') + .then((m) => m.StatisticsPageRoutingModule), + canActivate: [ServerCheckGuard] + }, + { + path: ACCESS_CONTROL_MODULE_PATH, + loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), + canActivate: [ServerCheckGuard, GroupAdministratorGuard], + }, + { path: '500', component: ThemedPageInternalServerErrorComponent }, + { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, + ] + } + ], { onSameUrlNavigation: 'reload', }) ], From 76ddce723990984fcb5fef3d6647c4a4338ba254 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 16 Nov 2021 17:38:20 +0100 Subject: [PATCH 06/77] [DSC-287] fix test --- .../server-check/server-check.guard.spec.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts index 976021dcdb..a9c03d1cd7 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -1,12 +1,16 @@ import { ServerCheckGuard } from './server-check.guard'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; -import { first } from 'rxjs/operators'; +import { take } from 'rxjs/operators'; import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; +import { Router } from '@angular/router'; +import { RootDataService } from '../data/root-data.service'; +import { Root } from '../data/root.model'; +import SpyObj = jasmine.SpyObj; describe('ServerCheckGuard', () => { let guard: ServerCheckGuard; - let router; - let rootDataServiceStub: any; + let router: SpyObj; + let rootDataServiceStub: SpyObj; rootDataServiceStub = jasmine.createSpyObj('RootDataService', { findRoot: jasmine.createSpy('findRoot') @@ -19,18 +23,22 @@ describe('ServerCheckGuard', () => { guard = new ServerCheckGuard(router, rootDataServiceStub); }); + afterEach(() => { + router.navigateByUrl.calls.reset(); + }); + it('should be created', () => { expect(guard).toBeTruthy(); }); describe('when root endpoint has succeeded', () => { beforeEach(() => { - rootDataServiceStub.findRoot.and.returnValue(createSuccessfulRemoteDataObject$({})); + rootDataServiceStub.findRoot.and.returnValue(createSuccessfulRemoteDataObject$({} as any)); }); it('should not redirect to error page', () => { guard.canActivate({} as any, {} as any).pipe( - first() + take(1) ).subscribe((canActivate: boolean) => { expect(canActivate).toEqual(true); expect(router.navigateByUrl).not.toHaveBeenCalled(); @@ -40,12 +48,12 @@ describe('ServerCheckGuard', () => { describe('when root endpoint has not succeeded', () => { beforeEach(() => { - rootDataServiceStub.findRoot.and.returnValue(createFailedRemoteDataObject$()); + rootDataServiceStub.findRoot.and.returnValue(createFailedRemoteDataObject$()); }); it('should redirect to error page', () => { guard.canActivate({} as any, {} as any).pipe( - first() + take(1) ).subscribe((canActivate: boolean) => { expect(canActivate).toEqual(false); expect(router.navigateByUrl).toHaveBeenCalledWith(getPageInternalServerErrorRoute()); From a323aefc2279a5c1184c07cbe0cd1180eeadf809 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 16 Nov 2021 19:13:57 +0100 Subject: [PATCH 07/77] [DSC-287] change app-routing.module.ts inn order to have ServerCheckGuard configured once --- src/app/app-routing.module.ts | 370 +++++++++++++++++----------------- 1 file changed, 186 insertions(+), 184 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index fcf9cd034a..63fa669206 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -32,190 +32,192 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; @NgModule({ imports: [ - RouterModule.forRoot([{ - path: '', canActivate: [AuthBlockingGuard], - children: [ - { path: '', redirectTo: '/home', pathMatch: 'full' }, - { - path: 'reload/:rnd', - component: ThemedPageNotFoundComponent, - pathMatch: 'full', - canActivate: [ServerCheckGuard, ReloadGuard] - }, - { - path: 'home', - loadChildren: () => import('./home-page/home-page.module') - .then((m) => m.HomePageModule), - data: { showBreadcrumbs: false }, - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'community-list', - loadChildren: () => import('./community-list-page/community-list-page.module') - .then((m) => m.CommunityListPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'id', - loadChildren: () => import('./lookup-by-id/lookup-by-id.module') - .then((m) => m.LookupIdModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'handle', - loadChildren: () => import('./lookup-by-id/lookup-by-id.module') - .then((m) => m.LookupIdModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: REGISTER_PATH, - loadChildren: () => import('./register-page/register-page.module') - .then((m) => m.RegisterPageModule), - canActivate: [ServerCheckGuard, SiteRegisterGuard] - }, - { - path: FORGOT_PASSWORD_PATH, - loadChildren: () => import('./forgot-password/forgot-password.module') - .then((m) => m.ForgotPasswordModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: COMMUNITY_MODULE_PATH, - loadChildren: () => import('./community-page/community-page.module') - .then((m) => m.CommunityPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: COLLECTION_MODULE_PATH, - loadChildren: () => import('./collection-page/collection-page.module') - .then((m) => m.CollectionPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: ITEM_MODULE_PATH, - loadChildren: () => import('./item-page/item-page.module') - .then((m) => m.ItemPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'entities/:entity-type', - loadChildren: () => import('./item-page/item-page.module') - .then((m) => m.ItemPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: LEGACY_BITSTREAM_MODULE_PATH, - loadChildren: () => import('./bitstream-page/bitstream-page.module') - .then((m) => m.BitstreamPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: BITSTREAM_MODULE_PATH, - loadChildren: () => import('./bitstream-page/bitstream-page.module') - .then((m) => m.BitstreamPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'mydspace', - loadChildren: () => import('./my-dspace-page/my-dspace-page.module') - .then((m) => m.MyDSpacePageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'search', - loadChildren: () => import('./search-page/search-page-routing.module') - .then((m) => m.SearchPageRoutingModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'browse', - loadChildren: () => import('./browse-by/browse-by-page.module') - .then((m) => m.BrowseByPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: ADMIN_MODULE_PATH, - loadChildren: () => import('./admin/admin.module') - .then((m) => m.AdminModule), - canActivate: [ServerCheckGuard, SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'login', - loadChildren: () => import('./login-page/login-page.module') - .then((m) => m.LoginPageModule), - canActivate: [ServerCheckGuard] - }, - { - path: 'logout', - loadChildren: () => import('./logout-page/logout-page.module') - .then((m) => m.LogoutPageModule), - canActivate: [ServerCheckGuard] - }, - { - path: 'submit', - loadChildren: () => import('./submit-page/submit-page.module') - .then((m) => m.SubmitPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'import-external', - loadChildren: () => import('./import-external-page/import-external-page.module') - .then((m) => m.ImportExternalPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: 'workspaceitems', - loadChildren: () => import('./workspaceitems-edit-page/workspaceitems-edit-page.module') - .then((m) => m.WorkspaceitemsEditPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: WORKFLOW_ITEM_MODULE_PATH, - loadChildren: () => import('./workflowitems-edit-page/workflowitems-edit-page.module') - .then((m) => m.WorkflowItemsEditPageModule), - canActivate: [ServerCheckGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: PROFILE_MODULE_PATH, - loadChildren: () => import('./profile-page/profile-page.module') - .then((m) => m.ProfilePageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: PROCESS_MODULE_PATH, - loadChildren: () => import('./process-page/process-page.module') - .then((m) => m.ProcessPageModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: INFO_MODULE_PATH, - loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), - canActivate: [ServerCheckGuard] - }, - { - path: REQUEST_COPY_MODULE_PATH, - loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), - canActivate: [ServerCheckGuard, AuthenticatedGuard, EndUserAgreementCurrentUserGuard] - }, - { - path: FORBIDDEN_PATH, - component: ThemedForbiddenComponent - }, - { - path: 'statistics', - loadChildren: () => import('./statistics-page/statistics-page-routing.module') - .then((m) => m.StatisticsPageRoutingModule), - canActivate: [ServerCheckGuard] - }, - { - path: ACCESS_CONTROL_MODULE_PATH, - loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), - canActivate: [ServerCheckGuard, GroupAdministratorGuard], - }, - { path: '500', component: ThemedPageInternalServerErrorComponent }, - { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, - ] - } + RouterModule.forRoot([ + { path: '500', component: ThemedPageInternalServerErrorComponent }, + { + path: '', canActivate: [ServerCheckGuard, AuthBlockingGuard], + children: [ + { path: '', redirectTo: '/home', pathMatch: 'full' }, + { + path: 'reload/:rnd', + component: ThemedPageNotFoundComponent, + pathMatch: 'full', + canActivate: [ReloadGuard] + }, + { + path: 'home', + loadChildren: () => import('./home-page/home-page.module') + .then((m) => m.HomePageModule), + data: { showBreadcrumbs: false }, + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'community-list', + loadChildren: () => import('./community-list-page/community-list-page.module') + .then((m) => m.CommunityListPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'id', + loadChildren: () => import('./lookup-by-id/lookup-by-id.module') + .then((m) => m.LookupIdModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'handle', + loadChildren: () => import('./lookup-by-id/lookup-by-id.module') + .then((m) => m.LookupIdModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: REGISTER_PATH, + loadChildren: () => import('./register-page/register-page.module') + .then((m) => m.RegisterPageModule), + canActivate: [SiteRegisterGuard] + }, + { + path: FORGOT_PASSWORD_PATH, + loadChildren: () => import('./forgot-password/forgot-password.module') + .then((m) => m.ForgotPasswordModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: COMMUNITY_MODULE_PATH, + loadChildren: () => import('./community-page/community-page.module') + .then((m) => m.CommunityPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: COLLECTION_MODULE_PATH, + loadChildren: () => import('./collection-page/collection-page.module') + .then((m) => m.CollectionPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: ITEM_MODULE_PATH, + loadChildren: () => import('./item-page/item-page.module') + .then((m) => m.ItemPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'entities/:entity-type', + loadChildren: () => import('./item-page/item-page.module') + .then((m) => m.ItemPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: LEGACY_BITSTREAM_MODULE_PATH, + loadChildren: () => import('./bitstream-page/bitstream-page.module') + .then((m) => m.BitstreamPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: BITSTREAM_MODULE_PATH, + loadChildren: () => import('./bitstream-page/bitstream-page.module') + .then((m) => m.BitstreamPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'mydspace', + loadChildren: () => import('./my-dspace-page/my-dspace-page.module') + .then((m) => m.MyDSpacePageModule), + canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'search', + loadChildren: () => import('./search-page/search-page-routing.module') + .then((m) => m.SearchPageRoutingModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'browse', + loadChildren: () => import('./browse-by/browse-by-page.module') + .then((m) => m.BrowseByPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: ADMIN_MODULE_PATH, + loadChildren: () => import('./admin/admin.module') + .then((m) => m.AdminModule), + canActivate: [SiteAdministratorGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: 'login', + loadChildren: () => import('./login-page/login-page.module') + .then((m) => m.LoginPageModule), + canActivate: [ServerCheckGuard] + }, + { + path: 'logout', + loadChildren: () => import('./logout-page/logout-page.module') + .then((m) => m.LogoutPageModule), + canActivate: [ServerCheckGuard] + }, + { + path: 'submit', + loadChildren: () => import('./submit-page/submit-page.module') + .then((m) => m.SubmitPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'import-external', + loadChildren: () => import('./import-external-page/import-external-page.module') + .then((m) => m.ImportExternalPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: 'workspaceitems', + loadChildren: () => import('./workspaceitems-edit-page/workspaceitems-edit-page.module') + .then((m) => m.WorkspaceitemsEditPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: WORKFLOW_ITEM_MODULE_PATH, + loadChildren: () => import('./workflowitems-edit-page/workflowitems-edit-page.module') + .then((m) => m.WorkflowItemsEditPageModule), + canActivate: [EndUserAgreementCurrentUserGuard] + }, + { + path: PROFILE_MODULE_PATH, + loadChildren: () => import('./profile-page/profile-page.module') + .then((m) => m.ProfilePageModule), + canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: PROCESS_MODULE_PATH, + loadChildren: () => import('./process-page/process-page.module') + .then((m) => m.ProcessPageModule), + canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: INFO_MODULE_PATH, + loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), + canActivate: [ServerCheckGuard] + }, + { + path: REQUEST_COPY_MODULE_PATH, + loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule), + canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] + }, + { + path: FORBIDDEN_PATH, + component: ThemedForbiddenComponent + }, + { + path: 'statistics', + loadChildren: () => import('./statistics-page/statistics-page-routing.module') + .then((m) => m.StatisticsPageRoutingModule), + canActivate: [ServerCheckGuard] + }, + { + path: ACCESS_CONTROL_MODULE_PATH, + loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), + canActivate: [GroupAdministratorGuard], + }, + + { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, + ] + } ], { onSameUrlNavigation: 'reload', }) From 92e9f79f09d4e6551abcea79c0fc4dc492f33213 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 17 Nov 2021 09:37:49 +0100 Subject: [PATCH 08/77] [DSC-287] optimize code and add typedoc --- src/app/app-routing.module.ts | 16 ++++++---------- src/app/core/server-check/server-check.guard.ts | 7 +++++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 63fa669206..49e96a028a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -11,6 +11,7 @@ import { FORBIDDEN_PATH, FORGOT_PASSWORD_PATH, INFO_MODULE_PATH, + INTERNAL_SERVER_ERROR, LEGACY_BITSTREAM_MODULE_PATH, PROFILE_MODULE_PATH, REGISTER_PATH, @@ -33,7 +34,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; @NgModule({ imports: [ RouterModule.forRoot([ - { path: '500', component: ThemedPageInternalServerErrorComponent }, + { path: INTERNAL_SERVER_ERROR, component: ThemedPageInternalServerErrorComponent }, { path: '', canActivate: [ServerCheckGuard, AuthBlockingGuard], children: [ @@ -144,14 +145,12 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; { path: 'login', loadChildren: () => import('./login-page/login-page.module') - .then((m) => m.LoginPageModule), - canActivate: [ServerCheckGuard] + .then((m) => m.LoginPageModule) }, { path: 'logout', loadChildren: () => import('./logout-page/logout-page.module') - .then((m) => m.LogoutPageModule), - canActivate: [ServerCheckGuard] + .then((m) => m.LogoutPageModule) }, { path: 'submit', @@ -191,8 +190,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; }, { path: INFO_MODULE_PATH, - loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), - canActivate: [ServerCheckGuard] + loadChildren: () => import('./info/info.module').then((m) => m.InfoModule) }, { path: REQUEST_COPY_MODULE_PATH, @@ -206,15 +204,13 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; { path: 'statistics', loadChildren: () => import('./statistics-page/statistics-page-routing.module') - .then((m) => m.StatisticsPageRoutingModule), - canActivate: [ServerCheckGuard] + .then((m) => m.StatisticsPageRoutingModule) }, { path: ACCESS_CONTROL_MODULE_PATH, loadChildren: () => import('./access-control/access-control.module').then((m) => m.AccessControlModule), canActivate: [GroupAdministratorGuard], }, - { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, ] } diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 478a710567..b7982eee9a 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -12,10 +12,17 @@ import { getFirstCompletedRemoteData } from '../shared/operators'; @Injectable({ providedIn: 'root' }) +/** + * A guard that checks if root api endpoint is reachable. + * If not redirect to 500 error page + */ export class ServerCheckGuard implements CanActivate { constructor(private router: Router, private rootDataService: RootDataService) { } + /** + * True when root api endpoint is reachable. + */ canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { From 5e17a4e958db858bc7eee8c4806ee51ce46ff00b Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 30 Nov 2021 13:27:16 +0100 Subject: [PATCH 09/77] 85262: Always enable deposit button --- .../submission-form-footer.component.html | 1 - .../submission-form-footer.component.spec.ts | 9 ---- .../submission-objects.effects.spec.ts | 53 ------------------- .../objects/submission-objects.effects.ts | 4 +- 4 files changed, 1 insertion(+), 66 deletions(-) diff --git a/src/app/submission/form/footer/submission-form-footer.component.html b/src/app/submission/form/footer/submission-form-footer.component.html index 4964eb56a2..203f7e2afa 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.html +++ b/src/app/submission/form/footer/submission-form-footer.component.html @@ -41,7 +41,6 @@ diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index dd47dad444..dbeb4ee00d 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -201,15 +201,6 @@ describe('SubmissionFormFooterComponent Component', () => { }); }); - it('should have deposit button disabled when submission is not valid', () => { - comp.showDepositAndDiscard = observableOf(true); - compAsAny.submissionIsInvalid = observableOf(true); - fixture.detectChanges(); - const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); - - expect(depositBtn.nativeElement.disabled).toBeTruthy(); - }); - it('should not have deposit button disabled when submission is valid', () => { comp.showDepositAndDiscard = observableOf(true); compAsAny.submissionIsInvalid = observableOf(false); diff --git a/src/app/submission/objects/submission-objects.effects.spec.ts b/src/app/submission/objects/submission-objects.effects.spec.ts index 122ebd90ac..8e763fd94b 100644 --- a/src/app/submission/objects/submission-objects.effects.spec.ts +++ b/src/app/submission/objects/submission-objects.effects.spec.ts @@ -879,59 +879,6 @@ describe('SubmissionObjectEffects test suite', () => { expect(submissionObjectEffects.saveAndDeposit$).toBeObservable(expected); }); - it('should not allow to deposit when there are errors', () => { - store.nextState({ - submission: { - objects: submissionState - } - } as any); - - actions = hot('--a-', { - a: { - type: SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION, - payload: { - submissionId: submissionId - } - } - }); - - const response = [Object.assign({}, mockSubmissionRestResponse[0], { - sections: mockSectionsData, - errors: mockSectionsErrors - })]; - - submissionJsonPatchOperationsServiceStub.jsonPatchByResourceType.and.returnValue(observableOf(response)); - - const errorsList = parseSectionErrors(mockSectionsErrors); - const expected = cold('--b-', { - b: [ - new UpdateSectionDataAction( - submissionId, - 'traditionalpageone', - mockSectionsData.traditionalpageone as any, - errorsList.traditionalpageone || [], - errorsList.traditionalpageone || [] - ), - new UpdateSectionDataAction( - submissionId, - 'license', - mockSectionsData.license as any, - errorsList.license || [], - errorsList.license || [] - ), - new UpdateSectionDataAction( - submissionId, - 'upload', - mockSectionsData.upload as any, - errorsList.upload || [], - errorsList.upload || [] - ) - ] - }); - - expect(submissionObjectEffects.saveAndDeposit$).toBeObservable(expected); - }); - it('should catch errors and return a SAVE_SUBMISSION_FORM_ERROR', () => { actions = hot('--a-', { a: { diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index b4ba1c2480..535e662922 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -206,9 +206,7 @@ export class SubmissionObjectEffects { if (this.canDeposit(response)) { return new DepositSubmissionAction(action.payload.submissionId); } else { - this.notificationsService.warning(null, this.translate.get('submission.sections.general.sections_not_valid')); - return this.parseSaveResponse((currentState.submission as SubmissionState).objects[action.payload.submissionId], - response, action.payload.submissionId, currentState.forms); + return new SaveSubmissionFormSuccessAction(action.payload.submissionId, response); } }), catchError(() => observableOf(new SaveSubmissionFormErrorAction(action.payload.submissionId)))); From 99af22b6216cfd67fffffc0ab5f7f7883584ab1b Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 30 Nov 2021 13:44:08 +0100 Subject: [PATCH 10/77] 85262: Re-disable deposit button during save/deposit --- .../submission/form/footer/submission-form-footer.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/submission/form/footer/submission-form-footer.component.html b/src/app/submission/form/footer/submission-form-footer.component.html index 203f7e2afa..e954fab34c 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.html +++ b/src/app/submission/form/footer/submission-form-footer.component.html @@ -41,6 +41,7 @@ From c8de6ccb4c42dfbb08cbc5aed6398a2f61168449 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Wed, 1 Dec 2021 18:50:42 +0100 Subject: [PATCH 11/77] [DSC-287] Fixed for yarn start error 500 loading --- .../page-internal-server-error.component.ts | 21 +------------------ src/app/root/root.component.ts | 4 ++++ 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts index 2c4e37d30f..b2dc70dbdf 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.ts +++ b/src/app/page-internal-server-error/page-internal-server-error.component.ts @@ -1,6 +1,5 @@ import { ServerResponseService } from '../core/services/server-response.service'; import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; -import { AuthService } from '../core/auth/auth.service'; /** * This component representing the `PageNotFound` DSpace page. @@ -11,23 +10,5 @@ import { AuthService } from '../core/auth/auth.service'; templateUrl: './page-internal-server-error.component.html', changeDetection: ChangeDetectionStrategy.Default }) -export class PageInternalServerErrorComponent implements OnInit { - - /** - * Initialize instance variables - * - * @param {AuthService} authservice - * @param {ServerResponseService} responseService - */ - constructor(private authservice: AuthService, private responseService: ServerResponseService) { - this.responseService.setNotFound(); - } - - /** - * Remove redirect url from the state - */ - ngOnInit(): void { - this.authservice.clearRedirectUrl(); - } - +export class PageInternalServerErrorComponent { } diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index 209f17b520..b70573e42b 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -71,5 +71,9 @@ export class RootComponent implements OnInit { .pipe( map(([collapsed, mobile]) => collapsed || mobile) ); + + if (this.router.url === '/500') { + this.shouldShowRouteLoader = false; + } } } From ed2c774d86b71ca09c3e286a448650311bf97aca Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 2 Dec 2021 12:39:07 +0100 Subject: [PATCH 12/77] 85262: Allow empty patch requests --- .../json-patch-operations.service.ts | 16 ++++++---- .../submission-form-footer.component.spec.ts | 9 ++++++ .../submission-objects.effects.spec.ts | 30 +++++++++++++++++++ .../objects/submission-objects.effects.ts | 3 +- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/app/core/json-patch/json-patch-operations.service.ts b/src/app/core/json-patch/json-patch-operations.service.ts index c3363f4db4..f160376837 100644 --- a/src/app/core/json-patch/json-patch-operations.service.ts +++ b/src/app/core/json-patch/json-patch-operations.service.ts @@ -40,13 +40,15 @@ export abstract class JsonPatchOperationsService * observable of response */ - protected submitJsonPatchOperations(hrefObs: Observable, resourceType: string, resourceId?: string): Observable { + protected submitJsonPatchOperations(hrefObs: Observable, resourceType: string, resourceId?: string, allowEmptyRequest = false): Observable { const requestId = this.requestService.generateRequestId(); let startTransactionTime = null; - const [patchRequest$, emptyRequest$] = partition((request: PatchRequestDefinition) => isNotEmpty(request.body))(hrefObs.pipe( + const [patchRequest$, emptyRequest$] = partition((request: PatchRequestDefinition) => allowEmptyRequest || isNotEmpty(request.body))(hrefObs.pipe( mergeMap((endpointURL: string) => { return this.store.select(jsonPatchOperationsByResourceType(resourceType)).pipe( take(1), @@ -79,11 +81,11 @@ export abstract class JsonPatchOperationsService isEmpty(request.body)), + filter((request: PatchRequestDefinition) => !allowEmptyRequest && isEmpty(request.body)), tap(() => startTransactionTime = null), map(() => null)), patchRequest$.pipe( - filter((request: PatchRequestDefinition) => isNotEmpty(request.body)), + filter((request: PatchRequestDefinition) => allowEmptyRequest || isNotEmpty(request.body)), tap(() => this.store.dispatch(new StartTransactionPatchOperationsAction(resourceType, resourceId, startTransactionTime))), tap((request: PatchRequestDefinition) => this.requestService.send(request)), mergeMap(() => { @@ -141,16 +143,18 @@ export abstract class JsonPatchOperationsService * observable of response */ - public jsonPatchByResourceType(linkPath: string, scopeId: string, resourceType: string): Observable { + public jsonPatchByResourceType(linkPath: string, scopeId: string, resourceType: string, allowEmptyRequest = false): Observable { const href$ = this.halService.getEndpoint(linkPath).pipe( filter((href: string) => isNotEmpty(href)), distinctUntilChanged(), map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId))); - return this.submitJsonPatchOperations(href$, resourceType); + return this.submitJsonPatchOperations(href$, resourceType, undefined, allowEmptyRequest); } /** diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index dbeb4ee00d..072f826deb 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -201,6 +201,15 @@ describe('SubmissionFormFooterComponent Component', () => { }); }); + it('should not have deposit button disabled when submission is not valid', () => { + comp.showDepositAndDiscard = observableOf(true); + compAsAny.submissionIsInvalid = observableOf(true); + fixture.detectChanges(); + const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); + + expect(depositBtn.nativeElement.disabled).toBeFalsy(); + }); + it('should not have deposit button disabled when submission is valid', () => { comp.showDepositAndDiscard = observableOf(true); compAsAny.submissionIsInvalid = observableOf(false); diff --git a/src/app/submission/objects/submission-objects.effects.spec.ts b/src/app/submission/objects/submission-objects.effects.spec.ts index 8e763fd94b..e760f71941 100644 --- a/src/app/submission/objects/submission-objects.effects.spec.ts +++ b/src/app/submission/objects/submission-objects.effects.spec.ts @@ -879,6 +879,36 @@ describe('SubmissionObjectEffects test suite', () => { expect(submissionObjectEffects.saveAndDeposit$).toBeObservable(expected); }); + it('should return a SAVE_SUBMISSION_FORM_SUCCESS action when there are errors', () => { + store.nextState({ + submission: { + objects: submissionState + } + } as any); + + actions = hot('--a-', { + a: { + type: SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION, + payload: { + submissionId: submissionId + } + } + }); + + const response = [Object.assign({}, mockSubmissionRestResponse[0], { + sections: mockSectionsData, + errors: mockSectionsErrors + })]; + + submissionJsonPatchOperationsServiceStub.jsonPatchByResourceType.and.returnValue(observableOf(response)); + + const expected = cold('--b-', { + b: new SaveSubmissionFormSuccessAction(submissionId, response as any[]) + }); + + expect(submissionObjectEffects.saveAndDeposit$).toBeObservable(expected); + }); + it('should catch errors and return a SAVE_SUBMISSION_FORM_ERROR', () => { actions = hot('--a-', { a: { diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index 535e662922..5432aa7a4c 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -201,7 +201,8 @@ export class SubmissionObjectEffects { return this.operationsService.jsonPatchByResourceType( this.submissionService.getSubmissionObjectLinkName(), action.payload.submissionId, - 'sections').pipe( + 'sections', + true).pipe( map((response: SubmissionObject[]) => { if (this.canDeposit(response)) { return new DepositSubmissionAction(action.payload.submissionId); From 768de1a1e73a585dfb50f3f1eb6d09b04dbcde06 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Fri, 3 Dec 2021 10:54:41 -0500 Subject: [PATCH 13/77] w2p-85346 Allow facets to be authority controlled and add test to verify --- src/app/shared/search/facet-value.model.ts | 6 ++++++ src/app/shared/search/search.utils.spec.ts | 10 ++++++++++ src/app/shared/search/search.utils.ts | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/src/app/shared/search/facet-value.model.ts b/src/app/shared/search/facet-value.model.ts index 969e531bd2..935190743d 100644 --- a/src/app/shared/search/facet-value.model.ts +++ b/src/app/shared/search/facet-value.model.ts @@ -24,6 +24,12 @@ export class FacetValue implements HALResource { @autoserialize count: number; + /** + * The Authority Value for this facet + */ + @autoserialize + authorityKey?: string; + /** * The {@link HALLink}s for this FacetValue */ diff --git a/src/app/shared/search/search.utils.spec.ts b/src/app/shared/search/search.utils.spec.ts index ca4b4894b1..40f1328ffe 100644 --- a/src/app/shared/search/search.utils.spec.ts +++ b/src/app/shared/search/search.utils.spec.ts @@ -12,6 +12,7 @@ describe('Search Utils', () => { let facetValueWithSearchHref: FacetValue; let facetValueWithoutSearchHref: FacetValue; let searchFilterConfig: SearchFilterConfig; + let facetValueWithSearchHrefAuthority: FacetValue; beforeEach(() => { facetValueWithSearchHref = Object.assign(new FacetValue(), { @@ -22,6 +23,11 @@ describe('Search Utils', () => { } } }); + facetValueWithSearchHrefAuthority = Object.assign(new FacetValue(), { + value: 'Value with search href', + authorityKey: 'uuid', + } + ); facetValueWithoutSearchHref = Object.assign(new FacetValue(), { value: 'Value without search href' }); @@ -34,6 +40,10 @@ describe('Search Utils', () => { expect(getFacetValueForType(facetValueWithSearchHref, searchFilterConfig)).toEqual('Value with search href,operator'); }); + it('should retrieve the correct value from the Facet', () => { + expect(getFacetValueForType(facetValueWithSearchHrefAuthority, searchFilterConfig)).toEqual('uuid,authority'); + }); + it('should return the facet value with an equals operator by default', () => { expect(getFacetValueForType(facetValueWithoutSearchHref, searchFilterConfig)).toEqual('Value without search href,equals'); }); diff --git a/src/app/shared/search/search.utils.ts b/src/app/shared/search/search.utils.ts index 38c5f568cb..2b9944562a 100644 --- a/src/app/shared/search/search.utils.ts +++ b/src/app/shared/search/search.utils.ts @@ -16,6 +16,10 @@ export function getFacetValueForType(facetValue: FacetValue, searchFilterConfig: return values[1]; } } + if (facetValue.authorityKey) { + return addOperatorToFilterValue(facetValue.authorityKey, 'authority'); + } + return addOperatorToFilterValue(facetValue.value, 'equals'); } From d3b5e09e2ac39f1382ea28eb1eb5d848b7acf328 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 9 Dec 2021 17:48:59 +0100 Subject: [PATCH 14/77] [DSC-287] remove unused imports --- .../page-internal-server-error.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts index b2dc70dbdf..09b441969a 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.ts +++ b/src/app/page-internal-server-error/page-internal-server-error.component.ts @@ -1,5 +1,4 @@ -import { ServerResponseService } from '../core/services/server-response.service'; -import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; /** * This component representing the `PageNotFound` DSpace page. From 549529c8896b5e14e4ce6798fb30d52d35b56f8f Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 10 Dec 2021 14:18:51 +0100 Subject: [PATCH 15/77] 85262: Get submission object instead of sending empty patch + revert empty patch code --- .../json-patch-operations.service.ts | 16 +++++--------- .../submission-objects.effects.spec.ts | 7 ++++++ .../objects/submission-objects.effects.ts | 22 +++++++++++++------ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/app/core/json-patch/json-patch-operations.service.ts b/src/app/core/json-patch/json-patch-operations.service.ts index f160376837..c3363f4db4 100644 --- a/src/app/core/json-patch/json-patch-operations.service.ts +++ b/src/app/core/json-patch/json-patch-operations.service.ts @@ -40,15 +40,13 @@ export abstract class JsonPatchOperationsService * observable of response */ - protected submitJsonPatchOperations(hrefObs: Observable, resourceType: string, resourceId?: string, allowEmptyRequest = false): Observable { + protected submitJsonPatchOperations(hrefObs: Observable, resourceType: string, resourceId?: string): Observable { const requestId = this.requestService.generateRequestId(); let startTransactionTime = null; - const [patchRequest$, emptyRequest$] = partition((request: PatchRequestDefinition) => allowEmptyRequest || isNotEmpty(request.body))(hrefObs.pipe( + const [patchRequest$, emptyRequest$] = partition((request: PatchRequestDefinition) => isNotEmpty(request.body))(hrefObs.pipe( mergeMap((endpointURL: string) => { return this.store.select(jsonPatchOperationsByResourceType(resourceType)).pipe( take(1), @@ -81,11 +79,11 @@ export abstract class JsonPatchOperationsService !allowEmptyRequest && isEmpty(request.body)), + filter((request: PatchRequestDefinition) => isEmpty(request.body)), tap(() => startTransactionTime = null), map(() => null)), patchRequest$.pipe( - filter((request: PatchRequestDefinition) => allowEmptyRequest || isNotEmpty(request.body)), + filter((request: PatchRequestDefinition) => isNotEmpty(request.body)), tap(() => this.store.dispatch(new StartTransactionPatchOperationsAction(resourceType, resourceId, startTransactionTime))), tap((request: PatchRequestDefinition) => this.requestService.send(request)), mergeMap(() => { @@ -143,18 +141,16 @@ export abstract class JsonPatchOperationsService * observable of response */ - public jsonPatchByResourceType(linkPath: string, scopeId: string, resourceType: string, allowEmptyRequest = false): Observable { + public jsonPatchByResourceType(linkPath: string, scopeId: string, resourceType: string): Observable { const href$ = this.halService.getEndpoint(linkPath).pipe( filter((href: string) => isNotEmpty(href)), distinctUntilChanged(), map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId))); - return this.submitJsonPatchOperations(href$, resourceType, undefined, allowEmptyRequest); + return this.submitJsonPatchOperations(href$, resourceType); } /** diff --git a/src/app/submission/objects/submission-objects.effects.spec.ts b/src/app/submission/objects/submission-objects.effects.spec.ts index e760f71941..b2bc054287 100644 --- a/src/app/submission/objects/submission-objects.effects.spec.ts +++ b/src/app/submission/objects/submission-objects.effects.spec.ts @@ -54,6 +54,8 @@ import { Item } from '../../core/shared/item.model'; import { WorkspaceitemDataService } from '../../core/submission/workspaceitem-data.service'; import { WorkflowItemDataService } from '../../core/submission/workflowitem-data.service'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; +import { SubmissionObjectDataService } from '../../core/submission/submission-object-data.service'; +import { mockSubmissionObjectDataService } from '../../shared/testing/submission-oject-data-service.mock'; describe('SubmissionObjectEffects test suite', () => { let submissionObjectEffects: SubmissionObjectEffects; @@ -63,6 +65,7 @@ describe('SubmissionObjectEffects test suite', () => { let notificationsServiceStub; let submissionServiceStub; let submissionJsonPatchOperationsServiceStub; + let submissionObjectDataServiceStub; const collectionId: string = mockSubmissionCollectionId; const submissionId: string = mockSubmissionId; const submissionDefinitionResponse: any = mockSubmissionDefinitionResponse; @@ -75,6 +78,9 @@ describe('SubmissionObjectEffects test suite', () => { notificationsServiceStub = new NotificationsServiceStub(); submissionServiceStub = new SubmissionServiceStub(); submissionJsonPatchOperationsServiceStub = new SubmissionJsonPatchOperationsServiceStub(); + submissionObjectDataServiceStub = mockSubmissionObjectDataService; + + submissionServiceStub.hasUnsavedModification.and.returnValue(observableOf(true)); TestBed.configureTestingModule({ imports: [ @@ -99,6 +105,7 @@ describe('SubmissionObjectEffects test suite', () => { { provide: WorkflowItemDataService, useValue: {} }, { provide: WorkflowItemDataService, useValue: {} }, { provide: HALEndpointService, useValue: {} }, + { provide: SubmissionObjectDataService, useValue: submissionObjectDataServiceStub }, ], }); diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index 5432aa7a4c..257854f027 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -196,13 +196,21 @@ export class SubmissionObjectEffects { */ @Effect() saveAndDeposit$ = this.actions$.pipe( ofType(SubmissionObjectActionTypes.SAVE_AND_DEPOSIT_SUBMISSION), - withLatestFrom(this.store$), - switchMap(([action, currentState]: [SaveAndDepositSubmissionAction, any]) => { - return this.operationsService.jsonPatchByResourceType( - this.submissionService.getSubmissionObjectLinkName(), - action.payload.submissionId, - 'sections', - true).pipe( + withLatestFrom(this.submissionService.hasUnsavedModification()), + switchMap(([action, hasUnsavedModification]: [SaveAndDepositSubmissionAction, boolean]) => { + let response$: Observable; + if (hasUnsavedModification) { + response$ = this.operationsService.jsonPatchByResourceType( + this.submissionService.getSubmissionObjectLinkName(), + action.payload.submissionId, + 'sections') as Observable; + } else { + response$ = this.submissionObjectService.findById(action.payload.submissionId).pipe( + getFirstSucceededRemoteDataPayload(), + map((submissionObject: SubmissionObject) => [submissionObject]) + ); + } + return response$.pipe( map((response: SubmissionObject[]) => { if (this.canDeposit(response)) { return new DepositSubmissionAction(action.payload.submissionId); From e2614b9dadcd17ce84b809518c783dda3a6a75dc Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 13 Dec 2021 13:48:09 -0500 Subject: [PATCH 16/77] w2p-85847 Add Authority to browse indexes --- .../browse-by-date-page.component.ts | 2 +- .../browse-by-metadata-page.component.ts | 12 +++++++++--- .../browse-by-title-page.component.ts | 2 +- src/app/core/browse/browse.service.spec.ts | 17 ++++++++++++++++- src/app/core/browse/browse.service.ts | 5 ++++- .../browse-entry-list-element.component.html | 2 +- .../browse-entry-list-element.component.ts | 14 +++++++++++++- 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 3158c3d7cc..2b1cd21f14 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -63,7 +63,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { this.browseId = params.id || this.defaultBrowseId; this.startsWith = +params.startsWith || params.startsWith; const searchOptions = browseParamsToOptions(params, currentPage, currentSort, this.browseId); - this.updatePageWithItems(searchOptions, this.value); + this.updatePageWithItems(searchOptions, this.value, undefined); this.updateParent(params.scope); this.updateStartsWithOptions(this.browseId, metadataField, params.scope); })); diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 3573ffb264..c6716afb5f 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -99,6 +99,11 @@ export class BrowseByMetadataPageComponent implements OnInit { */ value = ''; + /** + * The authority key (may be undefined) associated with {@link #value}. + */ + authority: string; + /** * The current startsWith option (fetched and updated from query-params) */ @@ -123,11 +128,12 @@ export class BrowseByMetadataPageComponent implements OnInit { }) ).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { this.browseId = params.id || this.defaultBrowseId; + this.authority = params.authority; this.value = +params.value || params.value || ''; this.startsWith = +params.startsWith || params.startsWith; const searchOptions = browseParamsToOptions(params, currentPage, currentSort, this.browseId); if (isNotEmpty(this.value)) { - this.updatePageWithItems(searchOptions, this.value); + this.updatePageWithItems(searchOptions, this.value, this.authority); } else { this.updatePage(searchOptions); } @@ -166,8 +172,8 @@ export class BrowseByMetadataPageComponent implements OnInit { * scope: string } * @param value The value of the browse-entry to display items for */ - updatePageWithItems(searchOptions: BrowseEntrySearchOptions, value: string) { - this.items$ = this.browseService.getBrowseItemsFor(value, searchOptions); + updatePageWithItems(searchOptions: BrowseEntrySearchOptions, value: string, authority: string) { + this.items$ = this.browseService.getBrowseItemsFor(value, authority, searchOptions); } /** diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index b3a2ceed00..a2fcce7bce 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -46,7 +46,7 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { }) ).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { this.browseId = params.id || this.defaultBrowseId; - this.updatePageWithItems(browseParamsToOptions(params, currentPage, currentSort, this.browseId), undefined); + this.updatePageWithItems(browseParamsToOptions(params, currentPage, currentSort, this.browseId), undefined, undefined); this.updateParent(params.scope); })); this.updateStartsWithTextOptions(); diff --git a/src/app/core/browse/browse.service.spec.ts b/src/app/core/browse/browse.service.spec.ts index a28add2e30..ac68fadb31 100644 --- a/src/app/core/browse/browse.service.spec.ts +++ b/src/app/core/browse/browse.service.spec.ts @@ -129,6 +129,7 @@ describe('BrowseService', () => { describe('getBrowseEntriesFor and findList', () => { // should contain special characters such that url encoding can be tested as well const mockAuthorName = 'Donald Smith & Sons'; + const mockAuthorityKey = 'some authority key ?=;'; beforeEach(() => { requestService = getMockRequestService(getRequestEntry$(true)); @@ -155,7 +156,7 @@ describe('BrowseService', () => { it('should call hrefOnlyDataService.findAllByHref with the expected href', () => { const expected = browseDefinitions[1]._links.items.href + '?filterValue=' + encodeURIComponent(mockAuthorName); - scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); + scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, undefined, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); scheduler.flush(); expect(getFirstUsedArgumentOfSpyMethod(hrefOnlyDataService.findAllByHref)).toBeObservable(cold('(a|)', { @@ -164,6 +165,20 @@ describe('BrowseService', () => { }); }); + describe('when getBrowseItemsFor is called with a valid filter value and authority key', () => { + it('should call hrefOnlyDataService.findAllByHref with the expected href', () => { + const expected = browseDefinitions[1]._links.items.href + + '?filterValue=' + encodeURIComponent(mockAuthorName) + + '&filterAuthority=' + encodeURIComponent(mockAuthorityKey); + + scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, mockAuthorityKey, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); + scheduler.flush(); + + expect(getFirstUsedArgumentOfSpyMethod(hrefOnlyDataService.findAllByHref)).toBeObservable(cold('(a|)', { + a: expected + })); + }); + }); }); describe('getBrowseURLFor', () => { diff --git a/src/app/core/browse/browse.service.ts b/src/app/core/browse/browse.service.ts index ffc6f313b9..05e625d6c1 100644 --- a/src/app/core/browse/browse.service.ts +++ b/src/app/core/browse/browse.service.ts @@ -105,7 +105,7 @@ export class BrowseService { * @param options Options to narrow down your search * @returns {Observable>>} */ - getBrowseItemsFor(filterValue: string, options: BrowseEntrySearchOptions): Observable>> { + getBrowseItemsFor(filterValue: string, filterAuthority: string, options: BrowseEntrySearchOptions): Observable>> { const href$ = this.getBrowseDefinitions().pipe( getBrowseDefinitionLinks(options.metadataDefinition), hasValueOperator(), @@ -132,6 +132,9 @@ export class BrowseService { if (isNotEmpty(filterValue)) { args.push(`filterValue=${encodeURIComponent(filterValue)}`); } + if (isNotEmpty(filterAuthority)) { + args.push(`filterAuthority=${encodeURIComponent(filterAuthority)}`); + } if (isNotEmpty(args)) { href = new URLCombiner(href, `?${args.join('&')}`).toString(); } diff --git a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html index e3455bf095..8577ee654c 100644 --- a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html +++ b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html @@ -1,5 +1,5 @@
- + {{object.value}} diff --git a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts index 1b0f1eef37..cfdf561f99 100644 --- a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts +++ b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts @@ -15,4 +15,16 @@ import { listableObjectComponent } from '../../object-collection/shared/listable * This component is automatically used to create a list view for BrowseEntry objects when used in ObjectCollectionComponent */ @listableObjectComponent(BrowseEntry, ViewMode.ListElement) -export class BrowseEntryListElementComponent extends AbstractListableElementComponent {} +export class BrowseEntryListElementComponent extends AbstractListableElementComponent { + + /** + * Get the query params to access the item page of this browse entry. + */ + public getQueryParams(): {[param: string]: any} { + return { + value: this.object.value, + authority: !!this.object.authority ? this.object.authority : undefined, + startsWith: undefined, + }; + } +} From b6904a4df90e9bb4e86ffc3bcadb20f34c531ae5 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 14 Dec 2021 12:40:51 +0100 Subject: [PATCH 17/77] [DSC-287] add link button to home page --- .../page-internal-server-error.component.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.html b/src/app/page-internal-server-error/page-internal-server-error.component.html index 8e30236c4f..09b499b496 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.html +++ b/src/app/page-internal-server-error/page-internal-server-error.component.html @@ -4,4 +4,7 @@

{{"500.help" | translate}}


-
\ No newline at end of file +

+ {{"500.link.home-page" | translate}} +

+ From ddcb1ecdf23c2f3310bba303a4bc929c117b801f Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 14 Dec 2021 12:42:24 +0100 Subject: [PATCH 18/77] [DSC-287] invalidate root endpoint cache when redirected to 500 page in order to check every time the rest server availability --- src/app/core/data/root-data.service.ts | 7 +++++++ src/app/core/server-check/server-check.guard.ts | 1 + 2 files changed, 8 insertions(+) diff --git a/src/app/core/data/root-data.service.ts b/src/app/core/data/root-data.service.ts index 8b4e836671..ce1b33a9e3 100644 --- a/src/app/core/data/root-data.service.ts +++ b/src/app/core/data/root-data.service.ts @@ -106,5 +106,12 @@ export class RootDataService { findAllByHref(href: string | Observable, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.dataService.findAllByHref(href, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } + + /** + * Set to sale the root endpoint cache hit + */ + invalidateRootCache() { + this.requestService.setStaleByHrefSubstring('server/api'); + } } /* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index b7982eee9a..017b75d373 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -32,6 +32,7 @@ export class ServerCheckGuard implements CanActivate { map((res: RemoteData) => res.hasSucceeded), tap((hasSucceeded: boolean) => { if (!hasSucceeded) { + this.rootDataService.invalidateRootCache(); this.router.navigateByUrl(getPageInternalServerErrorRoute()); } }), From 44fc86c9fe76fda5d6f18fab4786ebaae878fc93 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 14 Dec 2021 15:22:55 +0100 Subject: [PATCH 19/77] [DSC-287] use CanActivateChild in order to check every time the rest server availability --- src/app/app-routing.module.ts | 4 +++- src/app/core/server-check/server-check.guard.spec.ts | 9 ++++++--- src/app/core/server-check/server-check.guard.ts | 8 ++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3a47815f42..4a9810e4da 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -36,7 +36,9 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; RouterModule.forRoot([ { path: INTERNAL_SERVER_ERROR, component: ThemedPageInternalServerErrorComponent }, { - path: '', canActivate: [ServerCheckGuard, AuthBlockingGuard], + path: '', + canActivate: [AuthBlockingGuard], + canActivateChild: [ServerCheckGuard], children: [ { path: '', redirectTo: '/home', pathMatch: 'full' }, { diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts index a9c03d1cd7..749912be85 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -13,7 +13,8 @@ describe('ServerCheckGuard', () => { let rootDataServiceStub: SpyObj; rootDataServiceStub = jasmine.createSpyObj('RootDataService', { - findRoot: jasmine.createSpy('findRoot') + findRoot: jasmine.createSpy('findRoot'), + invalidateRootCache: jasmine.createSpy('invalidateRootCache') }); router = jasmine.createSpyObj('Router', { navigateByUrl: jasmine.createSpy('navigateByUrl') @@ -37,10 +38,11 @@ describe('ServerCheckGuard', () => { }); it('should not redirect to error page', () => { - guard.canActivate({} as any, {} as any).pipe( + guard.canActivateChild({} as any, {} as any).pipe( take(1) ).subscribe((canActivate: boolean) => { expect(canActivate).toEqual(true); + expect(rootDataServiceStub.invalidateRootCache).not.toHaveBeenCalled(); expect(router.navigateByUrl).not.toHaveBeenCalled(); }); }); @@ -52,10 +54,11 @@ describe('ServerCheckGuard', () => { }); it('should redirect to error page', () => { - guard.canActivate({} as any, {} as any).pipe( + guard.canActivateChild({} as any, {} as any).pipe( take(1) ).subscribe((canActivate: boolean) => { expect(canActivate).toEqual(false); + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalled(); expect(router.navigateByUrl).toHaveBeenCalledWith(getPageInternalServerErrorRoute()); }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 017b75d373..af216bef0e 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { map, tap } from 'rxjs/operators'; @@ -16,18 +16,18 @@ import { getFirstCompletedRemoteData } from '../shared/operators'; * A guard that checks if root api endpoint is reachable. * If not redirect to 500 error page */ -export class ServerCheckGuard implements CanActivate { +export class ServerCheckGuard implements CanActivateChild { constructor(private router: Router, private rootDataService: RootDataService) { } /** * True when root api endpoint is reachable. */ - canActivate( + canActivateChild( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.rootDataService.findRoot().pipe( + return this.rootDataService.findRoot(false).pipe( getFirstCompletedRemoteData(), map((res: RemoteData) => res.hasSucceeded), tap((hasSucceeded: boolean) => { From d426f5f17985c579e08177a998434a503a455bfd Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 14 Dec 2021 15:47:30 +0100 Subject: [PATCH 20/77] [DSC-287] fix test --- src/app/core/server-check/server-check.guard.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts index 749912be85..30d07234a3 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -26,6 +26,8 @@ describe('ServerCheckGuard', () => { afterEach(() => { router.navigateByUrl.calls.reset(); + rootDataServiceStub.invalidateRootCache.calls.reset(); + rootDataServiceStub.findRoot.calls.reset(); }); it('should be created', () => { From 71e40fdb6ef3d6e63b6232eee5dc333af2aaff3c Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 15 Dec 2021 14:04:38 +0100 Subject: [PATCH 21/77] 85979: only show security tab on profile page when canChangePassword FeatureID is true --- src/app/core/data/feature-authorization/feature-id.ts | 1 + src/app/profile-page/profile-page.component.html | 2 +- src/app/profile-page/profile-page.component.ts | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/core/data/feature-authorization/feature-id.ts b/src/app/core/data/feature-authorization/feature-id.ts index 15eba0e5db..b64de5100b 100644 --- a/src/app/core/data/feature-authorization/feature-id.ts +++ b/src/app/core/data/feature-authorization/feature-id.ts @@ -13,6 +13,7 @@ export enum FeatureID { CanManageGroup = 'canManageGroup', IsCollectionAdmin = 'isCollectionAdmin', IsCommunityAdmin = 'isCommunityAdmin', + CanChangePassword = 'canChangePassword', CanDownload = 'canDownload', CanRequestACopy = 'canRequestACopy', CanManageVersions = 'canManageVersions', diff --git a/src/app/profile-page/profile-page.component.html b/src/app/profile-page/profile-page.component.html index 619e4a2411..95d2be1274 100644 --- a/src/app/profile-page/profile-page.component.html +++ b/src/app/profile-page/profile-page.component.html @@ -7,7 +7,7 @@ -
+
{{'profile.card.security' | translate}}
; constructor(private authService: AuthService, private notificationsService: NotificationsService, private translate: TranslateService, - private epersonService: EPersonDataService) { + private epersonService: EPersonDataService, + private authorizationService: AuthorizationDataService) { } ngOnInit(): void { @@ -83,6 +87,7 @@ export class ProfilePageComponent implements OnInit { tap((user: EPerson) => this.currentUser = user) ); this.groupsRD$ = this.user$.pipe(switchMap((user: EPerson) => user.groups)); + this.canChangePassword$ = this.user$.pipe(switchMap((user:EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href))); } /** From 2f022f505dd8c1543e77ab5b57287eebd5cf41c2 Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 15 Dec 2021 14:41:10 +0100 Subject: [PATCH 22/77] 85979: tests for canChangePassword UI changes --- .../profile-page/profile-page.component.html | 2 +- .../profile-page.component.spec.ts | 46 +++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/app/profile-page/profile-page.component.html b/src/app/profile-page/profile-page.component.html index 95d2be1274..ccfae0bba1 100644 --- a/src/app/profile-page/profile-page.component.html +++ b/src/app/profile-page/profile-page.component.html @@ -7,7 +7,7 @@
-
+
{{'profile.card.security' | translate}}
{ let component: ProfilePageComponent; @@ -28,10 +31,13 @@ describe('ProfilePageComponent', () => { let epersonService; let notificationsService; + let canChangePassword = new BehaviorSubject(true); + function init() { user = Object.assign(new EPerson(), { id: 'userId', - groups: createSuccessfulRemoteDataObject$(createPaginatedList([])) + groups: createSuccessfulRemoteDataObject$(createPaginatedList([])), + _links: {self: {href: 'test.com/uuid/1234567654321'}} }); initialState = { core: { @@ -74,6 +80,7 @@ describe('ProfilePageComponent', () => { { provide: EPersonDataService, useValue: epersonService }, { provide: NotificationsService, useValue: notificationsService }, { provide: AuthService, useValue: authService }, + { provide: AuthorizationDataService, useValue: jasmine.createSpyObj('authorizationService', { isAuthorized: canChangePassword }) }, provideMockStore({ initialState }), ], schemas: [NO_ERRORS_SCHEMA] @@ -183,7 +190,7 @@ describe('ProfilePageComponent', () => { component.setPasswordValue('testest'); component.setInvalid(false); - operations = [{op: 'add', path: '/password', value: 'testest'}]; + operations = [{ op: 'add', path: '/password', value: 'testest' }]; result = component.updateSecurity(); }); @@ -196,4 +203,35 @@ describe('ProfilePageComponent', () => { }); }); }); + + describe('canChangePassword$', () => { + describe('when the user is allowed to change their password', () => { + beforeEach(() => { + canChangePassword.next(true); + }); + + it('should contain true', () => { + getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: true }); + }); + + it('should show the security section on the page', () => { + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('.security-section'))).not.toBeNull(); + }); + }); + + describe('when the user is not allowed to change their password', () => { + beforeEach(() => { + canChangePassword.next(false); + }); + + it('should contain false', () => { + getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: false }); + }); + + it('should not show the security section on the page', fakeAsync(() => { + expect(fixture.debugElement.query(By.css('.security-section'))).toBeNull(); + })); + }); + }); }); From 6594a3877fc1c3dfe258d048449eae87abcde34f Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 15 Dec 2021 15:13:27 +0100 Subject: [PATCH 23/77] fixed lint/lgtm issues --- src/app/profile-page/profile-page.component.spec.ts | 4 ++-- src/app/profile-page/profile-page.component.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/profile-page/profile-page.component.spec.ts b/src/app/profile-page/profile-page.component.spec.ts index adffe527d1..c7b644375c 100644 --- a/src/app/profile-page/profile-page.component.spec.ts +++ b/src/app/profile-page/profile-page.component.spec.ts @@ -1,5 +1,5 @@ import { ProfilePageComponent } from './profile-page.component'; -import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing'; import { VarDirective } from '../shared/utils/var.directive'; import { TranslateModule } from '@ngx-translate/core'; import { RouterTestingModule } from '@angular/router/testing'; @@ -31,7 +31,7 @@ describe('ProfilePageComponent', () => { let epersonService; let notificationsService; - let canChangePassword = new BehaviorSubject(true); + const canChangePassword = new BehaviorSubject(true); function init() { user = Object.assign(new EPerson(), { diff --git a/src/app/profile-page/profile-page.component.ts b/src/app/profile-page/profile-page.component.ts index 271b0277da..fece166a59 100644 --- a/src/app/profile-page/profile-page.component.ts +++ b/src/app/profile-page/profile-page.component.ts @@ -87,7 +87,7 @@ export class ProfilePageComponent implements OnInit { tap((user: EPerson) => this.currentUser = user) ); this.groupsRD$ = this.user$.pipe(switchMap((user: EPerson) => user.groups)); - this.canChangePassword$ = this.user$.pipe(switchMap((user:EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href))); + this.canChangePassword$ = this.user$.pipe(switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href))); } /** From dd69bc65ab6938aaf2684c597f3a3f246ac4ea2c Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 15 Dec 2021 16:21:09 +0100 Subject: [PATCH 24/77] Fixes to tests --- src/app/profile-page/profile-page.component.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/profile-page/profile-page.component.spec.ts b/src/app/profile-page/profile-page.component.spec.ts index c7b644375c..ce7f2f1acb 100644 --- a/src/app/profile-page/profile-page.component.spec.ts +++ b/src/app/profile-page/profile-page.component.spec.ts @@ -204,7 +204,7 @@ describe('ProfilePageComponent', () => { }); }); - describe('canChangePassword$', () => { + fdescribe('canChangePassword$', () => { describe('when the user is allowed to change their password', () => { beforeEach(() => { canChangePassword.next(true); @@ -229,9 +229,10 @@ describe('ProfilePageComponent', () => { getTestScheduler().expectObservable(component.canChangePassword$).toBe('(a)', { a: false }); }); - it('should not show the security section on the page', fakeAsync(() => { + it('should not show the security section on the page', () => { + fixture.detectChanges(); expect(fixture.debugElement.query(By.css('.security-section'))).toBeNull(); - })); + }); }); }); }); From b7d01127a536b6f8650ac331477351373e5229f1 Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 15 Dec 2021 16:21:55 +0100 Subject: [PATCH 25/77] Removed unnecessary import --- src/app/profile-page/profile-page.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/profile-page/profile-page.component.spec.ts b/src/app/profile-page/profile-page.component.spec.ts index ce7f2f1acb..59e62c6a16 100644 --- a/src/app/profile-page/profile-page.component.spec.ts +++ b/src/app/profile-page/profile-page.component.spec.ts @@ -1,5 +1,5 @@ import { ProfilePageComponent } from './profile-page.component'; -import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { VarDirective } from '../shared/utils/var.directive'; import { TranslateModule } from '@ngx-translate/core'; import { RouterTestingModule } from '@angular/router/testing'; From 7529fcde35cb5b6fe52676b47c1cafefc3429629 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 15 Dec 2021 16:46:40 +0100 Subject: [PATCH 26/77] remove fdescribe --- src/app/profile-page/profile-page.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/profile-page/profile-page.component.spec.ts b/src/app/profile-page/profile-page.component.spec.ts index 59e62c6a16..f48b894d8d 100644 --- a/src/app/profile-page/profile-page.component.spec.ts +++ b/src/app/profile-page/profile-page.component.spec.ts @@ -204,7 +204,7 @@ describe('ProfilePageComponent', () => { }); }); - fdescribe('canChangePassword$', () => { + describe('canChangePassword$', () => { describe('when the user is allowed to change their password', () => { beforeEach(() => { canChangePassword.next(true); From a4d91c37a7fc9e9d734bbd62864023628b26661c Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 15 Dec 2021 22:38:08 +0100 Subject: [PATCH 27/77] [CST-4633] Create search.module and resolve dependencies issues --- .../access-control/access-control.module.ts | 4 +- .../admin-registries.module.ts | 4 +- .../bitstream-formats.module.ts | 4 +- .../admin-search-page/admin-search.module.ts | 2 + .../admin-workflow.module.ts | 2 + src/app/admin/admin.module.ts | 2 +- .../bitstream-page/bitstream-page.module.ts | 6 +- src/app/browse-by/browse-by.module.ts | 2 + .../collection-form.component.ts | 6 +- .../collection-form/collection-form.module.ts | 4 + .../collection-page/collection-page.module.ts | 4 +- .../create-collection-page.component.ts | 4 +- .../delete-collection-page.component.ts | 4 +- .../collection-metadata.component.ts | 2 +- .../collection-roles.component.spec.ts | 2 + .../edit-collection-page.component.ts | 4 +- .../edit-collection-page.module.ts | 8 +- .../community-form.component.ts | 6 +- .../community-form/community-form.module.ts | 4 + .../community-page/community-page.module.ts | 4 +- .../create-community-page.component.ts | 2 +- .../delete-community-page.component.ts | 4 +- .../community-metadata.component.ts | 2 +- .../community-roles.component.spec.ts | 2 + .../edit-community-page.component.ts | 4 +- .../edit-community-page.module.ts | 6 +- .../journal-entities.module.ts | 2 + .../research-entities.module.ts | 8 +- .../edit-item-page/edit-item-page.module.ts | 9 +- src/app/item-page/item-shared.module.ts | 36 ++++ .../related-entities-search.component.ts | 2 +- .../my-dspace-page/my-dspace-page.module.ts | 2 + src/app/profile-page/profile-page.module.ts | 4 +- src/app/search-page/search-page.module.ts | 2 + .../comcol-form/comcol-form.component.html | 0 .../comcol-form/comcol-form.component.scss | 0 .../comcol-form/comcol-form.component.spec.ts | 22 +- .../comcol-form/comcol-form.component.ts | 50 ++--- .../create-comcol-page.component.spec.ts | 18 +- .../create-comcol-page.component.ts | 24 +-- .../delete-comcol-page.component.spec.ts | 16 +- .../delete-comcol-page.component.ts | 16 +- .../comcol-metadata.component.spec.ts | 12 +- .../comcol-metadata.component.ts | 18 +- .../comcol-role/comcol-role.component.html | 0 .../comcol-role/comcol-role.component.scss | 0 .../comcol-role/comcol-role.component.spec.ts | 10 +- .../comcol-role/comcol-role.component.ts | 22 +- .../edit-comcol-page.component.html | 0 .../edit-comcol-page.component.spec.ts | 6 +- .../edit-comcol-page.component.ts | 6 +- .../comcol-page-browse-by.component.html | 0 .../comcol-page-browse-by.component.scss | 0 .../comcol-page-browse-by.component.ts | 8 +- .../comcol-page-content.component.html | 0 .../comcol-page-content.component.scss | 0 .../comcol-page-content.component.ts | 0 .../comcol-page-handle.component.html | 0 .../comcol-page-handle.component.scss | 0 .../comcol-page-handle.component.spec.ts | 0 .../comcol-page-handle.component.ts | 0 .../comcol-page-header.component.html | 0 .../comcol-page-header.component.scss | 0 .../comcol-page-header.component.ts | 0 .../comcol-page-logo.component.html | 0 .../comcol-page-logo.component.scss | 0 .../comcol-page-logo.component.ts | 2 +- src/app/shared/comcol/comcol.module.ts | 42 ++++ src/app/shared/form/form.module.ts | 82 ++++++++ .../resource-policies.module.ts | 52 +++++ src/app/shared/search/search.module.ts | 103 +++++++++ src/app/shared/shared.module.ts | 196 ++---------------- src/app/submission/submission.module.ts | 22 +- src/themes/custom/theme.module.ts | 9 +- src/themes/dspace/theme.module.ts | 7 + 75 files changed, 568 insertions(+), 338 deletions(-) create mode 100644 src/app/item-page/item-shared.module.ts rename src/app/shared/{ => comcol}/comcol-forms/comcol-form/comcol-form.component.html (100%) rename src/app/shared/{ => comcol}/comcol-forms/comcol-form/comcol-form.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-forms/comcol-form/comcol-form.component.spec.ts (93%) rename src/app/shared/{ => comcol}/comcol-forms/comcol-form/comcol-form.component.ts (85%) rename src/app/shared/{ => comcol}/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts (90%) rename src/app/shared/{ => comcol}/comcol-forms/create-comcol-page/create-comcol-page.component.ts (77%) rename src/app/shared/{ => comcol}/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts (91%) rename src/app/shared/{ => comcol}/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts (80%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts (92%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts (79%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html (100%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts (94%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts (82%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/edit-comcol-page.component.html (100%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts (91%) rename src/app/shared/{ => comcol}/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts (90%) rename src/app/shared/{ => comcol}/comcol-page-browse-by/comcol-page-browse-by.component.html (100%) rename src/app/shared/{ => comcol}/comcol-page-browse-by/comcol-page-browse-by.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-page-browse-by/comcol-page-browse-by.component.ts (86%) rename src/app/shared/{ => comcol}/comcol-page-content/comcol-page-content.component.html (100%) rename src/app/shared/{ => comcol}/comcol-page-content/comcol-page-content.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-page-content/comcol-page-content.component.ts (100%) rename src/app/shared/{ => comcol}/comcol-page-handle/comcol-page-handle.component.html (100%) rename src/app/shared/{ => comcol}/comcol-page-handle/comcol-page-handle.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-page-handle/comcol-page-handle.component.spec.ts (100%) rename src/app/shared/{ => comcol}/comcol-page-handle/comcol-page-handle.component.ts (100%) rename src/app/shared/{ => comcol}/comcol-page-header/comcol-page-header.component.html (100%) rename src/app/shared/{ => comcol}/comcol-page-header/comcol-page-header.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-page-header/comcol-page-header.component.ts (100%) rename src/app/shared/{ => comcol}/comcol-page-logo/comcol-page-logo.component.html (100%) rename src/app/shared/{ => comcol}/comcol-page-logo/comcol-page-logo.component.scss (100%) rename src/app/shared/{ => comcol}/comcol-page-logo/comcol-page-logo.component.ts (95%) create mode 100644 src/app/shared/comcol/comcol.module.ts create mode 100644 src/app/shared/form/form.module.ts create mode 100644 src/app/shared/resource-policies/resource-policies.module.ts create mode 100644 src/app/shared/search/search.module.ts diff --git a/src/app/access-control/access-control.module.ts b/src/app/access-control/access-control.module.ts index 0e872458bd..891238bbed 100644 --- a/src/app/access-control/access-control.module.ts +++ b/src/app/access-control/access-control.module.ts @@ -9,13 +9,15 @@ import { GroupFormComponent } from './group-registry/group-form/group-form.compo import { MembersListComponent } from './group-registry/group-form/members-list/members-list.component'; import { SubgroupsListComponent } from './group-registry/group-form/subgroup-list/subgroups-list.component'; import { GroupsRegistryComponent } from './group-registry/groups-registry.component'; +import { FormModule } from '../shared/form/form.module'; @NgModule({ imports: [ CommonModule, SharedModule, RouterModule, - AccessControlRoutingModule + AccessControlRoutingModule, + FormModule ], declarations: [ EPeopleRegistryComponent, diff --git a/src/app/admin/admin-registries/admin-registries.module.ts b/src/app/admin/admin-registries/admin-registries.module.ts index 5c82bb2ec9..65f7b61419 100644 --- a/src/app/admin/admin-registries/admin-registries.module.ts +++ b/src/app/admin/admin-registries/admin-registries.module.ts @@ -8,6 +8,7 @@ import { SharedModule } from '../../shared/shared.module'; import { MetadataSchemaFormComponent } from './metadata-registry/metadata-schema-form/metadata-schema-form.component'; import { MetadataFieldFormComponent } from './metadata-schema/metadata-field-form/metadata-field-form.component'; import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.module'; +import { FormModule } from '../../shared/form/form.module'; @NgModule({ imports: [ @@ -15,7 +16,8 @@ import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.mo SharedModule, RouterModule, BitstreamFormatsModule, - AdminRegistriesRoutingModule + AdminRegistriesRoutingModule, + FormModule ], declarations: [ MetadataRegistryComponent, diff --git a/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.module.ts b/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.module.ts index 1667a07c0b..afbe35a1f6 100644 --- a/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.module.ts +++ b/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.module.ts @@ -7,13 +7,15 @@ import { FormatFormComponent } from './format-form/format-form.component'; import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component'; import { BitstreamFormatsRoutingModule } from './bitstream-formats-routing.module'; import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component'; +import { FormModule } from '../../../shared/form/form.module'; @NgModule({ imports: [ CommonModule, SharedModule, RouterModule, - BitstreamFormatsRoutingModule + BitstreamFormatsRoutingModule, + FormModule ], declarations: [ BitstreamFormatsComponent, diff --git a/src/app/admin/admin-search-page/admin-search.module.ts b/src/app/admin/admin-search-page/admin-search.module.ts index ecf8d8a2d2..353d6dd498 100644 --- a/src/app/admin/admin-search-page/admin-search.module.ts +++ b/src/app/admin/admin-search-page/admin-search.module.ts @@ -10,6 +10,7 @@ import { CollectionAdminSearchResultGridElementComponent } from './admin-search- import { ItemAdminSearchResultActionsComponent } from './admin-search-results/item-admin-search-result-actions.component'; import { JournalEntitiesModule } from '../../entity-groups/journal-entities/journal-entities.module'; import { ResearchEntitiesModule } from '../../entity-groups/research-entities/research-entities.module'; +import { SearchModule } from '../../shared/search/search.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -24,6 +25,7 @@ const ENTRY_COMPONENTS = [ @NgModule({ imports: [ + SearchModule, SharedModule.withEntryComponents(), JournalEntitiesModule.withEntryComponents(), ResearchEntitiesModule.withEntryComponents() diff --git a/src/app/admin/admin-workflow-page/admin-workflow.module.ts b/src/app/admin/admin-workflow-page/admin-workflow.module.ts index 02e5e01023..85e8f00a46 100644 --- a/src/app/admin/admin-workflow-page/admin-workflow.module.ts +++ b/src/app/admin/admin-workflow-page/admin-workflow.module.ts @@ -5,6 +5,7 @@ import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './adm import { WorkflowItemAdminWorkflowActionsComponent } from './admin-workflow-search-results/workflow-item-admin-workflow-actions.component'; import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component'; import { AdminWorkflowPageComponent } from './admin-workflow-page.component'; +import { SearchModule } from '../../shared/search/search.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -14,6 +15,7 @@ const ENTRY_COMPONENTS = [ @NgModule({ imports: [ + SearchModule, SharedModule.withEntryComponents() ], declarations: [ diff --git a/src/app/admin/admin.module.ts b/src/app/admin/admin.module.ts index 6c756dd851..b28a0cf89e 100644 --- a/src/app/admin/admin.module.ts +++ b/src/app/admin/admin.module.ts @@ -24,7 +24,7 @@ const ENTRY_COMPONENTS = [ AccessControlModule, AdminSearchModule.withEntryComponents(), AdminWorkflowModuleModule.withEntryComponents(), - SharedModule, + SharedModule ], declarations: [ AdminCurationTasksComponent, diff --git a/src/app/bitstream-page/bitstream-page.module.ts b/src/app/bitstream-page/bitstream-page.module.ts index 80e5ad14e3..d168a06db2 100644 --- a/src/app/bitstream-page/bitstream-page.module.ts +++ b/src/app/bitstream-page/bitstream-page.module.ts @@ -4,6 +4,8 @@ import { SharedModule } from '../shared/shared.module'; import { EditBitstreamPageComponent } from './edit-bitstream-page/edit-bitstream-page.component'; import { BitstreamPageRoutingModule } from './bitstream-page-routing.module'; import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bitstream-authorizations.component'; +import { FormModule } from '../shared/form/form.module'; +import { ResourcePoliciesModule } from '../shared/resource-policies/resource-policies.module'; /** * This module handles all components that are necessary for Bitstream related pages @@ -12,7 +14,9 @@ import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bit imports: [ CommonModule, SharedModule, - BitstreamPageRoutingModule + BitstreamPageRoutingModule, + FormModule, + ResourcePoliciesModule ], declarations: [ BitstreamAuthorizationsComponent, diff --git a/src/app/browse-by/browse-by.module.ts b/src/app/browse-by/browse-by.module.ts index cd44e52b81..e1dfaacea5 100644 --- a/src/app/browse-by/browse-by.module.ts +++ b/src/app/browse-by/browse-by.module.ts @@ -6,6 +6,7 @@ import { BrowseByMetadataPageComponent } from './browse-by-metadata-page/browse- import { BrowseByDatePageComponent } from './browse-by-date-page/browse-by-date-page.component'; import { BrowseBySwitcherComponent } from './browse-by-switcher/browse-by-switcher.component'; import { ThemedBrowseBySwitcherComponent } from './browse-by-switcher/themed-browse-by-switcher.component'; +import { ComcolModule } from '../shared/comcol/comcol.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -17,6 +18,7 @@ const ENTRY_COMPONENTS = [ @NgModule({ imports: [ CommonModule, + ComcolModule, SharedModule ], declarations: [ diff --git a/src/app/collection-page/collection-form/collection-form.component.ts b/src/app/collection-page/collection-form/collection-form.component.ts index 7835ccc8e5..bb84153835 100644 --- a/src/app/collection-page/collection-form/collection-form.component.ts +++ b/src/app/collection-page/collection-form/collection-form.component.ts @@ -10,7 +10,7 @@ import { } from '@ng-dynamic-forms/core'; import { Collection } from '../../core/shared/collection.model'; -import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; +import { ComColFormComponent } from '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CommunityDataService } from '../../core/data/community-data.service'; import { AuthService } from '../../core/auth/auth.service'; @@ -28,8 +28,8 @@ import { NONE_ENTITY_TYPE } from '../../core/shared/item-relationships/item-type */ @Component({ selector: 'ds-collection-form', - styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'], - templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html' + styleUrls: ['../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss'], + templateUrl: '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.html' }) export class CollectionFormComponent extends ComColFormComponent implements OnInit { /** diff --git a/src/app/collection-page/collection-form/collection-form.module.ts b/src/app/collection-page/collection-form/collection-form.module.ts index a9ff5f3ea9..ddf18f0586 100644 --- a/src/app/collection-page/collection-form/collection-form.module.ts +++ b/src/app/collection-page/collection-form/collection-form.module.ts @@ -2,9 +2,13 @@ import { NgModule } from '@angular/core'; import { CollectionFormComponent } from './collection-form.component'; import { SharedModule } from '../../shared/shared.module'; +import { ComcolModule } from '../../shared/comcol/comcol.module'; +import { FormModule } from '../../shared/form/form.module'; @NgModule({ imports: [ + ComcolModule, + FormModule, SharedModule ], declarations: [ diff --git a/src/app/collection-page/collection-page.module.ts b/src/app/collection-page/collection-page.module.ts index a13731ed23..3652823200 100644 --- a/src/app/collection-page/collection-page.module.ts +++ b/src/app/collection-page/collection-page.module.ts @@ -14,6 +14,7 @@ import { SearchService } from '../core/shared/search/search.service'; import { StatisticsModule } from '../statistics/statistics.module'; import { CollectionFormModule } from './collection-form/collection-form.module'; import { ThemedCollectionPageComponent } from './themed-collection-page.component'; +import { ComcolModule } from '../shared/comcol/comcol.module'; @NgModule({ imports: [ @@ -22,7 +23,8 @@ import { ThemedCollectionPageComponent } from './themed-collection-page.componen CollectionPageRoutingModule, StatisticsModule.forRoot(), EditItemPageModule, - CollectionFormModule + CollectionFormModule, + ComcolModule ], declarations: [ CollectionPageComponent, diff --git a/src/app/collection-page/create-collection-page/create-collection-page.component.ts b/src/app/collection-page/create-collection-page/create-collection-page.component.ts index a38739c407..a938b37ce1 100644 --- a/src/app/collection-page/create-collection-page/create-collection-page.component.ts +++ b/src/app/collection-page/create-collection-page/create-collection-page.component.ts @@ -2,12 +2,12 @@ import { Component } from '@angular/core'; import { CommunityDataService } from '../../core/data/community-data.service'; import { RouteService } from '../../core/services/route.service'; import { Router } from '@angular/router'; -import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component'; +import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component'; import { Collection } from '../../core/shared/collection.model'; import { CollectionDataService } from '../../core/data/collection-data.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; -import {RequestService} from '../../core/data/request.service'; +import { RequestService } from '../../core/data/request.service'; /** * Component that represents the page where a user can create a new Collection diff --git a/src/app/collection-page/delete-collection-page/delete-collection-page.component.ts b/src/app/collection-page/delete-collection-page/delete-collection-page.component.ts index 8daba0abfc..3e30373070 100644 --- a/src/app/collection-page/delete-collection-page/delete-collection-page.component.ts +++ b/src/app/collection-page/delete-collection-page/delete-collection-page.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component'; +import { DeleteComColPageComponent } from '../../shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CollectionDataService } from '../../core/data/collection-data.service'; import { Collection } from '../../core/shared/collection.model'; import { TranslateService } from '@ngx-translate/core'; -import {RequestService} from '../../core/data/request.service'; +import { RequestService } from '../../core/data/request.service'; /** * Component that represents the page where a user can delete an existing Collection diff --git a/src/app/collection-page/edit-collection-page/collection-metadata/collection-metadata.component.ts b/src/app/collection-page/edit-collection-page/collection-metadata/collection-metadata.component.ts index 8cb10775ac..cfaad3767e 100644 --- a/src/app/collection-page/edit-collection-page/collection-metadata/collection-metadata.component.ts +++ b/src/app/collection-page/edit-collection-page/collection-metadata/collection-metadata.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; +import { ComcolMetadataComponent } from '../../../shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; import { Collection } from '../../../core/shared/collection.model'; import { CollectionDataService } from '../../../core/data/collection-data.service'; import { ActivatedRoute, Router } from '@angular/router'; diff --git a/src/app/collection-page/edit-collection-page/collection-roles/collection-roles.component.spec.ts b/src/app/collection-page/edit-collection-page/collection-roles/collection-roles.component.spec.ts index 401065a661..985290a592 100644 --- a/src/app/collection-page/edit-collection-page/collection-roles/collection-roles.component.spec.ts +++ b/src/app/collection-page/edit-collection-page/collection-roles/collection-roles.component.spec.ts @@ -12,6 +12,7 @@ import { RequestService } from '../../../core/data/request.service'; import { RouterTestingModule } from '@angular/router/testing'; import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ComcolModule } from '../../../shared/comcol/comcol.module'; describe('CollectionRolesComponent', () => { @@ -65,6 +66,7 @@ describe('CollectionRolesComponent', () => { TestBed.configureTestingModule({ imports: [ + ComcolModule, SharedModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), diff --git a/src/app/collection-page/edit-collection-page/edit-collection-page.component.ts b/src/app/collection-page/edit-collection-page/edit-collection-page.component.ts index aff1995a14..62fbb3ee3d 100644 --- a/src/app/collection-page/edit-collection-page/edit-collection-page.component.ts +++ b/src/app/collection-page/edit-collection-page/edit-collection-page.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component'; +import { EditComColPageComponent } from '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component'; import { Collection } from '../../core/shared/collection.model'; import { getCollectionPageRoute } from '../collection-page-routing-paths'; @@ -9,7 +9,7 @@ import { getCollectionPageRoute } from '../collection-page-routing-paths'; */ @Component({ selector: 'ds-edit-collection', - templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' + templateUrl: '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' }) export class EditCollectionPageComponent extends EditComColPageComponent { type = 'collection'; diff --git a/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts b/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts index 0b09542fa0..45612be41a 100644 --- a/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts +++ b/src/app/collection-page/edit-collection-page/edit-collection-page.module.ts @@ -10,6 +10,9 @@ import { CollectionSourceComponent } from './collection-source/collection-source import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component'; import { CollectionFormModule } from '../collection-form/collection-form.module'; import { CollectionSourceControlsComponent } from './collection-source/collection-source-controls/collection-source-controls.component'; +import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module'; +import { FormModule } from '../../shared/form/form.module'; +import { ComcolModule } from '../../shared/comcol/comcol.module'; /** * Module that contains all components related to the Edit Collection page administrator functionality @@ -19,7 +22,10 @@ import { CollectionSourceControlsComponent } from './collection-source/collectio CommonModule, SharedModule, EditCollectionPageRoutingModule, - CollectionFormModule + CollectionFormModule, + ResourcePoliciesModule, + FormModule, + ComcolModule ], declarations: [ EditCollectionPageComponent, diff --git a/src/app/community-page/community-form/community-form.component.ts b/src/app/community-page/community-form/community-form.component.ts index 59480e8f68..a3730fd418 100644 --- a/src/app/community-page/community-form/community-form.component.ts +++ b/src/app/community-page/community-form/community-form.component.ts @@ -6,7 +6,7 @@ import { DynamicTextAreaModel } from '@ng-dynamic-forms/core'; import { Community } from '../../core/shared/community.model'; -import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; +import { ComColFormComponent } from '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component'; import { TranslateService } from '@ngx-translate/core'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CommunityDataService } from '../../core/data/community-data.service'; @@ -19,8 +19,8 @@ import { ObjectCacheService } from '../../core/cache/object-cache.service'; */ @Component({ selector: 'ds-community-form', - styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'], - templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html' + styleUrls: ['../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss'], + templateUrl: '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.html' }) export class CommunityFormComponent extends ComColFormComponent { /** diff --git a/src/app/community-page/community-form/community-form.module.ts b/src/app/community-page/community-form/community-form.module.ts index 36dbea5c0d..925d218973 100644 --- a/src/app/community-page/community-form/community-form.module.ts +++ b/src/app/community-page/community-form/community-form.module.ts @@ -2,9 +2,13 @@ import { NgModule } from '@angular/core'; import { CommunityFormComponent } from './community-form.component'; import { SharedModule } from '../../shared/shared.module'; +import { ComcolModule } from '../../shared/comcol/comcol.module'; +import { FormModule } from '../../shared/form/form.module'; @NgModule({ imports: [ + ComcolModule, + FormModule, SharedModule ], declarations: [ diff --git a/src/app/community-page/community-page.module.ts b/src/app/community-page/community-page.module.ts index 3ae75f166c..724b762e90 100644 --- a/src/app/community-page/community-page.module.ts +++ b/src/app/community-page/community-page.module.ts @@ -12,6 +12,7 @@ import { DeleteCommunityPageComponent } from './delete-community-page/delete-com import { StatisticsModule } from '../statistics/statistics.module'; import { CommunityFormModule } from './community-form/community-form.module'; import { ThemedCommunityPageComponent } from './themed-community-page.component'; +import { ComcolModule } from '../shared/comcol/comcol.module'; const DECLARATIONS = [CommunityPageComponent, ThemedCommunityPageComponent, @@ -26,7 +27,8 @@ const DECLARATIONS = [CommunityPageComponent, SharedModule, CommunityPageRoutingModule, StatisticsModule.forRoot(), - CommunityFormModule + CommunityFormModule, + ComcolModule ], declarations: [ ...DECLARATIONS diff --git a/src/app/community-page/create-community-page/create-community-page.component.ts b/src/app/community-page/create-community-page/create-community-page.component.ts index be3385b92f..b332fad100 100644 --- a/src/app/community-page/create-community-page/create-community-page.component.ts +++ b/src/app/community-page/create-community-page/create-community-page.component.ts @@ -3,7 +3,7 @@ import { Community } from '../../core/shared/community.model'; import { CommunityDataService } from '../../core/data/community-data.service'; import { RouteService } from '../../core/services/route.service'; import { Router } from '@angular/router'; -import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component'; +import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; import { RequestService } from '../../core/data/request.service'; diff --git a/src/app/community-page/delete-community-page/delete-community-page.component.ts b/src/app/community-page/delete-community-page/delete-community-page.component.ts index ec51076bbc..0cccc503e1 100644 --- a/src/app/community-page/delete-community-page/delete-community-page.component.ts +++ b/src/app/community-page/delete-community-page/delete-community-page.component.ts @@ -2,10 +2,10 @@ import { Component } from '@angular/core'; import { Community } from '../../core/shared/community.model'; import { CommunityDataService } from '../../core/data/community-data.service'; import { ActivatedRoute, Router } from '@angular/router'; -import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component'; +import { DeleteComColPageComponent } from '../../shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; -import {RequestService} from '../../core/data/request.service'; +import { RequestService } from '../../core/data/request.service'; /** * Component that represents the page where a user can delete an existing Community diff --git a/src/app/community-page/edit-community-page/community-metadata/community-metadata.component.ts b/src/app/community-page/edit-community-page/community-metadata/community-metadata.component.ts index c4bb88289f..a2dbfa6eb6 100644 --- a/src/app/community-page/edit-community-page/community-metadata/community-metadata.component.ts +++ b/src/app/community-page/edit-community-page/community-metadata/community-metadata.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; +import { ComcolMetadataComponent } from '../../../shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; import { ActivatedRoute, Router } from '@angular/router'; import { Community } from '../../../core/shared/community.model'; import { CommunityDataService } from '../../../core/data/community-data.service'; diff --git a/src/app/community-page/edit-community-page/community-roles/community-roles.component.spec.ts b/src/app/community-page/edit-community-page/community-roles/community-roles.component.spec.ts index b61705126c..d1188df02d 100644 --- a/src/app/community-page/edit-community-page/community-roles/community-roles.component.spec.ts +++ b/src/app/community-page/edit-community-page/community-roles/community-roles.component.spec.ts @@ -12,6 +12,7 @@ import { SharedModule } from '../../../shared/shared.module'; import { RouterTestingModule } from '@angular/router/testing'; import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ComcolModule } from '../../../shared/comcol/comcol.module'; describe('CommunityRolesComponent', () => { @@ -50,6 +51,7 @@ describe('CommunityRolesComponent', () => { TestBed.configureTestingModule({ imports: [ + ComcolModule, SharedModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), diff --git a/src/app/community-page/edit-community-page/edit-community-page.component.ts b/src/app/community-page/edit-community-page/edit-community-page.component.ts index 836384ab84..54a6ee4944 100644 --- a/src/app/community-page/edit-community-page/edit-community-page.component.ts +++ b/src/app/community-page/edit-community-page/edit-community-page.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { Community } from '../../core/shared/community.model'; import { ActivatedRoute, Router } from '@angular/router'; -import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component'; +import { EditComColPageComponent } from '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component'; import { getCommunityPageRoute } from '../community-page-routing-paths'; /** @@ -9,7 +9,7 @@ import { getCommunityPageRoute } from '../community-page-routing-paths'; */ @Component({ selector: 'ds-edit-community', - templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' + templateUrl: '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' }) export class EditCommunityPageComponent extends EditComColPageComponent { type = 'community'; diff --git a/src/app/community-page/edit-community-page/edit-community-page.module.ts b/src/app/community-page/edit-community-page/edit-community-page.module.ts index 3f7511f700..2b0fc73f2a 100644 --- a/src/app/community-page/edit-community-page/edit-community-page.module.ts +++ b/src/app/community-page/edit-community-page/edit-community-page.module.ts @@ -8,6 +8,8 @@ import { CommunityMetadataComponent } from './community-metadata/community-metad import { CommunityRolesComponent } from './community-roles/community-roles.component'; import { CommunityAuthorizationsComponent } from './community-authorizations/community-authorizations.component'; import { CommunityFormModule } from '../community-form/community-form.module'; +import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module'; +import { ComcolModule } from '../../shared/comcol/comcol.module'; /** * Module that contains all components related to the Edit Community page administrator functionality @@ -17,7 +19,9 @@ import { CommunityFormModule } from '../community-form/community-form.module'; CommonModule, SharedModule, EditCommunityPageRoutingModule, - CommunityFormModule + CommunityFormModule, + ComcolModule, + ResourcePoliciesModule ], declarations: [ EditCommunityPageComponent, diff --git a/src/app/entity-groups/journal-entities/journal-entities.module.ts b/src/app/entity-groups/journal-entities/journal-entities.module.ts index dc88490eac..3bf861e10d 100644 --- a/src/app/entity-groups/journal-entities/journal-entities.module.ts +++ b/src/app/entity-groups/journal-entities/journal-entities.module.ts @@ -19,6 +19,7 @@ import { JournalVolumeSearchResultGridElementComponent } from './item-grid-eleme import { JournalVolumeSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component'; import { JournalIssueSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component'; import { JournalSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component'; +import { ItemSharedModule } from '../../item-page/item-shared.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -45,6 +46,7 @@ const ENTRY_COMPONENTS = [ @NgModule({ imports: [ CommonModule, + ItemSharedModule, SharedModule ], declarations: [ diff --git a/src/app/entity-groups/research-entities/research-entities.module.ts b/src/app/entity-groups/research-entities/research-entities.module.ts index c9d6c2d5b6..721a22be08 100644 --- a/src/app/entity-groups/research-entities/research-entities.module.ts +++ b/src/app/entity-groups/research-entities/research-entities.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { SharedModule } from '../../shared/shared.module'; import { OrgUnitComponent } from './item-pages/org-unit/org-unit.component'; import { PersonComponent } from './item-pages/person/person.component'; @@ -27,6 +28,7 @@ import { ExternalSourceEntryListSubmissionElementComponent } from './submission/ import { OrgUnitSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component'; import { PersonSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component'; import { ProjectSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component'; +import { ItemSharedModule } from '../../item-page/item-shared.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -65,7 +67,9 @@ const COMPONENTS = [ @NgModule({ imports: [ CommonModule, - SharedModule + ItemSharedModule, + SharedModule, + NgbTooltipModule ], declarations: [ ...COMPONENTS, @@ -79,7 +83,7 @@ export class ResearchEntitiesModule { static withEntryComponents() { return { ngModule: ResearchEntitiesModule, - providers: ENTRY_COMPONENTS.map((component) => ({provide: component})) + providers: ENTRY_COMPONENTS.map((component) => ({ provide: component })) }; } } diff --git a/src/app/item-page/edit-item-page/edit-item-page.module.ts b/src/app/item-page/edit-item-page/edit-item-page.module.ts index 11b1d585ba..97901bd7c8 100644 --- a/src/app/item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/item-page/edit-item-page/edit-item-page.module.ts @@ -1,5 +1,8 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; + +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; + import { SharedModule } from '../../shared/shared.module'; import { EditItemPageRoutingModule } from './edit-item-page.routing.module'; import { EditItemPageComponent } from './edit-item-page.component'; @@ -31,6 +34,8 @@ import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.co import { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component'; import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component'; import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe'; +import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module'; + /** * Module that contains all components related to the Edit Item page administrator functionality @@ -39,9 +44,11 @@ import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe'; imports: [ CommonModule, SharedModule, + NgbTooltipModule, EditItemPageRoutingModule, SearchPageModule, - DragDropModule + DragDropModule, + ResourcePoliciesModule ], declarations: [ EditItemPageComponent, diff --git a/src/app/item-page/item-shared.module.ts b/src/app/item-page/item-shared.module.ts new file mode 100644 index 0000000000..b191b6c4b3 --- /dev/null +++ b/src/app/item-page/item-shared.module.ts @@ -0,0 +1,36 @@ +import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component'; +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SearchModule } from '../shared/search/search.module'; +import { SharedModule } from '../shared/shared.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { DYNAMIC_FORM_CONTROL_MAP_FN } from '@ng-dynamic-forms/core'; +import { dsDynamicFormControlMapFn } from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component'; +import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component'; + +const COMPONENTS = [ + RelatedEntitiesSearchComponent, + TabbedRelatedEntitiesSearchComponent +]; + +@NgModule({ + declarations: [ + ...COMPONENTS + ], + imports: [ + CommonModule, + SearchModule, + SharedModule, + TranslateModule + ], + exports: [ + ...COMPONENTS + ], + providers: [ + { + provide: DYNAMIC_FORM_CONTROL_MAP_FN, + useValue: dsDynamicFormControlMapFn + } + ] +}) +export class ItemSharedModule { } diff --git a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts index 46c02a613a..781e72795b 100644 --- a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts +++ b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts @@ -10,7 +10,7 @@ import { getFilterByRelation } from '../../../../shared/utils/relation-query.uti }) /** * A component to show related items as search results. - * Related items can be facetted, or queried using an + * Related items can be faceted, or queried using an * optional search box. */ export class RelatedEntitiesSearchComponent implements OnInit { diff --git a/src/app/my-dspace-page/my-dspace-page.module.ts b/src/app/my-dspace-page/my-dspace-page.module.ts index a5a18effbc..183edf2728 100644 --- a/src/app/my-dspace-page/my-dspace-page.module.ts +++ b/src/app/my-dspace-page/my-dspace-page.module.ts @@ -14,6 +14,7 @@ import { MyDspaceSearchModule } from './my-dspace-search.module'; import { MyDSpaceNewSubmissionDropdownComponent } from './my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component'; import { MyDSpaceNewExternalDropdownComponent } from './my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component'; import { ThemedMyDSpacePageComponent } from './themed-my-dspace-page.component'; +import { SearchModule } from '../shared/search/search.module'; const DECLARATIONS = [ MyDSpacePageComponent, @@ -29,6 +30,7 @@ const DECLARATIONS = [ imports: [ CommonModule, SharedModule, + SearchModule, MyDspacePageRoutingModule, MyDspaceSearchModule.withEntryComponents() ], diff --git a/src/app/profile-page/profile-page.module.ts b/src/app/profile-page/profile-page.module.ts index 0b2274f2d4..dc9595140b 100644 --- a/src/app/profile-page/profile-page.module.ts +++ b/src/app/profile-page/profile-page.module.ts @@ -6,12 +6,14 @@ import { ProfilePageComponent } from './profile-page.component'; import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component'; import { ProfilePageSecurityFormComponent } from './profile-page-security-form/profile-page-security-form.component'; import { ThemedProfilePageComponent } from './themed-profile-page.component'; +import { FormModule } from '../shared/form/form.module'; @NgModule({ imports: [ ProfilePageRoutingModule, CommonModule, - SharedModule + SharedModule, + FormModule ], exports: [ ProfilePageSecurityFormComponent, diff --git a/src/app/search-page/search-page.module.ts b/src/app/search-page/search-page.module.ts index 0cf6164f8a..d7015974d8 100644 --- a/src/app/search-page/search-page.module.ts +++ b/src/app/search-page/search-page.module.ts @@ -14,6 +14,7 @@ import { SearchConfigurationService } from '../core/shared/search/search-configu import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module'; import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module'; import { ThemedSearchPageComponent } from './themed-search-page.component'; +import { SearchModule } from '../shared/search/search.module'; const components = [ SearchPageComponent, @@ -25,6 +26,7 @@ const components = [ @NgModule({ imports: [ CommonModule, + SearchModule, SharedModule.withEntryComponents(), CoreModule.forRoot(), StatisticsModule.forRoot(), diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html similarity index 100% rename from src/app/shared/comcol-forms/comcol-form/comcol-form.component.html rename to src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.scss b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss similarity index 100% rename from src/app/shared/comcol-forms/comcol-form/comcol-form.component.scss rename to src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.spec.ts similarity index 93% rename from src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts rename to src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.spec.ts index c7c6e2e5e7..e5c2033d8b 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -7,19 +7,19 @@ import { RouterTestingModule } from '@angular/router/testing'; import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { TranslateModule } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { AuthService } from '../../../core/auth/auth.service'; -import { ObjectCacheService } from '../../../core/cache/object-cache.service'; -import { RequestService } from '../../../core/data/request.service'; -import { RestRequestMethod } from '../../../core/data/rest-request-method'; -import { Community } from '../../../core/shared/community.model'; -import { hasValue } from '../../empty.util'; -import { AuthServiceMock } from '../../mocks/auth.service.mock'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; -import { VarDirective } from '../../utils/var.directive'; +import { AuthService } from '../../../../core/auth/auth.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { RequestService } from '../../../../core/data/request.service'; +import { RestRequestMethod } from '../../../../core/data/rest-request-method'; +import { Community } from '../../../../core/shared/community.model'; +import { hasValue } from '../../../empty.util'; +import { AuthServiceMock } from '../../../mocks/auth.service.mock'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../../testing/notifications-service.stub'; +import { VarDirective } from '../../../utils/var.directive'; import { ComColFormComponent } from './comcol-form.component'; import { Operation } from 'fast-json-patch'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils'; describe('ComColFormComponent', () => { let comp: ComColFormComponent; diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts similarity index 85% rename from src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts rename to src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts index ef7a5e55e8..c3ba9dcaee 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.ts @@ -1,39 +1,27 @@ -import { - Component, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output, - ViewChild -} from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { - DynamicFormControlModel, - DynamicFormService, - DynamicInputModel -} from '@ng-dynamic-forms/core'; +import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import { FileUploader } from 'ng2-file-upload'; import { BehaviorSubject, combineLatest as observableCombineLatest, Subscription } from 'rxjs'; -import { AuthService } from '../../../core/auth/auth.service'; -import { ObjectCacheService } from '../../../core/cache/object-cache.service'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { RemoteData } from '../../../core/data/remote-data'; -import { RequestService } from '../../../core/data/request.service'; -import { RestRequestMethod } from '../../../core/data/rest-request-method'; -import { Bitstream } from '../../../core/shared/bitstream.model'; -import { Collection } from '../../../core/shared/collection.model'; -import { Community } from '../../../core/shared/community.model'; -import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models'; -import { ResourceType } from '../../../core/shared/resource-type'; -import { hasValue, isNotEmpty } from '../../empty.util'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { UploaderOptions } from '../../uploader/uploader-options.model'; -import { UploaderComponent } from '../../uploader/uploader.component'; +import { AuthService } from '../../../../core/auth/auth.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { ComColDataService } from '../../../../core/data/comcol-data.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { RequestService } from '../../../../core/data/request.service'; +import { RestRequestMethod } from '../../../../core/data/rest-request-method'; +import { Bitstream } from '../../../../core/shared/bitstream.model'; +import { Collection } from '../../../../core/shared/collection.model'; +import { Community } from '../../../../core/shared/community.model'; +import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; +import { ResourceType } from '../../../../core/shared/resource-type'; +import { hasValue, isNotEmpty } from '../../../empty.util'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { UploaderOptions } from '../../../uploader/uploader-options.model'; +import { UploaderComponent } from '../../../uploader/uploader.component'; import { Operation } from 'fast-json-patch'; -import { NoContent } from '../../../core/shared/NoContent.model'; -import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { NoContent } from '../../../../core/shared/NoContent.model'; +import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; /** * A form for creating and editing Communities or Collections diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts similarity index 90% rename from src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts rename to src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts index 05c3e50e4b..0104de83ca 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { CommunityDataService } from '../../../core/data/community-data.service'; -import { RouteService } from '../../../core/services/route.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { RouteService } from '../../../../core/services/route.service'; import { Router } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { Community } from '../../../core/shared/community.model'; -import { SharedModule } from '../../shared.module'; +import { Community } from '../../../../core/shared/community.model'; +import { SharedModule } from '../../../shared.module'; import { CommonModule } from '@angular/common'; import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { CreateComColPageComponent } from './create-comcol-page.component'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; -import { RequestService } from '../../../core/data/request.service'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils'; +import { ComColDataService } from '../../../../core/data/comcol-data.service'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../../testing/notifications-service.stub'; +import { RequestService } from '../../../../core/data/request.service'; import { getTestScheduler } from 'jasmine-marbles'; describe('CreateComColPageComponent', () => { diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts similarity index 77% rename from src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts rename to src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts index b1be5ae9be..2db9fcc20c 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -3,18 +3,18 @@ import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { mergeMap, take } from 'rxjs/operators'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { CommunityDataService } from '../../../core/data/community-data.service'; -import { RemoteData } from '../../../core/data/remote-data'; -import { RouteService } from '../../../core/services/route.service'; -import { Community } from '../../../core/shared/community.model'; -import { getFirstSucceededRemoteDataPayload, } from '../../../core/shared/operators'; -import { ResourceType } from '../../../core/shared/resource-type'; -import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { RequestParam } from '../../../core/cache/models/request-param.model'; -import { RequestService } from '../../../core/data/request.service'; -import { Collection } from '../../../core/shared/collection.model'; +import { ComColDataService } from '../../../../core/data/comcol-data.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { RouteService } from '../../../../core/services/route.service'; +import { Community } from '../../../../core/shared/community.model'; +import { getFirstSucceededRemoteDataPayload, } from '../../../../core/shared/operators'; +import { ResourceType } from '../../../../core/shared/resource-type'; +import { hasValue, isNotEmpty, isNotUndefined } from '../../../empty.util'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { RequestParam } from '../../../../core/cache/models/request-param.model'; +import { RequestService } from '../../../../core/data/request.service'; +import { Collection } from '../../../../core/shared/collection.model'; /** * Component representing the create page for communities and collections diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts b/src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts similarity index 91% rename from src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts rename to src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts index 6eaf102808..6aab79c5d4 100644 --- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { CommunityDataService } from '../../../core/data/community-data.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { Community } from '../../../core/shared/community.model'; -import { SharedModule } from '../../shared.module'; +import { Community } from '../../../../core/shared/community.model'; +import { SharedModule } from '../../../shared.module'; import { CommonModule } from '@angular/common'; import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { DeleteComColPageComponent } from './delete-comcol-page.component'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationsServiceStub } from '../../testing/notifications-service.stub'; -import { RequestService } from '../../../core/data/request.service'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../../testing/notifications-service.stub'; +import { RequestService } from '../../../../core/data/request.service'; import { getTestScheduler } from 'jasmine-marbles'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { createFailedRemoteDataObject$, createNoContentRemoteDataObject$ } from '../../remote-data.utils'; +import { ComColDataService } from '../../../../core/data/comcol-data.service'; +import { createFailedRemoteDataObject$, createNoContentRemoteDataObject$ } from '../../../remote-data.utils'; describe('DeleteComColPageComponent', () => { let comp: DeleteComColPageComponent; diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts b/src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts similarity index 80% rename from src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts rename to src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts index 8579becc83..f781b71f3f 100644 --- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts +++ b/src/app/shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts @@ -1,16 +1,16 @@ import { Component, OnInit } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; -import { RemoteData } from '../../../core/data/remote-data'; +import { RemoteData } from '../../../../core/data/remote-data'; import { first, map } from 'rxjs/operators'; -import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsService } from '../../../notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; -import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; -import { NoContent } from '../../../core/shared/NoContent.model'; -import { RequestService } from '../../../core/data/request.service'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { Community } from '../../../core/shared/community.model'; -import { Collection } from '../../../core/shared/collection.model'; +import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; +import { NoContent } from '../../../../core/shared/NoContent.model'; +import { RequestService } from '../../../../core/data/request.service'; +import { ComColDataService } from '../../../../core/data/comcol-data.service'; +import { Community } from '../../../../core/shared/community.model'; +import { Collection } from '../../../../core/shared/collection.model'; /** * Component representing the delete page for communities and collections diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts similarity index 92% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts index 9c8d616383..6588d9cbac 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts @@ -5,16 +5,16 @@ import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { ComColDataService } from '../../../../core/data/comcol-data.service'; -import { Community } from '../../../../core/shared/community.model'; -import { NotificationsService } from '../../../notifications/notifications.service'; -import { SharedModule } from '../../../shared.module'; -import { NotificationsServiceStub } from '../../../testing/notifications-service.stub'; +import { ComColDataService } from '../../../../../core/data/comcol-data.service'; +import { Community } from '../../../../../core/shared/community.model'; +import { NotificationsService } from '../../../../notifications/notifications.service'; +import { SharedModule } from '../../../../shared.module'; +import { NotificationsServiceStub } from '../../../../testing/notifications-service.stub'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ -} from '../../../remote-data.utils'; +} from '../../../../remote-data.utils'; import { ComcolMetadataComponent } from './comcol-metadata.component'; describe('ComColMetadataComponent', () => { diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts similarity index 79% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts index cc68ad4970..5bd51ea650 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts @@ -1,17 +1,17 @@ import { Component, OnInit } from '@angular/core'; -import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; +import { DSpaceObject } from '../../../../../core/shared/dspace-object.model'; import { Observable } from 'rxjs'; -import { RemoteData } from '../../../../core/data/remote-data'; +import { RemoteData } from '../../../../../core/data/remote-data'; import { ActivatedRoute, Router } from '@angular/router'; import { first, map, take } from 'rxjs/operators'; -import { getFirstSucceededRemoteData, getFirstCompletedRemoteData } from '../../../../core/shared/operators'; -import { hasValue, isEmpty } from '../../../empty.util'; -import { ResourceType } from '../../../../core/shared/resource-type'; -import { ComColDataService } from '../../../../core/data/comcol-data.service'; -import { NotificationsService } from '../../../notifications/notifications.service'; +import { getFirstCompletedRemoteData, getFirstSucceededRemoteData } from '../../../../../core/shared/operators'; +import { hasValue, isEmpty } from '../../../../empty.util'; +import { ResourceType } from '../../../../../core/shared/resource-type'; +import { ComColDataService } from '../../../../../core/data/comcol-data.service'; +import { NotificationsService } from '../../../../notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; -import { Community } from '../../../../core/shared/community.model'; -import { Collection } from '../../../../core/shared/collection.model'; +import { Community } from '../../../../../core/shared/community.model'; +import { Collection } from '../../../../../core/shared/collection.model'; @Component({ selector: 'ds-comcol-metadata', diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html similarity index 100% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.scss b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.scss similarity index 100% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.scss rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.scss diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts similarity index 94% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts index cc5b64b9b5..175abe48e4 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.spec.ts @@ -1,15 +1,15 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComcolRoleComponent } from './comcol-role.component'; -import { GroupDataService } from '../../../../core/eperson/group-data.service'; +import { GroupDataService } from '../../../../../core/eperson/group-data.service'; import { By } from '@angular/platform-browser'; -import { SharedModule } from '../../../shared.module'; import { TranslateModule } from '@ngx-translate/core'; import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; -import { RequestService } from '../../../../core/data/request.service'; +import { RequestService } from '../../../../../core/data/request.service'; import { of as observableOf } from 'rxjs'; import { RouterTestingModule } from '@angular/router/testing'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ComcolModule } from '../../../comcol.module'; describe('ComcolRoleComponent', () => { @@ -32,7 +32,7 @@ describe('ComcolRoleComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ - SharedModule, + ComcolModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NoopAnimationsModule diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts similarity index 82% rename from src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts index 4eb364a3cc..7ed88fae1c 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts @@ -1,17 +1,17 @@ import { Component, Input, OnInit } from '@angular/core'; -import { Group } from '../../../../core/eperson/models/group.model'; -import { Community } from '../../../../core/shared/community.model'; +import { Group } from '../../../../../core/eperson/models/group.model'; +import { Community } from '../../../../../core/shared/community.model'; import { BehaviorSubject, Observable } from 'rxjs'; -import { GroupDataService } from '../../../../core/eperson/group-data.service'; -import { Collection } from '../../../../core/shared/collection.model'; +import { GroupDataService } from '../../../../../core/eperson/group-data.service'; +import { Collection } from '../../../../../core/shared/collection.model'; import { filter, map, switchMap } from 'rxjs/operators'; -import { getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../../../../core/shared/operators'; -import { RequestService } from '../../../../core/data/request.service'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { HALLink } from '../../../../core/shared/hal-link.model'; -import { getGroupEditRoute } from '../../../../access-control/access-control-routing-paths'; -import { hasNoValue, hasValue } from '../../../empty.util'; -import { NoContent } from '../../../../core/shared/NoContent.model'; +import { getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../../../../../core/shared/operators'; +import { RequestService } from '../../../../../core/data/request.service'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { HALLink } from '../../../../../core/shared/hal-link.model'; +import { getGroupEditRoute } from '../../../../../access-control/access-control-routing-paths'; +import { hasNoValue, hasValue } from '../../../../empty.util'; +import { NoContent } from '../../../../../core/shared/NoContent.model'; /** * Component for managing a community or collection role. diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html similarity index 100% rename from src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts similarity index 91% rename from src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts index d13958bb79..d3d936c9f7 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts @@ -2,12 +2,12 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { Community } from '../../../core/shared/community.model'; -import { SharedModule } from '../../shared.module'; +import { Community } from '../../../../core/shared/community.model'; +import { SharedModule } from '../../../shared.module'; import { CommonModule } from '@angular/common'; import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { EditComColPageComponent } from './edit-comcol-page.component'; describe('EditComColPageComponent', () => { diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts similarity index 90% rename from src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts rename to src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts index 793065096f..48eb9aec96 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts @@ -4,9 +4,9 @@ import { Observable } from 'rxjs'; import { first, map } from 'rxjs/operators'; import { ActivatedRoute, Router } from '@angular/router'; -import { RemoteData } from '../../../core/data/remote-data'; -import { isNotEmpty } from '../../empty.util'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { isNotEmpty } from '../../../empty.util'; +import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; /** * Component representing the edit page for communities and collections diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.html similarity index 100% rename from src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.html rename to src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.html diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.scss b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.scss similarity index 100% rename from src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.scss rename to src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.scss diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts similarity index 86% rename from src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts rename to src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts index 01912dbcaa..b65ad5140c 100644 --- a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts +++ b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts @@ -2,10 +2,10 @@ import { Component, Input, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ActivatedRoute, Params, Router } from '@angular/router'; -import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface'; -import { environment } from '../../../environments/environment'; -import { getCommunityPageRoute } from '../../community-page/community-page-routing-paths'; -import { getCollectionPageRoute } from '../../collection-page/collection-page-routing-paths'; +import { BrowseByTypeConfig } from '../../../../config/browse-by-type-config.interface'; +import { environment } from '../../../../environments/environment'; +import { getCommunityPageRoute } from '../../../community-page/community-page-routing-paths'; +import { getCollectionPageRoute } from '../../../collection-page/collection-page-routing-paths'; export interface ComColPageNavOption { id: string; diff --git a/src/app/shared/comcol-page-content/comcol-page-content.component.html b/src/app/shared/comcol/comcol-page-content/comcol-page-content.component.html similarity index 100% rename from src/app/shared/comcol-page-content/comcol-page-content.component.html rename to src/app/shared/comcol/comcol-page-content/comcol-page-content.component.html diff --git a/src/app/shared/comcol-page-content/comcol-page-content.component.scss b/src/app/shared/comcol/comcol-page-content/comcol-page-content.component.scss similarity index 100% rename from src/app/shared/comcol-page-content/comcol-page-content.component.scss rename to src/app/shared/comcol/comcol-page-content/comcol-page-content.component.scss diff --git a/src/app/shared/comcol-page-content/comcol-page-content.component.ts b/src/app/shared/comcol/comcol-page-content/comcol-page-content.component.ts similarity index 100% rename from src/app/shared/comcol-page-content/comcol-page-content.component.ts rename to src/app/shared/comcol/comcol-page-content/comcol-page-content.component.ts diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.html b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html similarity index 100% rename from src/app/shared/comcol-page-handle/comcol-page-handle.component.html rename to src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.scss b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss similarity index 100% rename from src/app/shared/comcol-page-handle/comcol-page-handle.component.scss rename to src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.spec.ts b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.spec.ts similarity index 100% rename from src/app/shared/comcol-page-handle/comcol-page-handle.component.spec.ts rename to src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.spec.ts diff --git a/src/app/shared/comcol-page-handle/comcol-page-handle.component.ts b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts similarity index 100% rename from src/app/shared/comcol-page-handle/comcol-page-handle.component.ts rename to src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts diff --git a/src/app/shared/comcol-page-header/comcol-page-header.component.html b/src/app/shared/comcol/comcol-page-header/comcol-page-header.component.html similarity index 100% rename from src/app/shared/comcol-page-header/comcol-page-header.component.html rename to src/app/shared/comcol/comcol-page-header/comcol-page-header.component.html diff --git a/src/app/shared/comcol-page-header/comcol-page-header.component.scss b/src/app/shared/comcol/comcol-page-header/comcol-page-header.component.scss similarity index 100% rename from src/app/shared/comcol-page-header/comcol-page-header.component.scss rename to src/app/shared/comcol/comcol-page-header/comcol-page-header.component.scss diff --git a/src/app/shared/comcol-page-header/comcol-page-header.component.ts b/src/app/shared/comcol/comcol-page-header/comcol-page-header.component.ts similarity index 100% rename from src/app/shared/comcol-page-header/comcol-page-header.component.ts rename to src/app/shared/comcol/comcol-page-header/comcol-page-header.component.ts diff --git a/src/app/shared/comcol-page-logo/comcol-page-logo.component.html b/src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.html similarity index 100% rename from src/app/shared/comcol-page-logo/comcol-page-logo.component.html rename to src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.html diff --git a/src/app/shared/comcol-page-logo/comcol-page-logo.component.scss b/src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.scss similarity index 100% rename from src/app/shared/comcol-page-logo/comcol-page-logo.component.scss rename to src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.scss diff --git a/src/app/shared/comcol-page-logo/comcol-page-logo.component.ts b/src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.ts similarity index 95% rename from src/app/shared/comcol-page-logo/comcol-page-logo.component.ts rename to src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.ts index f3c2d4e80d..a9761bfd5f 100644 --- a/src/app/shared/comcol-page-logo/comcol-page-logo.component.ts +++ b/src/app/shared/comcol/comcol-page-logo/comcol-page-logo.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { Bitstream } from '../../core/shared/bitstream.model'; +import { Bitstream } from '../../../core/shared/bitstream.model'; @Component({ selector: 'ds-comcol-page-logo', diff --git a/src/app/shared/comcol/comcol.module.ts b/src/app/shared/comcol/comcol.module.ts new file mode 100644 index 0000000000..664f14a098 --- /dev/null +++ b/src/app/shared/comcol/comcol.module.ts @@ -0,0 +1,42 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component'; +import { ComcolPageHandleComponent } from './comcol-page-handle/comcol-page-handle.component'; +import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component'; +import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component'; +import { ComColFormComponent } from './comcol-forms/comcol-form/comcol-form.component'; +import { CreateComColPageComponent } from './comcol-forms/create-comcol-page/create-comcol-page.component'; +import { EditComColPageComponent } from './comcol-forms/edit-comcol-page/edit-comcol-page.component'; +import { DeleteComColPageComponent } from './comcol-forms/delete-comcol-page/delete-comcol-page.component'; +import { ComcolPageBrowseByComponent } from './comcol-page-browse-by/comcol-page-browse-by.component'; +import { ComcolRoleComponent } from './comcol-forms/edit-comcol-page/comcol-role/comcol-role.component'; +import { SharedModule } from '../shared.module'; +import { FormModule } from '../form/form.module'; + +const COMPONENTS = [ + ComcolPageContentComponent, + ComcolPageHandleComponent, + ComcolPageHeaderComponent, + ComcolPageLogoComponent, + ComColFormComponent, + CreateComColPageComponent, + EditComColPageComponent, + DeleteComColPageComponent, + ComcolPageBrowseByComponent, + ComcolRoleComponent, +]; + +@NgModule({ + declarations: [ + ...COMPONENTS + ], + imports: [ + CommonModule, + FormModule, + SharedModule + ], + exports: [ + ...COMPONENTS + ] +}) +export class ComcolModule { } diff --git a/src/app/shared/form/form.module.ts b/src/app/shared/form/form.module.ts new file mode 100644 index 0000000000..62ab5bd647 --- /dev/null +++ b/src/app/shared/form/form.module.ts @@ -0,0 +1,82 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormComponent } from './form.component'; +import { DsDynamicFormComponent } from './builder/ds-dynamic-form-ui/ds-dynamic-form.component'; +import { + DsDynamicFormControlContainerComponent, + dsDynamicFormControlMapFn +} from './builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component'; +import { DsDynamicListComponent } from './builder/ds-dynamic-form-ui/models/list/dynamic-list.component'; +import { DsDynamicLookupComponent } from './builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; +import { DsDynamicDisabledComponent } from './builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component'; +import { DsDynamicLookupRelationModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component'; +import { DsDynamicScrollableDropdownComponent } from './builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component'; +import { DsDynamicTagComponent } from './builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component'; +import { DsDynamicOneboxComponent } from './builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component'; +import { DsDynamicRelationGroupComponent } from './builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components'; +import { DsDatePickerComponent } from './builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; +import { DsDynamicFormGroupComponent } from './builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component'; +import { DsDynamicFormArrayComponent } from './builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component'; +import { DsDatePickerInlineComponent } from './builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component'; +import { DsDynamicLookupRelationSearchTabComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component'; +import { DsDynamicLookupRelationSelectionTabComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component'; +import { DsDynamicLookupRelationExternalSourceTabComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component'; +import { SharedModule } from '../shared.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { SearchModule } from '../search/search.module'; +import { DYNAMIC_FORM_CONTROL_MAP_FN, DynamicFormsCoreModule } from '@ng-dynamic-forms/core'; +import { ExistingMetadataListElementComponent } from './builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; +import { ExistingRelationListElementComponent } from './builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component'; +import { ExternalSourceEntryImportModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component'; +import { CustomSwitchComponent } from './builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component'; +import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap'; + +const COMPONENTS = [ + CustomSwitchComponent, + DsDynamicFormComponent, + DsDynamicFormControlContainerComponent, + DsDynamicListComponent, + DsDynamicLookupComponent, + DsDynamicLookupRelationSearchTabComponent, + DsDynamicLookupRelationSelectionTabComponent, + DsDynamicLookupRelationExternalSourceTabComponent, + DsDynamicDisabledComponent, + DsDynamicLookupRelationModalComponent, + DsDynamicScrollableDropdownComponent, + DsDynamicTagComponent, + DsDynamicOneboxComponent, + DsDynamicRelationGroupComponent, + DsDatePickerComponent, + DsDynamicFormGroupComponent, + DsDynamicFormArrayComponent, + DsDatePickerInlineComponent, + ExistingMetadataListElementComponent, + ExistingRelationListElementComponent, + ExternalSourceEntryImportModalComponent, + FormComponent +]; + +@NgModule({ + declarations: [ + ...COMPONENTS + ], + imports: [ + CommonModule, + DynamicFormsCoreModule, + DynamicFormsNGBootstrapUIModule, + SearchModule, + SharedModule, + TranslateModule + ], + exports: [ + ...COMPONENTS + ], + providers: [ + { + provide: DYNAMIC_FORM_CONTROL_MAP_FN, + useValue: dsDynamicFormControlMapFn + } + ] +}) +export class FormModule { +} diff --git a/src/app/shared/resource-policies/resource-policies.module.ts b/src/app/shared/resource-policies/resource-policies.module.ts new file mode 100644 index 0000000000..6eeaddce36 --- /dev/null +++ b/src/app/shared/resource-policies/resource-policies.module.ts @@ -0,0 +1,52 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { TranslateModule } from '@ngx-translate/core'; + +import { ResourcePoliciesComponent } from './resource-policies.component'; +import { ResourcePolicyFormComponent } from './form/resource-policy-form.component'; +import { ResourcePolicyEditComponent } from './edit/resource-policy-edit.component'; +import { ResourcePolicyCreateComponent } from './create/resource-policy-create.component'; +import { FormModule } from '../form/form.module'; +import { ResourcePolicyResolver } from './resolvers/resource-policy.resolver'; +import { ResourcePolicyTargetResolver } from './resolvers/resource-policy-target.resolver'; +import { EpersonGroupListComponent } from './form/eperson-group-list/eperson-group-list.component'; +import { GroupSearchBoxComponent } from './form/eperson-group-list/group-search-box/group-search-box.component'; +import { EpersonSearchBoxComponent } from './form/eperson-group-list/eperson-search-box/eperson-search-box.component'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { SharedModule } from '../shared.module'; + +const COMPONENTS = [ + ResourcePoliciesComponent, + ResourcePolicyFormComponent, + ResourcePolicyEditComponent, + ResourcePolicyCreateComponent, + EpersonGroupListComponent, + EpersonSearchBoxComponent, + GroupSearchBoxComponent +]; + +const PROVIDERS = [ + ResourcePolicyResolver, + ResourcePolicyTargetResolver +]; + +@NgModule({ + declarations: [ + ...COMPONENTS + ], + imports: [ + NgbModule, + CommonModule, + FormModule, + TranslateModule, + SharedModule + ], + providers: [ + ...PROVIDERS + ], + exports: [ + ...COMPONENTS + ] +}) +export class ResourcePoliciesModule { } diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts new file mode 100644 index 0000000000..d5816d2a1b --- /dev/null +++ b/src/app/shared/search/search.module.ts @@ -0,0 +1,103 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component'; +import { SearchFiltersComponent } from './search-filters/search-filters.component'; +import { SearchFilterComponent } from './search-filters/search-filter/search-filter.component'; +import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-filter.component'; +import { SearchLabelsComponent } from './search-labels/search-labels.component'; +import { SearchLabelComponent } from './search-labels/search-label/search-label.component'; +import { SearchFacetFilterWrapperComponent } from './search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component'; +import { SearchRangeFilterComponent } from './search-filters/search-filter/search-range-filter/search-range-filter.component'; +import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component'; +import { SearchHierarchyFilterComponent } from './search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component'; +import { SearchBooleanFilterComponent } from './search-filters/search-filter/search-boolean-filter/search-boolean-filter.component'; +import { SearchFacetOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component'; +import { SearchFacetSelectedOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component'; +import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component'; +import { SearchAuthorityFilterComponent } from './search-filters/search-filter/search-authority-filter/search-authority-filter.component'; +import { SearchSidebarComponent } from './search-sidebar/search-sidebar.component'; +import { SearchSettingsComponent } from './search-settings/search-settings.component'; +import { ConfigurationSearchPageComponent } from '../../search-page/configuration-search-page.component'; +import { ThemedConfigurationSearchPageComponent } from '../../search-page/themed-configuration-search-page.component'; +import { SearchObjects } from './search-objects.model'; +import { FacetConfigResponse } from './facet-config-response.model'; +import { FacetValues } from './facet-values.model'; +import { SearchResult } from './search-result.model'; +import { MissingTranslationHandler, TranslateModule } from '@ngx-translate/core'; +import { MissingTranslationHelper } from '../translate/missing-translation.helper'; +import { SharedModule } from '../shared.module'; +import { SearchResultsComponent } from './search-results/search-results.component'; + +const COMPONENTS = [ + SearchResultsComponent, + SearchSidebarComponent, + SearchSettingsComponent, + SearchFiltersComponent, + SearchFilterComponent, + SearchFacetFilterComponent, + SearchLabelsComponent, + SearchLabelComponent, + SearchFacetFilterWrapperComponent, + SearchRangeFilterComponent, + SearchTextFilterComponent, + SearchHierarchyFilterComponent, + SearchBooleanFilterComponent, + SearchFacetOptionComponent, + SearchFacetSelectedOptionComponent, + SearchFacetRangeOptionComponent, + SearchAuthorityFilterComponent, + SearchSwitchConfigurationComponent, + ConfigurationSearchPageComponent, + ThemedConfigurationSearchPageComponent +]; + +const ENTRY_COMPONENTS = [ + SearchFacetFilterComponent, + SearchRangeFilterComponent, + SearchTextFilterComponent, + SearchHierarchyFilterComponent, + SearchBooleanFilterComponent, + SearchFacetOptionComponent, + SearchFacetSelectedOptionComponent, + SearchFacetRangeOptionComponent, + SearchAuthorityFilterComponent, +]; + +/** + * Declaration needed to make sure all decorator functions are called in time + */ +export const MODELS = [ + SearchObjects, + FacetConfigResponse, + FacetValues, + SearchResult +]; + +@NgModule({ + declarations: [ + ...COMPONENTS + ], + imports: [ + CommonModule, + TranslateModule.forChild({ + missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MissingTranslationHelper }, + useDefaultLang: true + }), + SharedModule.withEntryComponents() + ], + exports: [ + ...COMPONENTS + ] +}) +export class SearchModule { + /** + * NOTE: this method allows to resolve issue with components that using a custom decorator + * which are not loaded during SSR otherwise + */ + static withEntryComponents() { + return { + ngModule: SearchModule, + providers: ENTRY_COMPONENTS.map((component) => ({ provide: component })) + }; + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 2b64260f46..d88445a930 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -6,17 +6,21 @@ import { CdkTreeModule } from '@angular/cdk/tree'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { NouisliderModule } from 'ng2-nouislider'; -import { NgbDatepickerModule, NgbModule, NgbTimepickerModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; +import { + NgbDatepickerModule, + NgbDropdownModule, + NgbNavModule, + NgbPaginationModule, + NgbTimepickerModule, + NgbTooltipModule, + NgbTypeaheadModule +} from '@ng-bootstrap/ng-bootstrap'; import { MissingTranslationHandler, TranslateModule } from '@ngx-translate/core'; import { NgxPaginationModule } from 'ngx-pagination'; import { FileUploadModule } from 'ng2-file-upload'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; -import { DYNAMIC_FORM_CONTROL_MAP_FN, DynamicFormsCoreModule } from '@ng-dynamic-forms/core'; -import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap'; import { TextMaskModule } from 'angular2-text-mask'; import { MomentModule } from 'ngx-moment'; - -import { ComcolRoleComponent } from './comcol-forms/edit-comcol-page/comcol-role/comcol-role.component'; import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component'; import { ExportMetadataSelectorComponent } from './dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component'; import { FileDropzoneNoUploaderComponent } from './file-dropzone-no-uploader/file-dropzone-no-uploader.component'; @@ -35,10 +39,6 @@ import { CommunityGridElementComponent } from './object-grid/community-grid-elem import { AbstractListableElementComponent } from './object-collection/shared/object-collection-element/abstract-listable-element.component'; import { ObjectGridComponent } from './object-grid/object-grid.component'; import { ObjectCollectionComponent } from './object-collection/object-collection.component'; -import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component'; -import { ComcolPageHandleComponent } from './comcol-page-handle/comcol-page-handle.component'; -import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component'; -import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component'; import { ErrorComponent } from './error/error.component'; import { LoadingComponent } from './loading/loading.component'; import { PaginationComponent } from './pagination/pagination.component'; @@ -49,14 +49,6 @@ import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.com import { VarDirective } from './utils/var.directive'; import { AuthNavMenuComponent } from './auth-nav-menu/auth-nav-menu.component'; import { LogOutComponent } from './log-out/log-out.component'; -import { FormComponent } from './form/form.component'; -import { DsDynamicOneboxComponent } from './form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component'; -import { DsDynamicScrollableDropdownComponent } from './form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component'; -import { - DsDynamicFormControlContainerComponent, - dsDynamicFormControlMapFn, -} from './form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component'; -import { DsDynamicFormComponent } from './form/builder/ds-dynamic-form-ui/ds-dynamic-form.component'; import { DragClickDirective } from './utils/drag-click.directive'; import { TruncatePipe } from './utils/truncate.pipe'; import { TruncatableComponent } from './truncatable/truncatable.component'; @@ -64,15 +56,7 @@ import { TruncatableService } from './truncatable/truncatable.service'; import { TruncatablePartComponent } from './truncatable/truncatable-part/truncatable-part.component'; import { UploaderComponent } from './uploader/uploader.component'; import { ChipsComponent } from './chips/chips.component'; -import { DsDynamicTagComponent } from './form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component'; -import { DsDynamicListComponent } from './form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component'; -import { DsDynamicFormGroupComponent } from './form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component'; -import { DsDynamicFormArrayComponent } from './form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component'; -import { DsDynamicRelationGroupComponent } from './form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components'; -import { DsDatePickerInlineComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component'; import { NumberPickerComponent } from './number-picker/number-picker.component'; -import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; -import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; import { MockAdminGuard } from './mocks/admin-guard.service.mock'; import { AlertComponent } from './alert/alert.component'; import { SearchResultDetailElementComponent } from './object-detail/my-dspace-result-detail-element/search-result-detail-element.component'; @@ -101,14 +85,9 @@ import { LangSwitchComponent } from './lang-switch/lang-switch.component'; import { PlainTextMetadataListElementComponent } from './object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component'; import { ItemMetadataListElementComponent } from './object-list/metadata-representation-list-element/item/item-metadata-list-element.component'; import { MetadataRepresentationListElementComponent } from './object-list/metadata-representation-list-element/metadata-representation-list-element.component'; -import { ComColFormComponent } from './comcol-forms/comcol-form/comcol-form.component'; -import { CreateComColPageComponent } from './comcol-forms/create-comcol-page/create-comcol-page.component'; -import { EditComColPageComponent } from './comcol-forms/edit-comcol-page/edit-comcol-page.component'; -import { DeleteComColPageComponent } from './comcol-forms/delete-comcol-page/delete-comcol-page.component'; import { ObjectValuesPipe } from './utils/object-values-pipe'; import { InListValidator } from './utils/in-list-validator.directive'; import { AutoFocusDirective } from './utils/auto-focus.directive'; -import { ComcolPageBrowseByComponent } from './comcol-page-browse-by/comcol-page-browse-by.component'; import { StartsWithDateComponent } from './starts-with/date/starts-with-date.component'; import { StartsWithTextComponent } from './starts-with/text/starts-with-text.component'; import { DSOSelectorComponent } from './dso-selector/dso-selector/dso-selector.component'; @@ -127,32 +106,11 @@ import { RoleDirective } from './roles/role.directive'; import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component'; import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component'; import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component'; -import { DsDynamicLookupRelationModalComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component'; -import { SearchResultsComponent } from './search/search-results/search-results.component'; -import { SearchSidebarComponent } from './search/search-sidebar/search-sidebar.component'; -import { SearchSettingsComponent } from './search/search-settings/search-settings.component'; import { CollectionSearchResultGridElementComponent } from './object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; import { CommunitySearchResultGridElementComponent } from './object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component'; -import { SearchFiltersComponent } from './search/search-filters/search-filters.component'; -import { SearchFilterComponent } from './search/search-filters/search-filter/search-filter.component'; -import { SearchFacetFilterComponent } from './search/search-filters/search-filter/search-facet-filter/search-facet-filter.component'; -import { SearchLabelsComponent } from './search/search-labels/search-labels.component'; -import { SearchFacetFilterWrapperComponent } from './search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component'; -import { SearchRangeFilterComponent } from './search/search-filters/search-filter/search-range-filter/search-range-filter.component'; -import { SearchTextFilterComponent } from './search/search-filters/search-filter/search-text-filter/search-text-filter.component'; -import { SearchHierarchyFilterComponent } from './search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component'; -import { SearchBooleanFilterComponent } from './search/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component'; -import { SearchFacetOptionComponent } from './search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component'; -import { SearchFacetSelectedOptionComponent } from './search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component'; -import { SearchFacetRangeOptionComponent } from './search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component'; -import { SearchSwitchConfigurationComponent } from './search/search-switch-configuration/search-switch-configuration.component'; -import { SearchAuthorityFilterComponent } from './search/search-filters/search-filter/search-authority-filter/search-authority-filter.component'; -import { DsDynamicDisabledComponent } from './form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component'; -import { DsDynamicLookupRelationSearchTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component'; -import { DsDynamicLookupRelationSelectionTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component'; import { PageSizeSelectorComponent } from './page-size-selector/page-size-selector.component'; import { AbstractTrackableComponent } from './trackable/abstract-trackable.component'; -import { ComcolMetadataComponent } from './comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; +import { ComcolMetadataComponent } from './comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component'; import { ItemSelectComponent } from './object-select/item-select/item-select.component'; import { CollectionSelectComponent } from './object-select/collection-select/collection-select.component'; import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component'; @@ -164,48 +122,34 @@ import { MetadataRepresentationDirective } from './metadata-representation/metad import { ListableObjectComponentLoaderComponent } from './object-collection/shared/listable-object/listable-object-component-loader.component'; import { ItemSearchResultListElementComponent } from './object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { ListableObjectDirective } from './object-collection/shared/listable-object/listable-object.directive'; -import { SearchLabelComponent } from './search/search-labels/search-label/search-label.component'; import { ItemMetadataRepresentationListElementComponent } from './object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; import { PageWithSidebarComponent } from './sidebar/page-with-sidebar.component'; import { SidebarDropdownComponent } from './sidebar/sidebar-dropdown.component'; import { SidebarFilterComponent } from './sidebar/filter/sidebar-filter.component'; import { SidebarFilterSelectedOptionComponent } from './sidebar/filter/sidebar-filter-selected-option.component'; import { SelectableListItemControlComponent } from './object-collection/shared/selectable-list-item-control/selectable-list-item-control.component'; -import { DsDynamicLookupRelationExternalSourceTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component'; -import { ExternalSourceEntryImportModalComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component'; import { ImportableListItemControlComponent } from './object-collection/shared/importable-list-item-control/importable-list-item-control.component'; -import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; import { ItemVersionsComponent } from './item/item-versions/item-versions.component'; import { SortablejsModule } from 'ngx-sortablejs'; import { LogInContainerComponent } from './log-in/container/log-in-container.component'; import { LogInShibbolethComponent } from './log-in/methods/shibboleth/log-in-shibboleth.component'; import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component'; import { LogInComponent } from './log-in/log-in.component'; -import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component'; import { BundleListElementComponent } from './object-list/bundle-list-element/bundle-list-element.component'; import { MissingTranslationHelper } from './translate/missing-translation.helper'; import { ItemVersionsNoticeComponent } from './item/item-versions/notice/item-versions-notice.component'; import { FileValidator } from './utils/require-file.validator'; import { FileValueAccessorDirective } from './utils/file-value-accessor.directive'; import { FileSectionComponent } from '../item-page/simple/field-components/file-section/file-section.component'; -import { ExistingRelationListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component'; import { ModifyItemOverviewComponent } from '../item-page/edit-item-page/modify-item-overview/modify-item-overview.component'; import { ClaimedTaskActionsLoaderComponent } from './mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component'; import { ClaimedTaskActionsDirective } from './mydspace-actions/claimed-task/switcher/claimed-task-actions.directive'; import { ClaimedTaskActionsEditMetadataComponent } from './mydspace-actions/claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component'; import { ImpersonateNavbarComponent } from './impersonate-navbar/impersonate-navbar.component'; -import { ResourcePoliciesComponent } from './resource-policies/resource-policies.component'; import { NgForTrackByIdDirective } from './ng-for-track-by-id.directive'; -import { ResourcePolicyFormComponent } from './resource-policies/form/resource-policy-form.component'; -import { EpersonGroupListComponent } from './resource-policies/form/eperson-group-list/eperson-group-list.component'; -import { ResourcePolicyTargetResolver } from './resource-policies/resolvers/resource-policy-target.resolver'; -import { ResourcePolicyResolver } from './resource-policies/resolvers/resource-policy.resolver'; -import { EpersonSearchBoxComponent } from './resource-policies/form/eperson-group-list/eperson-search-box/eperson-search-box.component'; -import { GroupSearchBoxComponent } from './resource-policies/form/eperson-group-list/group-search-box/group-search-box.component'; import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component'; import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component'; import { EntityDropdownComponent } from './entity-dropdown/entity-dropdown.component'; -import { DsSelectComponent } from './ds-select/ds-select.component'; import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-treeview.component'; import { CurationFormComponent } from '../curation-form/curation-form.component'; import { PublicationSidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component'; @@ -219,53 +163,35 @@ import { HoverClassDirective } from './hover-class.directive'; import { ValidationSuggestionsComponent } from './input-suggestions/validation-suggestions/validation-suggestions.component'; import { ItemAlertsComponent } from './item/item-alerts/item-alerts.component'; import { ItemSearchResultGridElementComponent } from './object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component'; -import { ResourcePolicyEditComponent } from './resource-policies/edit/resource-policy-edit.component'; -import { ResourcePolicyCreateComponent } from './resource-policies/create/resource-policy-create.component'; -import { SearchObjects } from './search/search-objects.model'; -import { SearchResult } from './search/search-result.model'; -import { FacetConfigResponse } from './search/facet-config-response.model'; -import { FacetValues } from './search/facet-values.model'; import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstream-download-page.component'; import { GenericItemPageFieldComponent } from '../item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { MetadataRepresentationListComponent } from '../item-page/simple/metadata-representation-list/metadata-representation-list.component'; import { RelatedItemsComponent } from '../item-page/simple/related-items/related-items-component'; -import { TabbedRelatedEntitiesSearchComponent } from '../item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component'; -import { RelatedEntitiesSearchComponent } from '../item-page/simple/related-entities/related-entities-search/related-entities-search.component'; -import { ConfigurationSearchPageComponent } from '../search-page/configuration-search-page.component'; import { LinkMenuItemComponent } from './menu/menu-item/link-menu-item.component'; import { OnClickMenuItemComponent } from './menu/menu-item/onclick-menu-item.component'; import { TextMenuItemComponent } from './menu/menu-item/text-menu-item.component'; -import { ThemedConfigurationSearchPageComponent } from '../search-page/themed-configuration-search-page.component'; import { SearchNavbarComponent } from '../search-navbar/search-navbar.component'; import { ItemVersionsSummaryModalComponent } from './item/item-versions/item-versions-summary-modal/item-versions-summary-modal.component'; import { ItemVersionsDeleteModalComponent } from './item/item-versions/item-versions-delete-modal/item-versions-delete-modal.component'; import { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/scope-selector-modal.component'; import { BitstreamRequestACopyPageComponent } from './bitstream-request-a-copy-page/bitstream-request-a-copy-page.component'; - -/** - * Declaration needed to make sure all decorator functions are called in time - */ -export const MODELS = [ - SearchObjects, - FacetConfigResponse, - FacetValues, - SearchResult -]; +import { DsSelectComponent } from './ds-select/ds-select.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here CommonModule, SortablejsModule, - DynamicFormsCoreModule, - DynamicFormsNGBootstrapUIModule, FileUploadModule, FormsModule, InfiniteScrollModule, - NgbModule, + NgbNavModule, NgbDatepickerModule, NgbTimepickerModule, NgbTypeaheadModule, NgxPaginationModule, + NgbPaginationModule, + NgbDropdownModule, + NgbTooltipModule, ReactiveFormsModule, RouterModule, NouisliderModule, @@ -302,34 +228,9 @@ const COMPONENTS = [ AuthNavMenuComponent, UserMenuComponent, ChipsComponent, - ComcolPageContentComponent, - ComcolPageHandleComponent, - ComcolPageHeaderComponent, - ComcolPageLogoComponent, - ComColFormComponent, - CreateComColPageComponent, - EditComColPageComponent, - DeleteComColPageComponent, - ComcolPageBrowseByComponent, - ComcolRoleComponent, - DsDynamicFormComponent, - DsDynamicFormControlContainerComponent, - DsDynamicListComponent, - DsDynamicLookupComponent, - DsDynamicDisabledComponent, - DsDynamicLookupRelationModalComponent, - DsDynamicScrollableDropdownComponent, - DsDynamicTagComponent, - DsDynamicOneboxComponent, - DsDynamicRelationGroupComponent, - DsDatePickerComponent, - DsDynamicFormGroupComponent, - DsDynamicFormArrayComponent, - DsDatePickerInlineComponent, DsSelectComponent, ErrorComponent, FileSectionComponent, - FormComponent, LangSwitchComponent, LoadingComponent, LogInComponent, @@ -382,26 +283,9 @@ const COMPONENTS = [ CommunitySearchResultListElementComponent, CollectionSearchResultListElementComponent, BrowseByComponent, - SearchResultsComponent, - SearchSidebarComponent, - SearchSettingsComponent, + CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, - SearchFiltersComponent, - SearchFilterComponent, - SearchFacetFilterComponent, - SearchLabelsComponent, - SearchLabelComponent, - SearchFacetFilterWrapperComponent, - SearchRangeFilterComponent, - SearchTextFilterComponent, - SearchHierarchyFilterComponent, - SearchBooleanFilterComponent, - SearchFacetOptionComponent, - SearchFacetSelectedOptionComponent, - SearchFacetRangeOptionComponent, - SearchSwitchConfigurationComponent, - SearchAuthorityFilterComponent, PageSizeSelectorComponent, ListableObjectComponentLoaderComponent, CollectionListElementComponent, @@ -414,15 +298,14 @@ const COMPONENTS = [ TypeBadgeComponent, BrowseByComponent, AbstractTrackableComponent, - CustomSwitchComponent, + ItemSelectComponent, CollectionSelectComponent, MetadataRepresentationLoaderComponent, SelectableListItemControlComponent, - ExternalSourceEntryImportModalComponent, + ImportableListItemControlComponent, - ExistingMetadataListElementComponent, - ExistingRelationListElementComponent, + LogInShibbolethComponent, LogInPasswordComponent, LogInContainerComponent, @@ -431,13 +314,6 @@ const COMPONENTS = [ ItemVersionsNoticeComponent, ModifyItemOverviewComponent, ImpersonateNavbarComponent, - ResourcePoliciesComponent, - ResourcePolicyFormComponent, - ResourcePolicyEditComponent, - ResourcePolicyCreateComponent, - EpersonGroupListComponent, - EpersonSearchBoxComponent, - GroupSearchBoxComponent, FileDownloadLinkComponent, BitstreamDownloadPageComponent, BitstreamRequestACopyPageComponent, @@ -458,10 +334,7 @@ const COMPONENTS = [ PlainTextMetadataListElementComponent, ItemMetadataListElementComponent, MetadataRepresentationListElementComponent, - DsDynamicLookupRelationSearchTabComponent, - DsDynamicLookupRelationSelectionTabComponent, ItemMetadataRepresentationListElementComponent, - DsDynamicLookupRelationExternalSourceTabComponent, BundleListElementComponent, StartsWithDateComponent, StartsWithTextComponent, @@ -502,18 +375,7 @@ const ENTRY_COMPONENTS = [ PlainTextMetadataListElementComponent, ItemMetadataListElementComponent, MetadataRepresentationListElementComponent, - CustomSwitchComponent, ItemMetadataRepresentationListElementComponent, - SearchResultsComponent, - SearchFacetFilterComponent, - SearchRangeFilterComponent, - SearchTextFilterComponent, - SearchHierarchyFilterComponent, - SearchBooleanFilterComponent, - SearchFacetOptionComponent, - SearchFacetSelectedOptionComponent, - SearchFacetRangeOptionComponent, - SearchAuthorityFilterComponent, LogInPasswordComponent, LogInShibbolethComponent, BundleListElementComponent, @@ -539,11 +401,6 @@ const ENTRY_COMPONENTS = [ ScopeSelectorModalComponent, ]; -const SHARED_SEARCH_PAGE_COMPONENTS = [ - ConfigurationSearchPageComponent, - ThemedConfigurationSearchPageComponent -]; - const SHARED_ITEM_PAGE_COMPONENTS = [ MetadataFieldWrapperComponent, MetadataValuesComponent, @@ -553,20 +410,13 @@ const SHARED_ITEM_PAGE_COMPONENTS = [ GenericItemPageFieldComponent, MetadataRepresentationListComponent, RelatedItemsComponent, - RelatedEntitiesSearchComponent, - TabbedRelatedEntitiesSearchComponent + ]; const PROVIDERS = [ TruncatableService, MockAdminGuard, - AbstractTrackableComponent, - { - provide: DYNAMIC_FORM_CONTROL_MAP_FN, - useValue: dsDynamicFormControlMapFn - }, - ResourcePolicyResolver, - ResourcePolicyTargetResolver + AbstractTrackableComponent ]; const DIRECTIVES = [ @@ -599,7 +449,6 @@ const DIRECTIVES = [ ...COMPONENTS, ...DIRECTIVES, ...SHARED_ITEM_PAGE_COMPONENTS, - ...SHARED_SEARCH_PAGE_COMPONENTS, ItemVersionsSummaryModalComponent, ItemVersionsDeleteModalComponent, ], @@ -611,7 +460,6 @@ const DIRECTIVES = [ ...PIPES, ...COMPONENTS, ...SHARED_ITEM_PAGE_COMPONENTS, - ...SHARED_SEARCH_PAGE_COMPONENTS, ...DIRECTIVES, TranslateModule ] @@ -628,7 +476,7 @@ export class SharedModule { static withEntryComponents() { return { ngModule: SharedModule, - providers: ENTRY_COMPONENTS.map((component) => ({provide: component})) + providers: ENTRY_COMPONENTS.map((component) => ({ provide: component })) }; } } diff --git a/src/app/submission/submission.module.ts b/src/app/submission/submission.module.ts index e8c96284c0..5f14b5c246 100644 --- a/src/app/submission/submission.module.ts +++ b/src/app/submission/submission.module.ts @@ -37,6 +37,8 @@ import { ResearchEntitiesModule } from '../entity-groups/research-entities/resea import { ThemedSubmissionEditComponent } from './edit/themed-submission-edit.component'; import { ThemedSubmissionSubmitComponent } from './submit/themed-submission-submit.component'; import { ThemedSubmissionImportExternalComponent } from './import-external/themed-submission-import-external.component'; +import { FormModule } from '../shared/form/form.module'; +import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'; const DECLARATIONS = [ SubmissionSectionUploadAccessConditionsComponent, @@ -73,15 +75,17 @@ const ENTRY_COMPONENTS = [ ]; @NgModule({ - imports: [ - CommonModule, - CoreModule.forRoot(), - SharedModule, - StoreModule.forFeature('submission', submissionReducers, storeModuleConfig as StoreConfig), - EffectsModule.forFeature(submissionEffects), - JournalEntitiesModule.withEntryComponents(), - ResearchEntitiesModule.withEntryComponents(), - ], + imports: [ + CommonModule, + CoreModule.forRoot(), + SharedModule, + StoreModule.forFeature('submission', submissionReducers, storeModuleConfig as StoreConfig), + EffectsModule.forFeature(submissionEffects), + JournalEntitiesModule.withEntryComponents(), + ResearchEntitiesModule.withEntryComponents(), + FormModule, + NgbAccordionModule + ], declarations: DECLARATIONS, exports: DECLARATIONS, providers: [ diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index ba5f660012..a931da5a2a 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -79,7 +79,10 @@ import { HeaderComponent } from './app/header/header.component'; import { FooterComponent } from './app/footer/footer.component'; import { BreadcrumbsComponent } from './app/breadcrumbs/breadcrumbs.component'; import { HeaderNavbarWrapperComponent } from './app/header-nav-wrapper/header-navbar-wrapper.component'; -import { FileSectionComponent} from './app/item-page/simple/field-components/file-section/file-section.component'; +import { FileSectionComponent } from './app/item-page/simple/field-components/file-section/file-section.component'; +import { SearchModule } from '../../app/shared/search/search.module'; +import { ResourcePoliciesModule } from '../../app/shared/resource-policies/resource-policies.module'; +import { ComcolModule } from '../../app/shared/comcol/comcol.module'; const DECLARATIONS = [ FileSectionComponent, @@ -168,6 +171,10 @@ const DECLARATIONS = [ SubmissionModule, MyDSpacePageModule, MyDspaceSearchModule, + SearchModule, + FormsModule, + ResourcePoliciesModule, + ComcolModule ], declarations: DECLARATIONS }) diff --git a/src/themes/dspace/theme.module.ts b/src/themes/dspace/theme.module.ts index b03d5af5b4..2a774eb9c8 100644 --- a/src/themes/dspace/theme.module.ts +++ b/src/themes/dspace/theme.module.ts @@ -43,6 +43,9 @@ import { MyDSpacePageModule } from '../../app/my-dspace-page/my-dspace-page.modu import { NavbarComponent } from './app/navbar/navbar.component'; import { HeaderComponent } from './app/header/header.component'; import { HeaderNavbarWrapperComponent } from './app/header-nav-wrapper/header-navbar-wrapper.component'; +import { SearchModule } from '../../app/shared/search/search.module'; +import { ResourcePoliciesModule } from '../../app/shared/resource-policies/resource-policies.module'; +import { ComcolModule } from '../../app/shared/comcol/comcol.module'; const DECLARATIONS = [ HomeNewsComponent, @@ -94,6 +97,10 @@ const DECLARATIONS = [ SubmissionModule, MyDSpacePageModule, MyDspaceSearchModule, + SearchModule, + FormsModule, + ResourcePoliciesModule, + ComcolModule ], declarations: DECLARATIONS }) From b6ae15fbd2332aa69af6efad9d2705fdcfb37491 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 16 Dec 2021 10:00:08 +0100 Subject: [PATCH 28/77] [CST-4633] move search.component to search module and create search models folder --- .../collection-item-mapper.component.spec.ts | 2 +- .../collection-item-mapper.component.ts | 11 ++--- .../collection-page.component.ts | 9 +--- src/app/core/data/bundle-data.service.ts | 2 +- src/app/core/data/external-source.service.ts | 2 +- .../facet-config-response-parsing.service.ts | 4 +- .../facet-value-response-parsing.service.ts | 4 +- src/app/core/data/item-data.service.ts | 2 +- .../core/data/lookup-relation.service.spec.ts | 4 +- src/app/core/data/lookup-relation.service.ts | 4 +- .../data/mydspace-response-parsing.service.ts | 2 +- .../data/search-response-parsing.service.ts | 2 +- .../core/data/version-history-data.service.ts | 2 +- src/app/core/shared/operators.ts | 2 +- .../search-configuration.service.spec.ts | 4 +- .../search/search-configuration.service.ts | 13 +++--- .../search/search-filter.service.spec.ts | 4 +- .../shared/search/search-filter.service.ts | 2 +- .../core/shared/search/search.service.spec.ts | 7 +--- src/app/core/shared/search/search.service.ts | 15 +++---- .../item-bitstreams.component.ts | 7 +--- ...-drag-and-drop-bitstream-list.component.ts | 2 +- .../item-collection-mapper.component.spec.ts | 4 +- .../item-collection-mapper.component.ts | 9 ++-- .../edit-relationship-list.component.ts | 10 ++++- .../my-dspace-configuration.service.spec.ts | 5 +-- .../my-dspace-new-submission.component.ts | 2 +- .../my-dspace-page.component.scss | 2 +- .../my-dspace-page.component.spec.ts | 2 +- .../my-dspace-page.component.ts | 15 ++----- .../my-dspace-results.component.ts | 4 +- ...onfiguration-search-page.component.spec.ts | 2 +- .../configuration-search-page.component.ts | 14 ++----- src/app/search-page/search-page.module.ts | 2 - .../search-page/search-tracker.component.ts | 6 +-- ...uthorized-collection-selector.component.ts | 2 +- .../dso-selector.component.spec.ts | 2 +- .../dso-selector/dso-selector.component.ts | 6 +-- ...ynamic-form-control-container.component.ts | 2 +- ...ic-lookup-relation-modal.component.spec.ts | 4 +- ...dynamic-lookup-relation-modal.component.ts | 2 +- ...tion-external-source-tab.component.spec.ts | 2 +- ...-relation-external-source-tab.component.ts | 2 +- ...nal-source-entry-import-modal.component.ts | 4 +- ...okup-relation-search-tab.component.spec.ts | 4 +- ...ic-lookup-relation-search-tab.component.ts | 2 +- ...p-relation-selection-tab.component.spec.ts | 2 +- ...lookup-relation-selection-tab.component.ts | 2 +- .../item-versions/item-versions.component.ts | 2 +- ...aimed-approved-task-search-result.model.ts | 2 +- ...aimed-declined-task-search-result.model.ts | 2 +- .../claimed-task-search-result.model.ts | 2 +- .../shared/collection-search-result.model.ts | 2 +- .../shared/community-search-result.model.ts | 2 +- .../shared/item-search-result.model.ts | 2 +- .../shared/pool-task-search-result.model.ts | 2 +- .../workflow-item-search-result.model.ts | 2 +- .../workspace-item-search-result.model.ts | 2 +- .../item-detail-preview-field.component.ts | 2 +- .../item-detail-preview.component.ts | 2 +- .../search-result-detail-element.component.ts | 2 +- .../search-result-grid-element.component.ts | 2 +- .../item-list-preview.component.ts | 2 +- .../search-result-list-element.component.ts | 2 +- ...ebar-search-list-element.component.spec.ts | 2 +- .../sidebar-search-list-element.component.ts | 2 +- .../page-size-selector.component.ts | 2 +- .../facet-config-response.model.ts | 10 ++--- .../search/{ => models}/facet-value.model.ts | 4 +- .../search/{ => models}/facet-values.model.ts | 10 ++--- .../search/{ => models}/filter-type.model.ts | 0 .../paginated-search-options.model.spec.ts | 6 +-- .../paginated-search-options.model.ts | 8 ++-- .../search-filter-config.model.ts | 16 +++---- .../{ => models}/search-filter.model.ts | 0 .../{ => models}/search-objects.model.ts | 10 ++--- .../{ => models}/search-options.model.spec.ts | 3 +- .../{ => models}/search-options.model.ts | 8 ++-- .../search-query-response.model.ts | 4 +- .../{ => models}/search-result.model.ts | 18 ++++---- .../facet-config-response.resouce-type.ts | 2 +- .../types}/facet-values.resource-type.ts | 2 +- .../search-filter-config.resource-type.ts | 2 +- .../types}/search-objects.resource-type.ts | 2 +- .../types}/search-result.resource-type.ts | 2 +- .../search-authority-filter.component.ts | 2 +- .../search-boolean-filter.component.ts | 7 +--- .../search-facet-option.component.spec.ts | 8 ++-- .../search-facet-option.component.ts | 4 +- ...earch-facet-range-option.component.spec.ts | 8 ++-- .../search-facet-range-option.component.ts | 4 +- ...ch-facet-selected-option.component.spec.ts | 8 ++-- .../search-facet-selected-option.component.ts | 4 +- .../search-facet-filter-wrapper.component.ts | 4 +- .../search-facet-filter.component.spec.ts | 6 +-- .../search-facet-filter.component.ts | 12 ++++-- .../search-filter-type-decorator.ts | 3 +- .../search-filter/search-filter.actions.ts | 2 +- .../search-filter.component.spec.ts | 4 +- .../search-filter/search-filter.component.ts | 2 +- .../search-hierarchy-filter.component.ts | 7 +--- .../search-range-filter.component.spec.ts | 6 +-- .../search-range-filter.component.ts | 10 +++-- .../search-text-filter.component.ts | 11 ++--- .../search-filters.component.ts | 2 +- .../search-results.component.ts | 4 +- .../search-settings.component.ts | 2 +- .../search-sidebar.component.ts | 2 +- .../search}/search.component.html | 13 +++++- .../search}/search.component.scss | 0 .../search}/search.component.spec.ts | 28 ++++++------- .../search}/search.component.ts | 42 ++++++++++--------- src/app/shared/search/search.module.ts | 10 +++-- src/app/shared/search/search.utils.spec.ts | 4 +- src/app/shared/search/search.utils.ts | 4 +- src/app/statistics/statistics.service.spec.ts | 2 +- src/app/statistics/statistics.service.ts | 2 +- ...bmission-import-external.component.spec.ts | 2 +- .../configuration-search-page.component.ts | 6 +-- 119 files changed, 290 insertions(+), 309 deletions(-) rename src/app/shared/search/{ => models}/facet-config-response.model.ts (62%) rename src/app/shared/search/{ => models}/facet-value.model.ts (82%) rename src/app/shared/search/{ => models}/facet-values.model.ts (72%) rename src/app/shared/search/{ => models}/filter-type.model.ts (100%) rename src/app/shared/search/{ => models}/paginated-search-options.model.spec.ts (87%) rename src/app/shared/search/{ => models}/paginated-search-options.model.ts (82%) rename src/app/shared/search/{ => models}/search-filter-config.model.ts (78%) rename src/app/shared/search/{ => models}/search-filter.model.ts (100%) rename src/app/shared/search/{ => models}/search-objects.model.ts (68%) rename src/app/shared/search/{ => models}/search-options.model.spec.ts (90%) rename src/app/shared/search/{ => models}/search-options.model.ts (91%) rename src/app/shared/search/{ => models}/search-query-response.model.ts (87%) rename src/app/shared/search/{ => models}/search-result.model.ts (59%) rename src/app/shared/search/{ => models/types}/facet-config-response.resouce-type.ts (75%) rename src/app/shared/search/{ => models/types}/facet-values.resource-type.ts (74%) rename src/app/shared/search/{ => models/types}/search-filter-config.resource-type.ts (75%) rename src/app/shared/search/{ => models/types}/search-objects.resource-type.ts (74%) rename src/app/shared/search/{ => models/types}/search-result.resource-type.ts (73%) rename src/app/{search-page => shared/search}/search.component.html (89%) rename src/app/{search-page => shared/search}/search.component.scss (100%) rename src/app/{search-page => shared/search}/search.component.spec.ts (84%) rename src/app/{search-page => shared/search}/search.component.ts (77%) diff --git a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts index 0dfd013449..e8d8d3eb11 100644 --- a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts +++ b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts @@ -33,7 +33,7 @@ import { ErrorComponent } from '../../shared/error/error.component'; import { LoadingComponent } from '../../shared/loading/loading.component'; import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; import { SearchService } from '../../core/shared/search/search.service'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject, diff --git a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.ts b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.ts index 9a93457436..3172616efc 100644 --- a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.ts +++ b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.ts @@ -9,10 +9,11 @@ import { Collection } from '../../core/shared/collection.model'; import { PaginatedList } from '../../core/data/paginated-list.model'; import { map, startWith, switchMap, take } from 'rxjs/operators'; import { - getRemoteDataPayload, - getFirstSucceededRemoteData, - toDSpaceObjectListRD, - getFirstCompletedRemoteData, getAllSucceededRemoteData + getAllSucceededRemoteData, + getFirstCompletedRemoteData, + getFirstSucceededRemoteData, + getRemoteDataPayload, + toDSpaceObjectListRD } from '../../core/shared/operators'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; @@ -24,7 +25,7 @@ import { CollectionDataService } from '../../core/data/collection-data.service'; import { isNotEmpty } from '../../shared/empty.util'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { SearchService } from '../../core/shared/search/search.service'; import { followLink } from '../../shared/utils/follow-link-config.model'; import { NoContent } from '../../core/shared/NoContent.model'; diff --git a/src/app/collection-page/collection-page.component.ts b/src/app/collection-page/collection-page.component.ts index 366e1da7b1..820fd0c4a8 100644 --- a/src/app/collection-page/collection-page.component.ts +++ b/src/app/collection-page/collection-page.component.ts @@ -1,13 +1,8 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { - BehaviorSubject, - combineLatest as observableCombineLatest, - Observable, - Subject -} from 'rxjs'; +import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subject } from 'rxjs'; import { filter, map, mergeMap, startWith, switchMap, take } from 'rxjs/operators'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; import { SearchService } from '../core/shared/search/search.service'; import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; import { CollectionDataService } from '../core/data/collection-data.service'; diff --git a/src/app/core/data/bundle-data.service.ts b/src/app/core/data/bundle-data.service.ts index bff21d2c8d..3c885c0afd 100644 --- a/src/app/core/data/bundle-data.service.ts +++ b/src/app/core/data/bundle-data.service.ts @@ -20,7 +20,7 @@ import { PaginatedList } from './paginated-list.model'; import { RemoteData } from './remote-data'; import { FindListOptions, GetRequest } from './request.models'; import { RequestService } from './request.service'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { Bitstream } from '../shared/bitstream.model'; import { RequestEntryState } from './request.reducer'; diff --git a/src/app/core/data/external-source.service.ts b/src/app/core/data/external-source.service.ts index a3a0a532ec..d2fc9e6d96 100644 --- a/src/app/core/data/external-source.service.ts +++ b/src/app/core/data/external-source.service.ts @@ -12,7 +12,7 @@ import { HttpClient } from '@angular/common/http'; import { FindListOptions } from './request.models'; import { Observable } from 'rxjs'; import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { hasValue, isNotEmptyOperator } from '../../shared/empty.util'; import { RemoteData } from './remote-data'; import { PaginatedList } from './paginated-list.model'; diff --git a/src/app/core/data/facet-config-response-parsing.service.ts b/src/app/core/data/facet-config-response-parsing.service.ts index fc543c9072..8c24bd61d9 100644 --- a/src/app/core/data/facet-config-response-parsing.service.ts +++ b/src/app/core/data/facet-config-response-parsing.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; -import { SearchFilterConfig } from '../../shared/search/search-filter-config.model'; +import { SearchFilterConfig } from '../../shared/search/models/search-filter-config.model'; import { ParsedResponse } from '../cache/response.models'; import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { DSpaceSerializer } from '../dspace-rest/dspace.serializer'; import { RestRequest } from './request.models'; import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service'; -import { FacetConfigResponse } from '../../shared/search/facet-config-response.model'; +import { FacetConfigResponse } from '../../shared/search/models/facet-config-response.model'; @Injectable() export class FacetConfigResponseParsingService extends DspaceRestResponseParsingService { diff --git a/src/app/core/data/facet-value-response-parsing.service.ts b/src/app/core/data/facet-value-response-parsing.service.ts index 6b9e832685..12a2d4ba8c 100644 --- a/src/app/core/data/facet-value-response-parsing.service.ts +++ b/src/app/core/data/facet-value-response-parsing.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; -import { FacetValue } from '../../shared/search/facet-value.model'; +import { FacetValue } from '../../shared/search/models/facet-value.model'; import { ParsedResponse } from '../cache/response.models'; import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { DSpaceSerializer } from '../dspace-rest/dspace.serializer'; import { RestRequest } from './request.models'; -import { FacetValues } from '../../shared/search/facet-values.model'; +import { FacetValues } from '../../shared/search/models/facet-values.model'; import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service'; @Injectable() diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts index c31b6b3c97..a8d380124e 100644 --- a/src/app/core/data/item-data.service.ts +++ b/src/app/core/data/item-data.service.ts @@ -25,7 +25,7 @@ import { PaginatedList } from './paginated-list.model'; import { RemoteData } from './remote-data'; import { DeleteRequest, FindListOptions, GetRequest, PostRequest, PutRequest, RestRequest } from './request.models'; import { RequestService } from './request.service'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { Bundle } from '../shared/bundle.model'; import { MetadataMap } from '../shared/metadata.models'; import { BundleDataService } from './bundle-data.service'; diff --git a/src/app/core/data/lookup-relation.service.spec.ts b/src/app/core/data/lookup-relation.service.spec.ts index 876336bfa9..c9e523f796 100644 --- a/src/app/core/data/lookup-relation.service.spec.ts +++ b/src/app/core/data/lookup-relation.service.spec.ts @@ -5,9 +5,9 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.util import { createPaginatedList } from '../../shared/testing/utils.test'; import { buildPaginatedList } from './paginated-list.model'; import { PageInfo } from '../shared/page-info.model'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { RelationshipOptions } from '../../shared/form/builder/models/relationship-options.model'; -import { SearchResult } from '../../shared/search/search-result.model'; +import { SearchResult } from '../../shared/search/models/search-result.model'; import { Item } from '../shared/item.model'; import { skip, take } from 'rxjs/operators'; import { ExternalSource } from '../shared/external-source.model'; diff --git a/src/app/core/data/lookup-relation.service.ts b/src/app/core/data/lookup-relation.service.ts index 7ecf3a19cc..7808a24e92 100644 --- a/src/app/core/data/lookup-relation.service.ts +++ b/src/app/core/data/lookup-relation.service.ts @@ -1,11 +1,11 @@ import { ExternalSourceService } from './external-source.service'; import { SearchService } from '../shared/search/search.service'; import { concat, distinctUntilChanged, map, multicast, startWith, take, takeWhile } from 'rxjs/operators'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { Observable, ReplaySubject } from 'rxjs'; import { RemoteData } from './remote-data'; import { PaginatedList } from './paginated-list.model'; -import { SearchResult } from '../../shared/search/search-result.model'; +import { SearchResult } from '../../shared/search/models/search-result.model'; import { DSpaceObject } from '../shared/dspace-object.model'; import { RelationshipOptions } from '../../shared/form/builder/models/relationship-options.model'; import { Item } from '../shared/item.model'; diff --git a/src/app/core/data/mydspace-response-parsing.service.ts b/src/app/core/data/mydspace-response-parsing.service.ts index f71eaeb811..e111aca9dd 100644 --- a/src/app/core/data/mydspace-response-parsing.service.ts +++ b/src/app/core/data/mydspace-response-parsing.service.ts @@ -4,7 +4,7 @@ import { DSpaceSerializer } from '../dspace-rest/dspace.serializer'; import { RestRequest } from './request.models'; import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { hasValue } from '../../shared/empty.util'; -import { SearchObjects } from '../../shared/search/search-objects.model'; +import { SearchObjects } from '../../shared/search/models/search-objects.model'; import { MetadataMap, MetadataValue } from '../shared/metadata.models'; import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service'; diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index be2fbe90fc..814a2f8d1f 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { hasValue } from '../../shared/empty.util'; -import { SearchObjects } from '../../shared/search/search-objects.model'; +import { SearchObjects } from '../../shared/search/models/search-objects.model'; import { ParsedResponse } from '../cache/response.models'; import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { DSpaceSerializer } from '../dspace-rest/dspace.serializer'; diff --git a/src/app/core/data/version-history-data.service.ts b/src/app/core/data/version-history-data.service.ts index 4268516e6b..9aa4f055ff 100644 --- a/src/app/core/data/version-history-data.service.ts +++ b/src/app/core/data/version-history-data.service.ts @@ -12,7 +12,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; import { FindListOptions, PostRequest, RestRequest } from './request.models'; import { Observable, of } from 'rxjs'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { RemoteData } from './remote-data'; import { PaginatedList } from './paginated-list.model'; import { Version } from '../shared/version.model'; diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 3be04447ab..ea2a0283eb 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -13,7 +13,7 @@ import { withLatestFrom } from 'rxjs/operators'; import { hasNoValue, hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util'; -import { SearchResult } from '../../shared/search/search-result.model'; +import { SearchResult } from '../../shared/search/models/search-result.model'; import { PaginatedList } from '../data/paginated-list.model'; import { RemoteData } from '../data/remote-data'; import { RestRequest } from '../data/request.models'; diff --git a/src/app/core/shared/search/search-configuration.service.spec.ts b/src/app/core/shared/search/search-configuration.service.spec.ts index 805ecd0486..96f9ac5018 100644 --- a/src/app/core/shared/search/search-configuration.service.spec.ts +++ b/src/app/core/shared/search/search-configuration.service.spec.ts @@ -2,8 +2,8 @@ import { SearchConfigurationService } from './search-configuration.service'; import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../cache/models/sort-options.model'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; -import { SearchFilter } from '../../../shared/search/search-filter.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; +import { SearchFilter } from '../../../shared/search/models/search-filter.model'; import { of as observableOf } from 'rxjs'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; diff --git a/src/app/core/shared/search/search-configuration.service.ts b/src/app/core/shared/search/search-configuration.service.ts index 8c37fbc8f5..3b162a60b9 100644 --- a/src/app/core/shared/search/search-configuration.service.ts +++ b/src/app/core/shared/search/search-configuration.service.ts @@ -7,26 +7,23 @@ import { combineLatest as observableCombineLatest, merge as observableMerge, Observable, + of, Subscription } from 'rxjs'; import { distinctUntilChanged, filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { SearchOptions } from '../../../shared/search/search-options.model'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; -import { SearchFilter } from '../../../shared/search/search-filter.model'; +import { SearchOptions } from '../../../shared/search/models/search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; +import { SearchFilter } from '../../../shared/search/models/search-filter.model'; import { RemoteData } from '../../data/remote-data'; import { DSpaceObjectType } from '../dspace-object-type.model'; import { SortDirection, SortOptions } from '../../cache/models/sort-options.model'; import { RouteService } from '../../services/route.service'; -import { - getAllSucceededRemoteDataPayload, - getFirstSucceededRemoteData -} from '../operators'; +import { getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData } from '../operators'; import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { SearchConfig } from './search-filters/search-config.model'; import { SearchService } from './search.service'; -import { of } from 'rxjs'; import { PaginationService } from '../../pagination/pagination.service'; /** diff --git a/src/app/core/shared/search/search-filter.service.spec.ts b/src/app/core/shared/search/search-filter.service.spec.ts index 045b2b17c9..a42bf8e5f6 100644 --- a/src/app/core/shared/search/search-filter.service.spec.ts +++ b/src/app/core/shared/search/search-filter.service.spec.ts @@ -10,8 +10,8 @@ import { SearchFilterToggleAction } from '../../../shared/search/search-filters/search-filter/search-filter.actions'; import { SearchFiltersState } from '../../../shared/search/search-filters/search-filter/search-filter.reducer'; -import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model'; -import { FilterType } from '../../../shared/search/filter-type.model'; +import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model'; +import { FilterType } from '../../../shared/search/models/filter-type.model'; import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { of as observableOf } from 'rxjs'; import { SortDirection, SortOptions } from '../../cache/models/sort-options.model'; diff --git a/src/app/core/shared/search/search-filter.service.ts b/src/app/core/shared/search/search-filter.service.ts index 84d7268abb..00125e31f5 100644 --- a/src/app/core/shared/search/search-filter.service.ts +++ b/src/app/core/shared/search/search-filter.service.ts @@ -16,7 +16,7 @@ import { SearchFilterToggleAction } from '../../../shared/search/search-filters/search-filter/search-filter.actions'; import { hasValue, isNotEmpty, } from '../../../shared/empty.util'; -import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model'; +import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model'; import { SortDirection, SortOptions } from '../../cache/models/sort-options.model'; import { RouteService } from '../../services/route.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; diff --git a/src/app/core/shared/search/search.service.spec.ts b/src/app/core/shared/search/search.service.spec.ts index 00f10230c3..f9b768655e 100644 --- a/src/app/core/shared/search/search.service.spec.ts +++ b/src/app/core/shared/search/search.service.spec.ts @@ -9,7 +9,7 @@ import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { RouterStub } from '../../../shared/testing/router.stub'; import { HALEndpointService } from '../hal-endpoint.service'; import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; import { RemoteData } from '../../data/remote-data'; import { RequestEntry } from '../../data/request.reducer'; import { getMockRequestService } from '../../../shared/mocks/request.service.mock'; @@ -21,11 +21,8 @@ import { RouteService } from '../../services/route.service'; import { routeServiceStub } from '../../../shared/testing/route-service.stub'; import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; -import { SearchObjects } from '../../../shared/search/search-objects.model'; +import { SearchObjects } from '../../../shared/search/models/search-objects.model'; import { PaginationService } from '../../pagination/pagination.service'; -import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { SortDirection, SortOptions } from '../../cache/models/sort-options.model'; -import { FindListOptions } from '../../data/request.models'; import { SearchConfigurationService } from './search-configuration.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts index 91916a35ac..f70416594d 100644 --- a/src/app/core/shared/search/search.service.ts +++ b/src/app/core/shared/search/search.service.ts @@ -14,24 +14,24 @@ import { GenericConstructor } from '../generic-constructor'; import { HALEndpointService } from '../hal-endpoint.service'; import { URLCombiner } from '../../url-combiner/url-combiner'; import { hasValue, hasValueOperator, isNotEmpty } from '../../../shared/empty.util'; -import { SearchOptions } from '../../../shared/search/search-options.model'; -import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model'; +import { SearchOptions } from '../../../shared/search/models/search-options.model'; +import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model'; import { SearchResponseParsingService } from '../../data/search-response-parsing.service'; -import { SearchObjects } from '../../../shared/search/search-objects.model'; +import { SearchObjects } from '../../../shared/search/models/search-objects.model'; import { FacetValueResponseParsingService } from '../../data/facet-value-response-parsing.service'; import { FacetConfigResponseParsingService } from '../../data/facet-config-response-parsing.service'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; import { CommunityDataService } from '../../data/community-data.service'; import { ViewMode } from '../view-mode.model'; import { DSpaceObjectDataService } from '../../data/dspace-object-data.service'; import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service'; import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../operators'; import { RouteService } from '../../services/route.service'; -import { SearchResult } from '../../../shared/search/search-result.model'; +import { SearchResult } from '../../../shared/search/models/search-result.model'; import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model'; import { getSearchResultFor } from '../../../shared/search/search-result-element-decorator'; -import { FacetConfigResponse } from '../../../shared/search/facet-config-response.model'; -import { FacetValues } from '../../../shared/search/facet-values.model'; +import { FacetConfigResponse } from '../../../shared/search/models/facet-config-response.model'; +import { FacetValues } from '../../../shared/search/models/facet-values.model'; import { SearchConfig } from './search-filters/search-config.model'; import { PaginationService } from '../../pagination/pagination.service'; import { SearchConfigurationService } from './search-configuration.service'; @@ -407,6 +407,7 @@ export class SearchService implements OnDestroy { /** * Changes the current view mode in the current URL * @param {ViewMode} viewMode Mode to switch to + * @param {string[]} searchLinkParts */ setViewMode(viewMode: ViewMode, searchLinkParts?: string[]) { this.paginationService.getCurrentPagination(this.searchConfigurationService.paginationID, new PaginationComponentOptions()).pipe(take(1)) diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts index d66c5d060d..42e40b8f6d 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts @@ -15,14 +15,11 @@ import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../../core import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { Bundle } from '../../../core/shared/bundle.model'; -import { - FieldUpdate, - FieldUpdates -} from '../../../core/data/object-updates/object-updates.reducer'; +import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer'; import { Bitstream } from '../../../core/shared/bitstream.model'; import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions'; import { BundleDataService } from '../../../core/data/bundle-data.service'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; import { ResponsiveColumnSizes } from '../../../shared/responsive-table-sizes/responsive-column-sizes'; import { ResponsiveTableSizes } from '../../../shared/responsive-table-sizes/responsive-table-sizes'; import { NoContent } from '../../../core/shared/NoContent.model'; diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts index f3f00abf92..2c81a4e2cb 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts @@ -5,7 +5,7 @@ import { Bitstream } from '../../../../../core/shared/bitstream.model'; import { ObjectUpdatesService } from '../../../../../core/data/object-updates/object-updates.service'; import { BundleDataService } from '../../../../../core/data/bundle-data.service'; import { switchMap } from 'rxjs/operators'; -import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../shared/search/models/paginated-search-options.model'; import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-sizes/responsive-table-sizes'; import { followLink } from '../../../../../shared/utils/follow-link-config.model'; import { ObjectValuesPipe } from '../../../../../shared/utils/object-values-pipe'; diff --git a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts index b5473fa02d..c073f2d63e 100644 --- a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { EventEmitter } from '@angular/core'; -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; @@ -25,7 +25,7 @@ import { ObjectSelectService } from '../../../shared/object-select/object-select import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { SearchFormComponent } from '../../../shared/search-form/search-form.component'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { ObjectSelectServiceStub } from '../../../shared/testing/object-select-service.stub'; diff --git a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts index a7dc8dc1e5..a71fe5b385 100644 --- a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts +++ b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts @@ -9,11 +9,12 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { Collection } from '../../../core/shared/collection.model'; import { Item } from '../../../core/shared/item.model'; import { + getAllSucceededRemoteData, + getFirstCompletedRemoteData, + getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload, - getFirstSucceededRemoteData, - toDSpaceObjectListRD, - getAllSucceededRemoteData, getFirstCompletedRemoteData + toDSpaceObjectListRD } from '../../../core/shared/operators'; import { ActivatedRoute, Router } from '@angular/router'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; @@ -22,7 +23,7 @@ import { TranslateService } from '@ngx-translate/core'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; -import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SearchService } from '../../../core/shared/search/search.service'; import { NoContent } from '../../../core/shared/NoContent.model'; diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts index fe7ff0aacf..c7dd6799d7 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts @@ -3,7 +3,13 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { LinkService } from '../../../../core/cache/builders/link.service'; import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions'; import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service'; -import { combineLatest as observableCombineLatest, from as observableFrom, BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { + BehaviorSubject, + combineLatest as observableCombineLatest, + from as observableFrom, + Observable, + Subscription +} from 'rxjs'; import { FieldUpdate, FieldUpdates, @@ -25,7 +31,7 @@ import { ItemType } from '../../../../core/shared/item-relationships/item-type.m import { DsDynamicLookupRelationModalComponent } from '../../../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component'; import { RelationshipOptions } from '../../../../shared/form/builder/models/relationship-options.model'; import { SelectableListService } from '../../../../shared/object-list/selectable-list/selectable-list.service'; -import { SearchResult } from '../../../../shared/search/search-result.model'; +import { SearchResult } from '../../../../shared/search/models/search-result.model'; import { followLink } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; diff --git a/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts b/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts index fa278da967..b4926d7b92 100644 --- a/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts +++ b/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts @@ -1,16 +1,15 @@ import { of as observableOf } from 'rxjs'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; -import { SearchFilter } from '../shared/search/search-filter.model'; +import { SearchFilter } from '../shared/search/models/search-filter.model'; import { ActivatedRouteStub } from '../shared/testing/active-router.stub'; import { RoleServiceMock } from '../shared/mocks/role-service.mock'; import { cold, hot } from 'jasmine-marbles'; import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type'; import { PaginationServiceStub } from '../shared/testing/pagination-service.stub'; -import { PaginationService } from '../core/pagination/pagination.service'; describe('MyDSpaceConfigurationService', () => { let service: MyDSpaceConfigurationService; diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts index 580afd8ad4..127d266138 100644 --- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts +++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts @@ -13,7 +13,7 @@ import { UploaderOptions } from '../../shared/uploader/uploader-options.model'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { NotificationType } from '../../shared/notifications/models/notification-type'; import { hasValue } from '../../shared/empty.util'; -import { SearchResult } from '../../shared/search/search-result.model'; +import { SearchResult } from '../../shared/search/models/search-result.model'; import { CollectionSelectorComponent } from '../collection-selector/collection-selector.component'; import { UploaderComponent } from '../../shared/uploader/uploader.component'; import { UploaderError } from '../../shared/uploader/uploader-error.model'; diff --git a/src/app/my-dspace-page/my-dspace-page.component.scss b/src/app/my-dspace-page/my-dspace-page.component.scss index b35b2ba709..b9b3e5d2f6 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.scss +++ b/src/app/my-dspace-page/my-dspace-page.component.scss @@ -1 +1 @@ -@import '../search-page/search.component.scss'; +@import '../shared/search/search.component'; diff --git a/src/app/my-dspace-page/my-dspace-page.component.spec.ts b/src/app/my-dspace-page/my-dspace-page.component.spec.ts index b4b75b42a0..6d8bfc274c 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.spec.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.spec.ts @@ -21,7 +21,7 @@ import { routeServiceStub } from '../shared/testing/route-service.stub'; import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service.stub'; import { SearchService } from '../core/shared/search/search.service'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { SearchFilterService } from '../core/shared/search/search-filter.service'; import { RoleDirective } from '../shared/roles/role.directive'; diff --git a/src/app/my-dspace-page/my-dspace-page.component.ts b/src/app/my-dspace-page/my-dspace-page.component.ts index 89a4023be8..bac1713230 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.ts @@ -1,11 +1,4 @@ -import { - ChangeDetectionStrategy, - Component, - Inject, - InjectionToken, - Input, - OnInit -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject, InjectionToken, Input, OnInit } from '@angular/core'; import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'; import { map, switchMap, tap } from 'rxjs/operators'; @@ -15,7 +8,7 @@ import { RemoteData } from '../core/data/remote-data'; import { DSpaceObject } from '../core/shared/dspace-object.model'; import { pushInOut } from '../shared/animations/push'; import { HostWindowService } from '../shared/host-window.service'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; import { SearchService } from '../core/shared/search/search.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { hasValue } from '../shared/empty.util'; @@ -27,10 +20,10 @@ import { SearchConfigurationService } from '../core/shared/search/search-configu import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; import { ViewMode } from '../core/shared/view-mode.model'; import { MyDSpaceRequest } from '../core/data/request.models'; -import { SearchResult } from '../shared/search/search-result.model'; +import { SearchResult } from '../shared/search/models/search-result.model'; import { Context } from '../core/shared/context.model'; import { SortOptions } from '../core/cache/models/sort-options.model'; -import { SearchObjects } from '../shared/search/search-objects.model'; +import { SearchObjects } from '../shared/search/models/search-objects.model'; export const MYDSPACE_ROUTE = '/mydspace'; export const SEARCH_CONFIG_SERVICE: InjectionToken = new InjectionToken('searchConfigurationService'); diff --git a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts index 77f27e9d42..cc8f7c8fc3 100644 --- a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts +++ b/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts @@ -6,8 +6,8 @@ import { PaginatedList } from '../../core/data/paginated-list.model'; import { ViewMode } from '../../core/shared/view-mode.model'; import { isEmpty } from '../../shared/empty.util'; import { Context } from '../../core/shared/context.model'; -import { SearchResult } from '../../shared/search/search-result.model'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { SearchResult } from '../../shared/search/models/search-result.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; /** * Component that represents all results for mydspace page diff --git a/src/app/search-page/configuration-search-page.component.spec.ts b/src/app/search-page/configuration-search-page.component.spec.ts index 5ca593981f..4468aad9c4 100644 --- a/src/app/search-page/configuration-search-page.component.spec.ts +++ b/src/app/search-page/configuration-search-page.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { configureSearchComponentTestingModule } from './search.component.spec'; +import { configureSearchComponentTestingModule } from '../shared/search/search.component.spec'; import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { Component, ViewChild } from '@angular/core'; diff --git a/src/app/search-page/configuration-search-page.component.ts b/src/app/search-page/configuration-search-page.component.ts index df25febde7..6daa822e2e 100644 --- a/src/app/search-page/configuration-search-page.component.ts +++ b/src/app/search-page/configuration-search-page.component.ts @@ -1,13 +1,7 @@ import { HostWindowService } from '../shared/host-window.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { SearchComponent } from './search.component'; -import { - ChangeDetectionStrategy, - Component, - Inject, - Input, - OnInit -} from '@angular/core'; +import { SearchComponent } from '../shared/search/search.component'; +import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core'; import { pushInOut } from '../shared/animations/push'; import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; @@ -21,8 +15,8 @@ import { Router } from '@angular/router'; */ @Component({ selector: 'ds-configuration-search-page', - styleUrls: ['./search.component.scss'], - templateUrl: './search.component.html', + styleUrls: ['../shared/search/search.component.scss'], + templateUrl: '../shared/search/search.component.html', changeDetection: ChangeDetectionStrategy.OnPush, animations: [pushInOut], providers: [ diff --git a/src/app/search-page/search-page.module.ts b/src/app/search-page/search-page.module.ts index d7015974d8..758eca15c0 100644 --- a/src/app/search-page/search-page.module.ts +++ b/src/app/search-page/search-page.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CoreModule } from '../core/core.module'; import { SharedModule } from '../shared/shared.module'; -import { SearchComponent } from './search.component'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'; import { SearchTrackerComponent } from './search-tracker.component'; @@ -18,7 +17,6 @@ import { SearchModule } from '../shared/search/search.module'; const components = [ SearchPageComponent, - SearchComponent, SearchTrackerComponent, ThemedSearchPageComponent ]; diff --git a/src/app/search-page/search-tracker.component.ts b/src/app/search-page/search-tracker.component.ts index e7f59a2f23..f766e6f669 100644 --- a/src/app/search-page/search-tracker.component.ts +++ b/src/app/search-page/search-tracker.component.ts @@ -1,15 +1,15 @@ import { Component, Inject, OnInit } from '@angular/core'; import { Angulartics2 } from 'angulartics2'; import { map, switchMap } from 'rxjs/operators'; -import { SearchComponent } from './search.component'; +import { SearchComponent } from '../shared/search/search.component'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { HostWindowService } from '../shared/host-window.service'; import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; import { RouteService } from '../core/services/route.service'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { SearchService } from '../core/shared/search/search.service'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; -import { SearchObjects } from '../shared/search/search-objects.model'; +import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; +import { SearchObjects } from '../shared/search/models/search-objects.model'; import { Router } from '@angular/router'; import { RemoteData } from '../core/data/remote-data'; import { DSpaceObject } from '../core/shared/dspace-object.model'; diff --git a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts index b6aa0b3413..176d131566 100644 --- a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts @@ -6,7 +6,7 @@ import { Observable } from 'rxjs'; import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { map } from 'rxjs/operators'; import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; -import { SearchResult } from '../../../search/search-result.model'; +import { SearchResult } from '../../../search/models/search-result.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model'; import { followLink } from '../../../utils/follow-link-config.model'; diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts index 2565b36f7d..7c28859388 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts @@ -7,7 +7,7 @@ import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model' import { ItemSearchResult } from '../../object-collection/shared/item-search-result.model'; import { Item } from '../../../core/shared/item.model'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; -import { PaginatedSearchOptions } from '../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../search/models/paginated-search-options.model'; import { hasValue } from '../../empty.util'; import { createPaginatedList } from '../../testing/utils.test'; import { NotificationsService } from '../../notifications/notifications.service'; diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts index ebd9f24b61..82ad095cd4 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts @@ -22,15 +22,15 @@ import { debounceTime, map, startWith, switchMap, tap } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { CollectionElementLinkType } from '../../object-collection/collection-element-link.type'; -import { PaginatedSearchOptions } from '../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../search/models/paginated-search-options.model'; import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { ViewMode } from '../../../core/shared/view-mode.model'; import { Context } from '../../../core/shared/context.model'; import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../empty.util'; -import { PaginatedList, buildPaginatedList } from '../../../core/data/paginated-list.model'; -import { SearchResult } from '../../search/search-result.model'; +import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { RemoteData } from '../../../core/data/remote-data'; import { NotificationsService } from '../../notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 7adb9a837b..eb448a7d24 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -81,7 +81,7 @@ import { DYNAMIC_FORM_CONTROL_TYPE_CUSTOM_SWITCH } from './models/custom-switch/ import { CustomSwitchComponent } from './models/custom-switch/custom-switch.component'; import { find, map, startWith, switchMap, take } from 'rxjs/operators'; import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs'; -import { SearchResult } from '../../../search/search-result.model'; +import { SearchResult } from '../../../search/models/search-result.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { RelationshipService } from '../../../../core/data/relationship.service'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts index 4b4eedeffa..5d81eaf29a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { RouterTestingModule } from '@angular/router/testing'; -import { NgZone, NO_ERRORS_SCHEMA, DebugElement, EventEmitter } from '@angular/core'; +import { DebugElement, NgZone, NO_ERRORS_SCHEMA } from '@angular/core'; import { of as observableOf, Subscription } from 'rxjs'; import { DsDynamicLookupRelationModalComponent } from './dynamic-lookup-relation-modal.component'; import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; @@ -14,7 +14,7 @@ import { ItemSearchResult } from '../../../../object-collection/shared/item-sear import { RelationshipOptions } from '../../models/relationship-options.model'; import { AddRelationshipAction, RemoveRelationshipAction } from './relationship.actions'; import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service'; -import { PaginatedSearchOptions } from '../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../search/models/paginated-search-options.model'; import { ExternalSource } from '../../../../../core/shared/external-source.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; import { createPaginatedList } from '../../../../testing/utils.test'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts index fb5a9474d5..62071a5ad2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts @@ -9,7 +9,7 @@ import { SelectableListService } from '../../../../object-list/selectable-list/s import { SelectableListState } from '../../../../object-list/selectable-list/selectable-list.reducer'; import { ListableObject } from '../../../../object-collection/shared/listable-object.model'; import { RelationshipOptions } from '../../models/relationship-options.model'; -import { SearchResult } from '../../../../search/search-result.model'; +import { SearchResult } from '../../../../search/models/search-result.model'; import { Item } from '../../../../../core/shared/item.model'; import { AddRelationshipAction, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts index 62c33bd967..00b0527af6 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts @@ -4,7 +4,7 @@ import { VarDirective } from '../../../../../utils/var.directive'; import { TranslateModule } from '@ngx-translate/core'; import { RouterTestingModule } from '@angular/router/testing'; import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { of as observableOf } from 'rxjs'; import { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts index 48b9edc82a..ca2535cb91 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts @@ -8,7 +8,7 @@ import { PaginatedList } from '../../../../../../core/data/paginated-list.model' import { ExternalSourceEntry } from '../../../../../../core/shared/external-source-entry.model'; import { ExternalSource } from '../../../../../../core/shared/external-source.model'; import { map, startWith, switchMap } from 'rxjs/operators'; -import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model'; import { Context } from '../../../../../../core/shared/context.model'; import { ListableObject } from '../../../../../object-collection/shared/listable-object.model'; import { fadeIn, fadeInOut } from '../../../../../animations/fade'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts index d586520b64..bf1f2f7e70 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts @@ -6,11 +6,11 @@ import { Metadata } from '../../../../../../../core/shared/metadata.utils'; import { Observable } from 'rxjs'; import { RemoteData } from '../../../../../../../core/data/remote-data'; import { PaginatedList } from '../../../../../../../core/data/paginated-list.model'; -import { SearchResult } from '../../../../../../search/search-result.model'; +import { SearchResult } from '../../../../../../search/models/search-result.model'; import { Item } from '../../../../../../../core/shared/item.model'; import { RelationshipOptions } from '../../../../models/relationship-options.model'; import { LookupRelationService } from '../../../../../../../core/data/lookup-relation.service'; -import { PaginatedSearchOptions } from '../../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../../search/models/paginated-search-options.model'; import { CollectionElementLinkType } from '../../../../../../object-collection/collection-element-link.type'; import { Context } from '../../../../../../../core/shared/context.model'; import { SelectableListService } from '../../../../../../object-list/selectable-list/selectable-list.service'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts index f2e7efeaa5..09929f1973 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts @@ -10,7 +10,7 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { VarDirective } from '../../../../../utils/var.directive'; import { RelationshipOptions } from '../../../models/relationship-options.model'; import { of as observableOf } from 'rxjs'; -import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../remote-data.utils'; import { buildPaginatedList } from '../../../../../../core/data/paginated-list.model'; import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; @@ -21,11 +21,9 @@ import { PaginationService } from '../../../../../../core/pagination/pagination. import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; import { RelationshipService } from '../../../../../../core/data/relationship.service'; import { relatedRelationships } from '../../../../../testing/related-relationships.mock'; -import { RelationshipTypeService } from '../../../../../../core/data/relationship-type.service'; import { RelationshipType } from '../../../../../../core/shared/item-relationships/relationship-type.model'; - describe('DsDynamicLookupRelationSearchTabComponent', () => { let component: DsDynamicLookupRelationSearchTabComponent; let fixture: ComponentFixture; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts index 96af591540..23dd97601e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angu import { SEARCH_CONFIG_SERVICE } from '../../../../../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { Item } from '../../../../../../core/shared/item.model'; -import { SearchResult } from '../../../../../search/search-result.model'; +import { SearchResult } from '../../../../../search/models/search-result.model'; import { PaginatedList } from '../../../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../../../core/data/remote-data'; import { Observable } from 'rxjs'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts index dbe46609a6..472a719b27 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts @@ -4,7 +4,7 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search import { NO_ERRORS_SCHEMA } from '@angular/core'; import { VarDirective } from '../../../../../utils/var.directive'; import { Observable, of as observableOf } from 'rxjs'; -import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model'; import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; import { Item } from '../../../../../../core/shared/item.model'; import { DsDynamicLookupRelationSelectionTabComponent } from './dynamic-lookup-relation-selection-tab.component'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.ts index 9ba0ee2413..a78bf8896c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.ts @@ -8,7 +8,7 @@ import { map, switchMap, take } from 'rxjs/operators'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; import { buildPaginatedList, PaginatedList } from '../../../../../../core/data/paginated-list.model'; import { Router } from '@angular/router'; -import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../../../../search/models/paginated-search-options.model'; import { PageInfo } from '../../../../../../core/shared/page-info.model'; import { Context } from '../../../../../../core/shared/context.model'; import { createSuccessfulRemoteDataObject } from '../../../../../remote-data.utils'; diff --git a/src/app/shared/item/item-versions/item-versions.component.ts b/src/app/shared/item/item-versions/item-versions.component.ts index e7d65919d6..f36e8ab8fe 100644 --- a/src/app/shared/item/item-versions/item-versions.component.ts +++ b/src/app/shared/item/item-versions/item-versions.component.ts @@ -23,7 +23,7 @@ import { map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model'; import { VersionHistoryDataService } from '../../../core/data/version-history-data.service'; -import { PaginatedSearchOptions } from '../../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../search/models/paginated-search-options.model'; import { AlertType } from '../../alert/aletr-type'; import { followLink } from '../../utils/follow-link-config.model'; import { hasValue, hasValueOperator } from '../../empty.util'; diff --git a/src/app/shared/object-collection/shared/claimed-approved-task-search-result.model.ts b/src/app/shared/object-collection/shared/claimed-approved-task-search-result.model.ts index 7cacd87048..71b885d249 100644 --- a/src/app/shared/object-collection/shared/claimed-approved-task-search-result.model.ts +++ b/src/app/shared/object-collection/shared/claimed-approved-task-search-result.model.ts @@ -1,5 +1,5 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; /** * Represents a search result object of an Approved ClaimedTask object diff --git a/src/app/shared/object-collection/shared/claimed-declined-task-search-result.model.ts b/src/app/shared/object-collection/shared/claimed-declined-task-search-result.model.ts index ff775be909..eaf63bf6dd 100644 --- a/src/app/shared/object-collection/shared/claimed-declined-task-search-result.model.ts +++ b/src/app/shared/object-collection/shared/claimed-declined-task-search-result.model.ts @@ -1,5 +1,5 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; /** * Represents a search result object of a Declined ClaimedTask object diff --git a/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts b/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts index 1148ea1526..f8d0752245 100644 --- a/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts +++ b/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts @@ -1,5 +1,5 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; /** diff --git a/src/app/shared/object-collection/shared/collection-search-result.model.ts b/src/app/shared/object-collection/shared/collection-search-result.model.ts index 3b32197533..615ef0809c 100644 --- a/src/app/shared/object-collection/shared/collection-search-result.model.ts +++ b/src/app/shared/object-collection/shared/collection-search-result.model.ts @@ -1,4 +1,4 @@ -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { Collection } from '../../../core/shared/collection.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; diff --git a/src/app/shared/object-collection/shared/community-search-result.model.ts b/src/app/shared/object-collection/shared/community-search-result.model.ts index 9ce936b5d8..e80dfdaecf 100644 --- a/src/app/shared/object-collection/shared/community-search-result.model.ts +++ b/src/app/shared/object-collection/shared/community-search-result.model.ts @@ -1,5 +1,5 @@ import { Community } from '../../../core/shared/community.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; @searchResultFor(Community) diff --git a/src/app/shared/object-collection/shared/item-search-result.model.ts b/src/app/shared/object-collection/shared/item-search-result.model.ts index 4e445f0c88..66f3eb1513 100644 --- a/src/app/shared/object-collection/shared/item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/item-search-result.model.ts @@ -1,4 +1,4 @@ -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { Item } from '../../../core/shared/item.model'; import { inheritEquatable } from '../../../core/utilities/equals.decorators'; import { GenericConstructor } from '../../../core/shared/generic-constructor'; diff --git a/src/app/shared/object-collection/shared/pool-task-search-result.model.ts b/src/app/shared/object-collection/shared/pool-task-search-result.model.ts index 3cff48ba51..9ee74bcd4b 100644 --- a/src/app/shared/object-collection/shared/pool-task-search-result.model.ts +++ b/src/app/shared/object-collection/shared/pool-task-search-result.model.ts @@ -1,5 +1,5 @@ import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; /** diff --git a/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts b/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts index 107b66cbee..8611f8678a 100644 --- a/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts @@ -1,5 +1,5 @@ import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; /** diff --git a/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts b/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts index aa1d4988d4..fddd5dc203 100644 --- a/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts @@ -1,6 +1,6 @@ import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model'; import { searchResultFor } from '../../search/search-result-element-decorator'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; /** * Represents a search result object of a WorkspaceItem object diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts index 5c880133bc..5faf02eac0 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { Metadata } from '../../../../../core/shared/metadata.utils'; import { Item } from '../../../../../core/shared/item.model'; -import { SearchResult } from '../../../../search/search-result.model'; +import { SearchResult } from '../../../../search/models/search-result.model'; /** * This component show values for the given item metadata diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts index 92c1afcb59..778e455004 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts @@ -11,7 +11,7 @@ import { fadeInOut } from '../../../animations/fade'; import { Bitstream } from '../../../../core/shared/bitstream.model'; import { FileService } from '../../../../core/shared/file.service'; import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; -import { SearchResult } from '../../../search/search-result.model'; +import { SearchResult } from '../../../search/models/search-result.model'; /** * This component show metadata for the given item object in the detail view. diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts index e56576a08b..5b0bd2c39b 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts @@ -4,7 +4,7 @@ import { AbstractListableElementComponent } from '../../object-collection/shared import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { hasValue } from '../../empty.util'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; /** * Component representing Search Results with ViewMode.DetailedElement diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts index da1f0ea11b..6e72eaa942 100644 --- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { BitstreamDataService } from '../../../core/data/bitstream-data.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { Metadata } from '../../../core/shared/metadata.utils'; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts index 6d9f325757..840960d51f 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core'; import { Item } from '../../../../core/shared/item.model'; import { fadeInOut } from '../../../animations/fade'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SearchResult } from '../../../search/search-result.model'; +import { SearchResult } from '../../../search/models/search-result.model'; /** * This component show metadata for the given item object in the list view. diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index afd0363e7a..b85fb0a39f 100644 --- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { hasValue } from '../../empty.util'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts index 31ad68ec63..e6bd15df1b 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts @@ -3,7 +3,7 @@ import { VarDirective } from '../../utils/var.directive'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { TruncatableService } from '../../truncatable/truncatable.service'; import { LinkService } from '../../../core/cache/builders/link.service'; diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts index 693d6a9665..91f3ba6d88 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts @@ -1,4 +1,4 @@ -import { SearchResult } from '../../search/search-result.model'; +import { SearchResult } from '../../search/models/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { SearchResultListElementComponent } from '../search-result-list-element/search-result-list-element.component'; import { Component } from '@angular/core'; diff --git a/src/app/shared/page-size-selector/page-size-selector.component.ts b/src/app/shared/page-size-selector/page-size-selector.component.ts index ddfe1ca4d9..0dce32a4ba 100644 --- a/src/app/shared/page-size-selector/page-size-selector.component.ts +++ b/src/app/shared/page-size-selector/page-size-selector.component.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; -import { PaginatedSearchOptions } from '../search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model'; import { map, take } from 'rxjs/operators'; import { PaginationService } from '../../core/pagination/pagination.service'; diff --git a/src/app/shared/search/facet-config-response.model.ts b/src/app/shared/search/models/facet-config-response.model.ts similarity index 62% rename from src/app/shared/search/facet-config-response.model.ts rename to src/app/shared/search/models/facet-config-response.model.ts index 74190d35ba..74e6f10d62 100644 --- a/src/app/shared/search/facet-config-response.model.ts +++ b/src/app/shared/search/models/facet-config-response.model.ts @@ -1,10 +1,10 @@ -import { CacheableObject } from '../../core/cache/object-cache.reducer'; -import { typedObject } from '../../core/cache/builders/build-decorators'; -import { FACET_CONFIG_RESPONSE } from './facet-config-response.resouce-type'; -import { excludeFromEquals } from '../../core/utilities/equals.decorators'; +import { CacheableObject } from '../../../core/cache/object-cache.reducer'; +import { typedObject } from '../../../core/cache/builders/build-decorators'; +import { FACET_CONFIG_RESPONSE } from './types/facet-config-response.resouce-type'; +import { excludeFromEquals } from '../../../core/utilities/equals.decorators'; import { SearchFilterConfig } from './search-filter-config.model'; import { deserialize } from 'cerialize'; -import { HALLink } from '../../core/shared/hal-link.model'; +import { HALLink } from '../../../core/shared/hal-link.model'; /** * The response from the discover/facets endpoint diff --git a/src/app/shared/search/facet-value.model.ts b/src/app/shared/search/models/facet-value.model.ts similarity index 82% rename from src/app/shared/search/facet-value.model.ts rename to src/app/shared/search/models/facet-value.model.ts index 969e531bd2..f545d982ce 100644 --- a/src/app/shared/search/facet-value.model.ts +++ b/src/app/shared/search/models/facet-value.model.ts @@ -1,6 +1,6 @@ import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; -import { HALLink } from '../../core/shared/hal-link.model'; -import { HALResource } from '../../core/shared/hal-resource.model'; +import { HALLink } from '../../../core/shared/hal-link.model'; +import { HALResource } from '../../../core/shared/hal-resource.model'; /** * Class representing possible values for a certain filter diff --git a/src/app/shared/search/facet-values.model.ts b/src/app/shared/search/models/facet-values.model.ts similarity index 72% rename from src/app/shared/search/facet-values.model.ts rename to src/app/shared/search/models/facet-values.model.ts index 31b1f560fb..09bef25876 100644 --- a/src/app/shared/search/facet-values.model.ts +++ b/src/app/shared/search/models/facet-values.model.ts @@ -1,11 +1,11 @@ -import { typedObject } from '../../core/cache/builders/build-decorators'; -import { excludeFromEquals } from '../../core/utilities/equals.decorators'; -import { FACET_VALUES } from './facet-values.resource-type'; +import { typedObject } from '../../../core/cache/builders/build-decorators'; +import { excludeFromEquals } from '../../../core/utilities/equals.decorators'; +import { FACET_VALUES } from './types/facet-values.resource-type'; import { FacetValue } from './facet-value.model'; import { SearchQueryResponse } from './search-query-response.model'; -import { autoserializeAs, autoserialize, inheritSerialization } from 'cerialize'; +import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; import { FilterType } from './filter-type.model'; -import { PaginatedList } from '../../core/data/paginated-list.model'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; @typedObject @inheritSerialization(PaginatedList) diff --git a/src/app/shared/search/filter-type.model.ts b/src/app/shared/search/models/filter-type.model.ts similarity index 100% rename from src/app/shared/search/filter-type.model.ts rename to src/app/shared/search/models/filter-type.model.ts diff --git a/src/app/shared/search/paginated-search-options.model.spec.ts b/src/app/shared/search/models/paginated-search-options.model.spec.ts similarity index 87% rename from src/app/shared/search/paginated-search-options.model.spec.ts rename to src/app/shared/search/models/paginated-search-options.model.spec.ts index 9881cc1149..7afee06abf 100644 --- a/src/app/shared/search/paginated-search-options.model.spec.ts +++ b/src/app/shared/search/models/paginated-search-options.model.spec.ts @@ -1,7 +1,7 @@ -import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; -import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model'; import { PaginatedSearchOptions } from './paginated-search-options.model'; -import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; +import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; import { SearchFilter } from './search-filter.model'; describe('PaginatedSearchOptions', () => { diff --git a/src/app/shared/search/paginated-search-options.model.ts b/src/app/shared/search/models/paginated-search-options.model.ts similarity index 82% rename from src/app/shared/search/paginated-search-options.model.ts rename to src/app/shared/search/models/paginated-search-options.model.ts index 950b207c3a..925a7a3a7e 100644 --- a/src/app/shared/search/paginated-search-options.model.ts +++ b/src/app/shared/search/models/paginated-search-options.model.ts @@ -1,9 +1,9 @@ -import { SortOptions } from '../../core/cache/models/sort-options.model'; -import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; -import { isNotEmpty } from '../empty.util'; +import { SortOptions } from '../../../core/cache/models/sort-options.model'; +import { PaginationComponentOptions } from '../../pagination/pagination-component-options.model'; +import { isNotEmpty } from '../../empty.util'; import { SearchOptions } from './search-options.model'; import { SearchFilter } from './search-filter.model'; -import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; +import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; /** * This model class represents all parameters needed to request information about a certain page of a search request, in a certain order diff --git a/src/app/shared/search/search-filter-config.model.ts b/src/app/shared/search/models/search-filter-config.model.ts similarity index 78% rename from src/app/shared/search/search-filter-config.model.ts rename to src/app/shared/search/models/search-filter-config.model.ts index 1a0be94d2b..129259985a 100644 --- a/src/app/shared/search/search-filter-config.model.ts +++ b/src/app/shared/search/models/search-filter-config.model.ts @@ -1,14 +1,14 @@ import { FilterType } from './filter-type.model'; import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; -import { HALLink } from '../../core/shared/hal-link.model'; -import { typedObject } from '../../core/cache/builders/build-decorators'; -import { CacheableObject } from '../../core/cache/object-cache.reducer'; -import { excludeFromEquals } from '../../core/utilities/equals.decorators'; -import { SEARCH_FILTER_CONFIG } from './search-filter-config.resource-type'; +import { HALLink } from '../../../core/shared/hal-link.model'; +import { typedObject } from '../../../core/cache/builders/build-decorators'; +import { CacheableObject } from '../../../core/cache/object-cache.reducer'; +import { excludeFromEquals } from '../../../core/utilities/equals.decorators'; +import { SEARCH_FILTER_CONFIG } from './types/search-filter-config.resource-type'; - /** - * The configuration for a search filter - */ +/** + * The configuration for a search filter + */ @typedObject export class SearchFilterConfig implements CacheableObject { static type = SEARCH_FILTER_CONFIG; diff --git a/src/app/shared/search/search-filter.model.ts b/src/app/shared/search/models/search-filter.model.ts similarity index 100% rename from src/app/shared/search/search-filter.model.ts rename to src/app/shared/search/models/search-filter.model.ts diff --git a/src/app/shared/search/search-objects.model.ts b/src/app/shared/search/models/search-objects.model.ts similarity index 68% rename from src/app/shared/search/search-objects.model.ts rename to src/app/shared/search/models/search-objects.model.ts index 9974dc64ec..2afbab372b 100644 --- a/src/app/shared/search/search-objects.model.ts +++ b/src/app/shared/search/models/search-objects.model.ts @@ -1,10 +1,10 @@ import { autoserializeAs, inheritSerialization } from 'cerialize'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { SearchResult } from './search-result.model'; -import { PaginatedList } from '../../core/data/paginated-list.model'; -import { typedObject } from '../../core/cache/builders/build-decorators'; -import { SEARCH_OBJECTS } from './search-objects.resource-type'; -import { excludeFromEquals } from '../../core/utilities/equals.decorators'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { typedObject } from '../../../core/cache/builders/build-decorators'; +import { SEARCH_OBJECTS } from './types/search-objects.resource-type'; +import { excludeFromEquals } from '../../../core/utilities/equals.decorators'; import { SearchQueryResponse } from './search-query-response.model'; /** diff --git a/src/app/shared/search/search-options.model.spec.ts b/src/app/shared/search/models/search-options.model.spec.ts similarity index 90% rename from src/app/shared/search/search-options.model.spec.ts rename to src/app/shared/search/models/search-options.model.spec.ts index 8bed046736..176d321999 100644 --- a/src/app/shared/search/search-options.model.spec.ts +++ b/src/app/shared/search/models/search-options.model.spec.ts @@ -1,7 +1,6 @@ -import { PaginatedSearchOptions } from './paginated-search-options.model'; import { SearchOptions } from './search-options.model'; import { SearchFilter } from './search-filter.model'; -import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; +import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; describe('SearchOptions', () => { let options: SearchOptions; diff --git a/src/app/shared/search/search-options.model.ts b/src/app/shared/search/models/search-options.model.ts similarity index 91% rename from src/app/shared/search/search-options.model.ts rename to src/app/shared/search/models/search-options.model.ts index 591e4fcb04..470ef8a06f 100644 --- a/src/app/shared/search/search-options.model.ts +++ b/src/app/shared/search/models/search-options.model.ts @@ -1,8 +1,8 @@ -import { hasValue, isNotEmpty } from '../empty.util'; -import { URLCombiner } from '../../core/url-combiner/url-combiner'; +import { hasValue, isNotEmpty } from '../../empty.util'; +import { URLCombiner } from '../../../core/url-combiner/url-combiner'; import { SearchFilter } from './search-filter.model'; -import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; -import { ViewMode } from '../../core/shared/view-mode.model'; +import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; +import { ViewMode } from '../../../core/shared/view-mode.model'; /** * This model class represents all parameters needed to request information about a certain search request diff --git a/src/app/shared/search/search-query-response.model.ts b/src/app/shared/search/models/search-query-response.model.ts similarity index 87% rename from src/app/shared/search/search-query-response.model.ts rename to src/app/shared/search/models/search-query-response.model.ts index 77e513a918..a436a7c045 100644 --- a/src/app/shared/search/search-query-response.model.ts +++ b/src/app/shared/search/models/search-query-response.model.ts @@ -1,6 +1,6 @@ import { autoserialize } from 'cerialize'; -import { PageInfo } from '../../core/shared/page-info.model'; -import { PaginatedList } from '../../core/data/paginated-list.model'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; /** * Class representing the response returned by the server when performing a search request diff --git a/src/app/shared/search/search-result.model.ts b/src/app/shared/search/models/search-result.model.ts similarity index 59% rename from src/app/shared/search/search-result.model.ts rename to src/app/shared/search/models/search-result.model.ts index c221b2e581..6079c4af63 100644 --- a/src/app/shared/search/search-result.model.ts +++ b/src/app/shared/search/models/search-result.model.ts @@ -1,13 +1,13 @@ import { autoserialize, deserialize } from 'cerialize'; -import { typedObject } from '../../core/cache/builders/build-decorators'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { GenericConstructor } from '../../core/shared/generic-constructor'; -import { HALLink } from '../../core/shared/hal-link.model'; -import { MetadataMap } from '../../core/shared/metadata.models'; -import { excludeFromEquals, fieldsForEquals } from '../../core/utilities/equals.decorators'; -import { ListableObject } from '../object-collection/shared/listable-object.model'; -import { HALResource } from '../../core/shared/hal-resource.model'; -import { SEARCH_RESULT } from './search-result.resource-type'; +import { typedObject } from '../../../core/cache/builders/build-decorators'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { GenericConstructor } from '../../../core/shared/generic-constructor'; +import { HALLink } from '../../../core/shared/hal-link.model'; +import { MetadataMap } from '../../../core/shared/metadata.models'; +import { excludeFromEquals, fieldsForEquals } from '../../../core/utilities/equals.decorators'; +import { ListableObject } from '../../object-collection/shared/listable-object.model'; +import { HALResource } from '../../../core/shared/hal-resource.model'; +import { SEARCH_RESULT } from './types/search-result.resource-type'; /** * Represents a search result object of a certain () DSpaceObject diff --git a/src/app/shared/search/facet-config-response.resouce-type.ts b/src/app/shared/search/models/types/facet-config-response.resouce-type.ts similarity index 75% rename from src/app/shared/search/facet-config-response.resouce-type.ts rename to src/app/shared/search/models/types/facet-config-response.resouce-type.ts index 7c3bdef7ca..83f2ca0e66 100644 --- a/src/app/shared/search/facet-config-response.resouce-type.ts +++ b/src/app/shared/search/models/types/facet-config-response.resouce-type.ts @@ -1,4 +1,4 @@ -import { ResourceType } from '../../core/shared/resource-type'; +import { ResourceType } from '../../../../core/shared/resource-type'; /** * The resource type for FacetConfigResponse diff --git a/src/app/shared/search/facet-values.resource-type.ts b/src/app/shared/search/models/types/facet-values.resource-type.ts similarity index 74% rename from src/app/shared/search/facet-values.resource-type.ts rename to src/app/shared/search/models/types/facet-values.resource-type.ts index e1042bbbc0..c9d6c69c2e 100644 --- a/src/app/shared/search/facet-values.resource-type.ts +++ b/src/app/shared/search/models/types/facet-values.resource-type.ts @@ -1,4 +1,4 @@ -import { ResourceType } from '../../core/shared/resource-type'; +import { ResourceType } from '../../../../core/shared/resource-type'; /** * The resource type for FacetValues diff --git a/src/app/shared/search/search-filter-config.resource-type.ts b/src/app/shared/search/models/types/search-filter-config.resource-type.ts similarity index 75% rename from src/app/shared/search/search-filter-config.resource-type.ts rename to src/app/shared/search/models/types/search-filter-config.resource-type.ts index c2da308207..eb7521b8df 100644 --- a/src/app/shared/search/search-filter-config.resource-type.ts +++ b/src/app/shared/search/models/types/search-filter-config.resource-type.ts @@ -1,4 +1,4 @@ -import { ResourceType } from '../../core/shared/resource-type'; +import { ResourceType } from '../../../../core/shared/resource-type'; /** * The resource type for SearchFilterConfig diff --git a/src/app/shared/search/search-objects.resource-type.ts b/src/app/shared/search/models/types/search-objects.resource-type.ts similarity index 74% rename from src/app/shared/search/search-objects.resource-type.ts rename to src/app/shared/search/models/types/search-objects.resource-type.ts index cf5d7c9c9e..650b02f005 100644 --- a/src/app/shared/search/search-objects.resource-type.ts +++ b/src/app/shared/search/models/types/search-objects.resource-type.ts @@ -1,4 +1,4 @@ -import { ResourceType } from '../../core/shared/resource-type'; +import { ResourceType } from '../../../../core/shared/resource-type'; /** * The resource type for SearchObjects diff --git a/src/app/shared/search/search-result.resource-type.ts b/src/app/shared/search/models/types/search-result.resource-type.ts similarity index 73% rename from src/app/shared/search/search-result.resource-type.ts rename to src/app/shared/search/models/types/search-result.resource-type.ts index 4e18f17db6..354c1898c4 100644 --- a/src/app/shared/search/search-result.resource-type.ts +++ b/src/app/shared/search/models/types/search-result.resource-type.ts @@ -1,4 +1,4 @@ -import { ResourceType } from '../../core/shared/resource-type'; +import { ResourceType } from '../../../../core/shared/resource-type'; /** * The resource type for SearchResult diff --git a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts index 7a20fd5ff0..6dcb47ce9f 100644 --- a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { FilterType } from '../../../filter-type.model'; +import { FilterType } from '../../../models/filter-type.model'; import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; import { renderFacetFor } from '../search-filter-type-decorator'; diff --git a/src/app/shared/search/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts index 49f361e75e..c9da8500d0 100644 --- a/src/app/shared/search/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts @@ -1,10 +1,7 @@ import { Component, OnInit } from '@angular/core'; -import { FilterType } from '../../../filter-type.model'; +import { FilterType } from '../../../models/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; -import { - facetLoad, - SearchFacetFilterComponent -} from '../search-facet-filter/search-facet-filter.component'; +import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; @Component({ selector: 'ds-search-boolean-filter', diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index 7299a39c32..b0f2a51460 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -11,13 +11,11 @@ import { SearchFilterService } from '../../../../../../core/shared/search/search import { SearchService } from '../../../../../../core/shared/search/search.service'; import { RouterStub } from '../../../../../testing/router.stub'; import { SearchServiceStub } from '../../../../../testing/search-service.stub'; -import { FacetValue } from '../../../../facet-value.model'; -import { FilterType } from '../../../../filter-type.model'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { FacetValue } from '../../../../models/facet-value.model'; +import { FilterType } from '../../../../models/filter-type.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; import { SearchFacetOptionComponent } from './search-facet-option.component'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; -import { SortDirection, SortOptions } from '../../../../../../core/cache/models/sort-options.model'; -import { FindListOptions } from '../../../../../../core/data/request.models'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index 11056a232c..cdbab61a30 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -2,8 +2,8 @@ import { combineLatest as observableCombineLatest, Observable, Subscription } fr import { map } from 'rxjs/operators'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { FacetValue } from '../../../../facet-value.model'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { FacetValue } from '../../../../models/facet-value.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; import { SearchService } from '../../../../../../core/shared/search/search.service'; import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts index 9ed8dee0ea..e587913491 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts @@ -2,9 +2,9 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; -import { FilterType } from '../../../../filter-type.model'; -import { FacetValue } from '../../../../facet-value.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; +import { FilterType } from '../../../../models/filter-type.model'; +import { FacetValue } from '../../../../models/facet-value.model'; import { FormsModule } from '@angular/forms'; import { of as observableOf } from 'rxjs'; import { SearchService } from '../../../../../../core/shared/search/search.service'; @@ -20,8 +20,6 @@ import { RANGE_FILTER_MIN_SUFFIX } from '../../search-range-filter/search-range-filter.component'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; -import { SortDirection, SortOptions } from '../../../../../../core/cache/models/sort-options.model'; -import { FindListOptions } from '../../../../../../core/data/request.models'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts index 3d8215b210..b08a54e42b 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts @@ -2,8 +2,8 @@ import { Observable, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { FacetValue } from '../../../../facet-value.model'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { FacetValue } from '../../../../models/facet-value.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; import { SearchService } from '../../../../../../core/shared/search/search.service'; import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; import { diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts index 8f422b41bf..54c447aa61 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts @@ -10,13 +10,11 @@ import { SearchFilterService } from '../../../../../../core/shared/search/search import { SearchService } from '../../../../../../core/shared/search/search.service'; import { RouterStub } from '../../../../../testing/router.stub'; import { SearchServiceStub } from '../../../../../testing/search-service.stub'; -import { FacetValue } from '../../../../facet-value.model'; -import { FilterType } from '../../../../filter-type.model'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { FacetValue } from '../../../../models/facet-value.model'; +import { FilterType } from '../../../../models/filter-type.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; import { SearchFacetSelectedOptionComponent } from './search-facet-selected-option.component'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; -import { SortDirection, SortOptions } from '../../../../../../core/cache/models/sort-options.model'; -import { FindListOptions } from '../../../../../../core/data/request.models'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts index d92455fdd9..4566b882eb 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -1,12 +1,12 @@ import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { SearchFilterConfig } from '../../../../models/search-filter-config.model'; import { SearchService } from '../../../../../../core/shared/search/search.service'; import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; import { hasValue } from '../../../../../empty.util'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; -import { FacetValue } from '../../../../facet-value.model'; +import { FacetValue } from '../../../../models/facet-value.model'; import { currentPath } from '../../../../../utils/route.utils'; import { getFacetValueForType } from '../../../../search.utils'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index 6674b090a7..3f83c766fe 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -1,7 +1,7 @@ import { Component, Injector, Input, OnInit } from '@angular/core'; import { renderFilterType } from '../search-filter-type-decorator'; -import { FilterType } from '../../../filter-type.model'; -import { SearchFilterConfig } from '../../../search-filter-config.model'; +import { FilterType } from '../../../models/filter-type.model'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; import { FILTER_CONFIG, IN_PLACE_SEARCH } from '../../../../../core/shared/search/search-filter.service'; import { GenericConstructor } from '../../../../../core/shared/generic-constructor'; import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index dc58a8c853..919dfc0889 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -7,9 +7,9 @@ import { IN_PLACE_SEARCH, SearchFilterService } from '../../../../../core/shared/search/search-filter.service'; -import { SearchFilterConfig } from '../../../search-filter-config.model'; -import { FilterType } from '../../../filter-type.model'; -import { FacetValue } from '../../../facet-value.model'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; +import { FilterType } from '../../../models/filter-type.model'; +import { FacetValue } from '../../../models/facet-value.model'; import { FormsModule } from '@angular/forms'; import { of as observableOf } from 'rxjs'; import { SearchService } from '../../../../../core/shared/search/search.service'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index 0b28929554..9b898126f0 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -15,14 +15,18 @@ import { PaginatedList } from '../../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../../core/data/remote-data'; import { hasNoValue, hasValue, isNotEmpty } from '../../../../empty.util'; import { EmphasizePipe } from '../../../../utils/emphasize.pipe'; -import { FacetValue } from '../../../facet-value.model'; -import { SearchFilterConfig } from '../../../search-filter-config.model'; +import { FacetValue } from '../../../models/facet-value.model'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; import { SearchService } from '../../../../../core/shared/search/search.service'; -import { FILTER_CONFIG, IN_PLACE_SEARCH, SearchFilterService } from '../../../../../core/shared/search/search-filter.service'; +import { + FILTER_CONFIG, + IN_PLACE_SEARCH, + SearchFilterService +} from '../../../../../core/shared/search/search-filter.service'; import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service'; import { getFirstSucceededRemoteData } from '../../../../../core/shared/operators'; import { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; -import { SearchOptions } from '../../../search-options.model'; +import { SearchOptions } from '../../../models/search-options.model'; import { SEARCH_CONFIG_SERVICE } from '../../../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../../../utils/route.utils'; import { getFacetValueForType, stripOperatorFromFilterValue } from '../../../search.utils'; diff --git a/src/app/shared/search/search-filters/search-filter/search-filter-type-decorator.ts b/src/app/shared/search/search-filters/search-filter/search-filter-type-decorator.ts index 40cff30d41..7c7d721f2e 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter-type-decorator.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter-type-decorator.ts @@ -1,5 +1,4 @@ - -import { FilterType } from '../../filter-type.model'; +import { FilterType } from '../../models/filter-type.model'; /** * Contains the mapping between a facet component and a FilterType diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.actions.ts b/src/app/shared/search/search-filters/search-filter/search-filter.actions.ts index 59a1903eb8..ce1df556c9 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.actions.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.actions.ts @@ -1,7 +1,7 @@ import { Action } from '@ngrx/store'; import { type } from '../../../ngrx/type'; -import { SearchFilterConfig } from '../../search-filter-config.model'; +import { SearchFilterConfig } from '../../models/search-filter-config.model'; /** * For each action type in an action group, make a simple diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts index ee337a503b..1be4c0f2cb 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts @@ -8,8 +8,8 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { SearchFilterService } from '../../../../core/shared/search/search-filter.service'; import { SearchService } from '../../../../core/shared/search/search.service'; import { SearchFilterComponent } from './search-filter.component'; -import { SearchFilterConfig } from '../../search-filter-config.model'; -import { FilterType } from '../../filter-type.model'; +import { SearchFilterConfig } from '../../models/search-filter-config.model'; +import { FilterType } from '../../models/filter-type.model'; import { SearchConfigurationServiceStub } from '../../../testing/search-configuration-service.stub'; import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component'; import { SequenceService } from '../../../../core/shared/sequence.service'; diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index 8bc7502159..1897169a2e 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -3,7 +3,7 @@ import { Component, Inject, Input, OnInit } from '@angular/core'; import { Observable, of as observableOf } from 'rxjs'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; -import { SearchFilterConfig } from '../../search-filter-config.model'; +import { SearchFilterConfig } from '../../models/search-filter-config.model'; import { SearchFilterService } from '../../../../core/shared/search/search-filter.service'; import { slide } from '../../../animations/slide'; import { isNotEmpty } from '../../../empty.util'; diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts index 3b16f84ea5..d2f3de2dc3 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts @@ -1,10 +1,7 @@ import { Component, OnInit } from '@angular/core'; -import { FilterType } from '../../../filter-type.model'; +import { FilterType } from '../../../models/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; -import { - facetLoad, - SearchFacetFilterComponent -} from '../search-facet-filter/search-facet-filter.component'; +import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; @Component({ selector: 'ds-search-hierarchy-filter', diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts index 41f0b4307d..3bdd833c51 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -7,9 +7,9 @@ import { IN_PLACE_SEARCH, SearchFilterService } from '../../../../../core/shared/search/search-filter.service'; -import { SearchFilterConfig } from '../../../search-filter-config.model'; -import { FilterType } from '../../../filter-type.model'; -import { FacetValue } from '../../../facet-value.model'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; +import { FilterType } from '../../../models/filter-type.model'; +import { FacetValue } from '../../../models/facet-value.model'; import { FormsModule } from '@angular/forms'; import { of as observableOf } from 'rxjs'; import { SearchService } from '../../../../../core/shared/search/search.service'; diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 702854dee5..a6b33ddf88 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -3,11 +3,15 @@ import { map, startWith } from 'rxjs/operators'; import { isPlatformBrowser } from '@angular/common'; import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; -import { FilterType } from '../../../filter-type.model'; +import { FilterType } from '../../../models/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; -import { SearchFilterConfig } from '../../../search-filter-config.model'; -import { FILTER_CONFIG, IN_PLACE_SEARCH, SearchFilterService } from '../../../../../core/shared/search/search-filter.service'; +import { SearchFilterConfig } from '../../../models/search-filter-config.model'; +import { + FILTER_CONFIG, + IN_PLACE_SEARCH, + SearchFilterService +} from '../../../../../core/shared/search/search-filter.service'; import { SearchService } from '../../../../../core/shared/search/search.service'; import { Router } from '@angular/router'; import * as moment from 'moment'; diff --git a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts index b2b44ce219..cfd81c3750 100644 --- a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts @@ -1,13 +1,8 @@ import { Component, OnInit } from '@angular/core'; -import { FilterType } from '../../../filter-type.model'; -import { - facetLoad, - SearchFacetFilterComponent -} from '../search-facet-filter/search-facet-filter.component'; +import { FilterType } from '../../../models/filter-type.model'; +import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; import { renderFacetFor } from '../search-filter-type-decorator'; -import { - addOperatorToFilterValue, -} from '../../../search.utils'; +import { addOperatorToFilterValue, } from '../../../search.utils'; /** * This component renders a simple item page. diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 0556da4426..8b870f6467 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -5,7 +5,7 @@ import { map, switchMap } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { RemoteData } from '../../../core/data/remote-data'; -import { SearchFilterConfig } from '../search-filter-config.model'; +import { SearchFilterConfig } from '../models/search-filter-config.model'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SearchFilterService } from '../../../core/shared/search/search-filter.service'; import { getFirstSucceededRemoteData } from '../../../core/shared/operators'; diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 9e466fd620..b13771656e 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { RemoteData } from '../../../core/data/remote-data'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { fadeIn, fadeInOut } from '../../animations/fade'; -import { SearchResult } from '../search-result.model'; +import { SearchResult } from '../models/search-result.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { hasNoValue, isNotEmpty } from '../../empty.util'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; @@ -10,7 +10,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m import { CollectionElementLinkType } from '../../object-collection/collection-element-link.type'; import { ViewMode } from '../../../core/shared/view-mode.model'; import { Context } from '../../../core/shared/context.model'; -import { PaginatedSearchOptions } from '../paginated-search-options.model'; +import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; @Component({ selector: 'ds-search-results', diff --git a/src/app/shared/search/search-settings/search-settings.component.ts b/src/app/shared/search/search-settings/search-settings.component.ts index 9f6cab4a7b..c97410fa5f 100644 --- a/src/app/shared/search/search-settings/search-settings.component.ts +++ b/src/app/shared/search/search-settings/search-settings.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, Input } from '@angular/core'; import { SearchService } from '../../../core/shared/search/search.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { ActivatedRoute, Router } from '@angular/router'; -import { PaginatedSearchOptions } from '../paginated-search-options.model'; +import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { PaginationService } from '../../../core/pagination/pagination.service'; diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.ts index 7f134cacd3..1d858f579d 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.ts +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model'; import { Observable } from 'rxjs'; -import { PaginatedSearchOptions } from '../paginated-search-options.model'; +import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; /** diff --git a/src/app/search-page/search.component.html b/src/app/shared/search/search.component.html similarity index 89% rename from src/app/search-page/search.component.html rename to src/app/shared/search/search.component.html index 3489cccdfb..7886d7190e 100644 --- a/src/app/search-page/search.component.html +++ b/src/app/shared/search/search.component.html @@ -5,7 +5,16 @@
- + +
+ +
+ + + + + +
@@ -26,7 +35,7 @@ [context]="context">
-
+ ; diff --git a/src/app/search-page/search.component.ts b/src/app/shared/search/search.component.ts similarity index 77% rename from src/app/search-page/search.component.ts rename to src/app/shared/search/search.component.ts index 2972175bdf..0fb7ca358a 100644 --- a/src/app/search-page/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -1,26 +1,26 @@ import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { startWith, switchMap } from 'rxjs/operators'; -import { PaginatedList } from '../core/data/paginated-list.model'; -import { RemoteData } from '../core/data/remote-data'; -import { DSpaceObject } from '../core/shared/dspace-object.model'; -import { pushInOut } from '../shared/animations/push'; -import { HostWindowService } from '../shared/host-window.service'; -import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { hasValue, isEmpty } from '../shared/empty.util'; -import { getFirstCompletedRemoteData } from '../core/shared/operators'; -import { RouteService } from '../core/services/route.service'; -import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; -import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model'; -import { SearchResult } from '../shared/search/search-result.model'; -import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; -import { SearchService } from '../core/shared/search/search.service'; -import { currentPath } from '../shared/utils/route.utils'; +import { PaginatedList } from '../../core/data/paginated-list.model'; +import { RemoteData } from '../../core/data/remote-data'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { pushInOut } from '../animations/push'; +import { HostWindowService } from '../host-window.service'; +import { SidebarService } from '../sidebar/sidebar.service'; +import { hasValue, isEmpty } from '../empty.util'; +import { getFirstCompletedRemoteData } from '../../core/shared/operators'; +import { RouteService } from '../../core/services/route.service'; +import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; +import { PaginatedSearchOptions } from './models/paginated-search-options.model'; +import { SearchResult } from './models/search-result.model'; +import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; +import { SearchService } from '../../core/shared/search/search.service'; +import { currentPath } from '../utils/route.utils'; import { Router } from '@angular/router'; -import { Context } from '../core/shared/context.model'; -import { SortOptions } from '../core/cache/models/sort-options.model'; -import { followLink } from '../shared/utils/follow-link-config.model'; -import { Item } from '../core/shared/item.model'; +import { Context } from '../../core/shared/context.model'; +import { SortOptions } from '../../core/cache/models/sort-options.model'; +import { followLink } from '../utils/follow-link-config.model'; +import { Item } from '../../core/shared/item.model'; @Component({ selector: 'ds-search', @@ -104,6 +104,10 @@ export class SearchComponent implements OnInit { */ isSidebarCollapsed$: Observable; + /** + * A boolean representing if show search sidebar button + */ + @Input() showSidebar = true; constructor(protected service: SearchService, protected sidebarService: SidebarService, protected windowService: HostWindowService, diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts index d5816d2a1b..668d260c23 100644 --- a/src/app/shared/search/search.module.ts +++ b/src/app/shared/search/search.module.ts @@ -19,16 +19,18 @@ import { SearchSidebarComponent } from './search-sidebar/search-sidebar.componen import { SearchSettingsComponent } from './search-settings/search-settings.component'; import { ConfigurationSearchPageComponent } from '../../search-page/configuration-search-page.component'; import { ThemedConfigurationSearchPageComponent } from '../../search-page/themed-configuration-search-page.component'; -import { SearchObjects } from './search-objects.model'; -import { FacetConfigResponse } from './facet-config-response.model'; -import { FacetValues } from './facet-values.model'; -import { SearchResult } from './search-result.model'; +import { SearchObjects } from './models/search-objects.model'; +import { FacetConfigResponse } from './models/facet-config-response.model'; +import { FacetValues } from './models/facet-values.model'; +import { SearchResult } from './models/search-result.model'; import { MissingTranslationHandler, TranslateModule } from '@ngx-translate/core'; import { MissingTranslationHelper } from '../translate/missing-translation.helper'; import { SharedModule } from '../shared.module'; import { SearchResultsComponent } from './search-results/search-results.component'; +import { SearchComponent } from './search.component'; const COMPONENTS = [ + SearchComponent, SearchResultsComponent, SearchSidebarComponent, SearchSettingsComponent, diff --git a/src/app/shared/search/search.utils.spec.ts b/src/app/shared/search/search.utils.spec.ts index ca4b4894b1..68ecd87e2a 100644 --- a/src/app/shared/search/search.utils.spec.ts +++ b/src/app/shared/search/search.utils.spec.ts @@ -1,5 +1,5 @@ -import { FacetValue } from './facet-value.model'; -import { SearchFilterConfig } from './search-filter-config.model'; +import { FacetValue } from './models/facet-value.model'; +import { SearchFilterConfig } from './models/search-filter-config.model'; import { addOperatorToFilterValue, escapeRegExp, diff --git a/src/app/shared/search/search.utils.ts b/src/app/shared/search/search.utils.ts index 38c5f568cb..ed81ce46ae 100644 --- a/src/app/shared/search/search.utils.ts +++ b/src/app/shared/search/search.utils.ts @@ -1,5 +1,5 @@ -import { FacetValue } from './facet-value.model'; -import { SearchFilterConfig } from './search-filter-config.model'; +import { FacetValue } from './models/facet-value.model'; +import { SearchFilterConfig } from './models/search-filter-config.model'; import { isNotEmpty } from '../empty.util'; /** diff --git a/src/app/statistics/statistics.service.spec.ts b/src/app/statistics/statistics.service.spec.ts index cdf81afdb6..e4ca6a7059 100644 --- a/src/app/statistics/statistics.service.spec.ts +++ b/src/app/statistics/statistics.service.spec.ts @@ -5,7 +5,7 @@ import { getMockRequestService } from '../shared/mocks/request.service.mock'; import { TrackRequest } from './track-request.model'; import { isEqual } from 'lodash'; import { DSpaceObjectType } from '../core/shared/dspace-object-type.model'; -import { SearchOptions } from '../shared/search/search-options.model'; +import { SearchOptions } from '../shared/search/models/search-options.model'; describe('StatisticsService', () => { let service: StatisticsService; diff --git a/src/app/statistics/statistics.service.ts b/src/app/statistics/statistics.service.ts index 9e12e627b5..81c79c4c43 100644 --- a/src/app/statistics/statistics.service.ts +++ b/src/app/statistics/statistics.service.ts @@ -6,7 +6,7 @@ import { TrackRequest } from './track-request.model'; import { hasValue, isNotEmpty } from '../shared/empty.util'; import { HALEndpointService } from '../core/shared/hal-endpoint.service'; import { RestRequest } from '../core/data/request.models'; -import { SearchOptions } from '../shared/search/search-options.model'; +import { SearchOptions } from '../shared/search/models/search-options.model'; /** * The statistics service diff --git a/src/app/submission/import-external/submission-import-external.component.spec.ts b/src/app/submission/import-external/submission-import-external.component.spec.ts index 20f36995a6..dc53b2e45f 100644 --- a/src/app/submission/import-external/submission-import-external.component.spec.ts +++ b/src/app/submission/import-external/submission-import-external.component.spec.ts @@ -17,7 +17,7 @@ import { createPaginatedList, createTestComponent } from '../../shared/testing/u import { RouterStub } from '../../shared/testing/router.stub'; import { VarDirective } from '../../shared/utils/var.directive'; import { routeServiceStub } from '../../shared/testing/route-service.stub'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { ExternalSourceEntry } from '../../core/shared/external-source-entry.model'; diff --git a/src/themes/custom/app/search-page/configuration-search-page.component.ts b/src/themes/custom/app/search-page/configuration-search-page.component.ts index b578ed5d8c..159434c7a8 100644 --- a/src/themes/custom/app/search-page/configuration-search-page.component.ts +++ b/src/themes/custom/app/search-page/configuration-search-page.component.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { pushInOut } from '../../../../app/shared/animations/push'; import { SEARCH_CONFIG_SERVICE } from '../../../../app/my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../../../../app/core/shared/search/search-configuration.service'; @@ -7,9 +7,9 @@ import { ConfigurationSearchPageComponent as BaseComponent } from '../../../../a @Component({ selector: 'ds-configuration-search-page', // styleUrls: ['./configuration-search-page.component.scss'], - styleUrls: ['../../../../app/search-page/search.component.scss'], + styleUrls: ['../../../../app/shared/search/search.component.scss'], // templateUrl: './configuration-search-page.component.html' - templateUrl: '../../../../app/search-page/search.component.html', + templateUrl: '../../../../app/shared/search/search.component.html', changeDetection: ChangeDetectionStrategy.OnPush, animations: [pushInOut], providers: [ From ef18308893e66ca119cdaf2316f0958ed69ea062 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 17 Dec 2021 19:35:28 +0100 Subject: [PATCH 29/77] [CST-4633] Refactoring of search.component in order to have all functionality used during the different search components --- .../search/search-configuration.service.ts | 219 +++++++------- .../search-navbar/search-navbar.component.ts | 12 +- src/app/search-page/search-page.component.ts | 8 + .../search-form/search-form.component.ts | 3 - .../search-results.component.html | 6 +- .../search-results.component.ts | 7 + .../search-settings.component.html | 20 +- .../search-settings.component.spec.ts | 6 +- .../search-settings.component.ts | 8 +- .../search-sidebar.component.html | 8 +- .../search-sidebar.component.ts | 17 +- .../search-configuration-option.model.ts | 7 + ...search-switch-configuration.component.html | 2 +- ...rch-switch-configuration.component.spec.ts | 30 +- .../search-switch-configuration.component.ts | 25 +- src/app/shared/search/search.component.html | 22 +- .../shared/search/search.component.spec.ts | 60 ++-- src/app/shared/search/search.component.ts | 274 ++++++++++++------ 18 files changed, 450 insertions(+), 284 deletions(-) diff --git a/src/app/core/shared/search/search-configuration.service.ts b/src/app/core/shared/search/search-configuration.service.ts index 3b162a60b9..03e46cac65 100644 --- a/src/app/core/shared/search/search-configuration.service.ts +++ b/src/app/core/shared/search/search-configuration.service.ts @@ -3,14 +3,12 @@ import { ActivatedRoute, Params } from '@angular/router'; import { BehaviorSubject, - combineLatest, combineLatest as observableCombineLatest, merge as observableMerge, Observable, - of, Subscription } from 'rxjs'; -import { distinctUntilChanged, filter, map, startWith, switchMap, take } from 'rxjs/operators'; +import { filter, map, startWith } from 'rxjs/operators'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { SearchOptions } from '../../../shared/search/models/search-options.model'; import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; @@ -22,7 +20,7 @@ import { RouteService } from '../../services/route.service'; import { getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData } from '../operators'; import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; -import { SearchConfig } from './search-filters/search-config.model'; +import { SearchConfig, SortOption } from './search-filters/search-config.model'; import { SearchService } from './search.service'; import { PaginationService } from '../../pagination/pagination.service'; @@ -33,6 +31,14 @@ import { PaginationService } from '../../pagination/pagination.service'; export class SearchConfigurationService implements OnDestroy { public paginationID = 'spc'; + /** + * Emits the current search options + */ + public searchOptions: BehaviorSubject; + /** + * Emits the current search options including pagination and sort + */ + public paginatedSearchOptions: BehaviorSubject; /** * Default pagination settings */ @@ -41,50 +47,23 @@ export class SearchConfigurationService implements OnDestroy { pageSize: 10, currentPage: 1 }); - - /** - * Default sort settings - */ - protected defaultSort = new SortOptions('score', SortDirection.DESC); - - /** - * Default configuration parameter setting - */ - protected defaultConfiguration; - /** * Default scope setting */ protected defaultScope = ''; - /** * Default query setting */ protected defaultQuery = ''; - /** - * Emits the current default values + * A map of subscriptions to unsubscribe from on destroy */ - protected _defaults: Observable>; - - /** - * Emits the current search options - */ - public searchOptions: BehaviorSubject; - - /** - * Emits the current search options including pagination and sort - */ - public paginatedSearchOptions: BehaviorSubject; - - /** - * List of subscriptions to unsubscribe from on destroy - */ - protected subs: Subscription[] = []; + protected subs: Map = new Map(null); /** * Initialize the search options * @param {RouteService} routeService + * @param {PaginationService} paginationService * @param {ActivatedRoute} route */ constructor(protected routeService: RouteService, @@ -95,19 +74,23 @@ export class SearchConfigurationService implements OnDestroy { } /** - * Initialize the search options + * Emits the current default values */ - protected initDefaults() { - this.defaults - .pipe(getFirstSucceededRemoteData()) - .subscribe((defRD: RemoteData) => { - const defs = defRD.payload; - this.paginatedSearchOptions = new BehaviorSubject(defs); - this.searchOptions = new BehaviorSubject(defs); - this.subs.push(this.subscribeToSearchOptions(defs)); - this.subs.push(this.subscribeToPaginatedSearchOptions(defs.pagination.id, defs)); - } - ); + protected _defaults: Observable>; + + /** + * Default values for the Search Options + */ + get defaults(): Observable> { + if (hasNoValue(this._defaults)) { + const options = new PaginatedSearchOptions({ + pagination: this.defaultPagination, + scope: this.defaultScope, + query: this.defaultQuery + }); + this._defaults = createSuccessfulRemoteDataObject$(options, new Date().getTime()); + } + return this._defaults; } /** @@ -205,59 +188,82 @@ export class SearchConfigurationService implements OnDestroy { } /** - * Creates an observable of SearchConfig every time the configuration$ stream emits. - * @param configuration$ - * @param service + * Creates an observable of SearchConfig every time the configuration stream emits. + * @param configuration The search configuration + * @param service The serach service to use + * @param scope The search scope if exists */ - getConfigurationSearchConfigObservable(configuration$: Observable, service: SearchService): Observable { - return configuration$.pipe( - distinctUntilChanged(), - switchMap((configuration) => service.getSearchConfigurationFor(null, configuration)), - getAllSucceededRemoteDataPayload()); + getConfigurationSearchConfig(configuration: string, service: SearchService, scope?: string): Observable { + return service.getSearchConfigurationFor(scope, configuration).pipe( + getAllSucceededRemoteDataPayload() + ); } /** - * Every time searchConfig change (after a configuration change) it update the navigation with the default sort option - * and emit the new paginateSearchOptions value. - * @param configuration$ - * @param service + * Return the SortOptions list available for the given SearchConfig + * @param searchConfig The SearchConfig object */ - initializeSortOptionsFromConfiguration(searchConfig$: Observable) { - const subscription = searchConfig$.pipe(switchMap((searchConfig) => combineLatest([ - of(searchConfig), - this.paginatedSearchOptions.pipe(take(1)) - ]))).subscribe(([searchConfig, searchOptions]) => { - const field = searchConfig.sortOptions[0].name; - const direction = searchConfig.sortOptions[0].sortOrder.toLowerCase() === SortDirection.ASC.toLowerCase() ? SortDirection.ASC : SortDirection.DESC; - const updateValue = Object.assign(new PaginatedSearchOptions({}), searchOptions, { - sort: new SortOptions(field, direction) - }); - this.paginationService.updateRoute(this.paginationID, - { - sortDirection: updateValue.sort.direction, - sortField: updateValue.sort.field, - }); - this.paginatedSearchOptions.next(updateValue); - }); - this.subs.push(subscription); - } - - /** - * Creates an observable of available SortOptions[] every time the searchConfig$ stream emits. - * @param searchConfig$ - * @param service - */ - getConfigurationSortOptionsObservable(searchConfig$: Observable): Observable { - return searchConfig$.pipe(map((searchConfig) => { - const sortOptions = []; - searchConfig.sortOptions.forEach(sortOption => { - sortOptions.push(new SortOptions(sortOption.name, SortDirection.ASC)); - sortOptions.push(new SortOptions(sortOption.name, SortDirection.DESC)); - }); - return sortOptions; + getConfigurationSortOptions(searchConfig: SearchConfig): SortOptions[] { + return searchConfig.sortOptions.map((entry: SortOption) => ({ + field: entry.name, + direction: entry.sortOrder.toLowerCase() === SortDirection.ASC.toLowerCase() ? SortDirection.ASC : SortDirection.DESC })); } + setPaginationId(paginationId): void { + if (isNotEmpty(paginationId)) { + const currentValue: PaginatedSearchOptions = this.paginatedSearchOptions.getValue(); + const updatedValue: PaginatedSearchOptions = Object.assign(new PaginatedSearchOptions({}), currentValue, { + pagination: Object.assign({}, currentValue.pagination, { + id: paginationId + }) + }); + // unsubscribe from subscription related to old pagination id + this.unsubscribeFromSearchOptions(this.paginationID); + + // change to the new pagination id + this.paginationID = paginationId; + this.paginatedSearchOptions.next(updatedValue); + this.setSearchSubscription(this.paginationID, this.paginatedSearchOptions.value); + } + } + + /** + * Make sure to unsubscribe from all existing subscription to prevent memory leaks + */ + ngOnDestroy(): void { + this.subs + .forEach((subs: Subscription[]) => subs + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()) + ); + + this.subs = new Map(null); + } + + /** + * Initialize the search options + */ + protected initDefaults() { + this.defaults + .pipe(getFirstSucceededRemoteData()) + .subscribe((defRD: RemoteData) => { + const defs = defRD.payload; + this.paginatedSearchOptions = new BehaviorSubject(defs); + this.searchOptions = new BehaviorSubject(defs); + this.setSearchSubscription(this.paginationID, defs); + }); + } + + private setSearchSubscription(paginationID: string, defaults: PaginatedSearchOptions) { + this.unsubscribeFromSearchOptions(paginationID); + const subs = [ + this.subscribeToSearchOptions(defaults), + this.subscribeToPaginatedSearchOptions(paginationID || defaults.pagination.id, defaults) + ]; + this.subs.set(this.paginationID, subs); + } + /** * Sets up a subscription to all necessary parameters to make sure the searchOptions emits a new value every time they update * @param {SearchOptions} defaults Default values for when no parameters are available @@ -280,6 +286,7 @@ export class SearchConfigurationService implements OnDestroy { /** * Sets up a subscription to all necessary parameters to make sure the paginatedSearchOptions emits a new value every time they update + * @param {string} paginationId The pagination ID * @param {PaginatedSearchOptions} defaults Default values for when no parameters are available * @returns {Subscription} The subscription to unsubscribe from */ @@ -301,30 +308,16 @@ export class SearchConfigurationService implements OnDestroy { } /** - * Default values for the Search Options + * Unsubscribe from all subscriptions related to the given paginationID + * @param paginationId The pagination id */ - get defaults(): Observable> { - if (hasNoValue(this._defaults)) { - const options = new PaginatedSearchOptions({ - pagination: this.defaultPagination, - configuration: this.defaultConfiguration, - sort: this.defaultSort, - scope: this.defaultScope, - query: this.defaultQuery - }); - this._defaults = createSuccessfulRemoteDataObject$(options, new Date().getTime()); + private unsubscribeFromSearchOptions(paginationId: string): void { + if (this.subs.has(this.paginationID)) { + this.subs.get(this.paginationID) + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()); + this.subs.delete(paginationId); } - return this._defaults; - } - - /** - * Make sure to unsubscribe from all existing subscription to prevent memory leaks - */ - ngOnDestroy(): void { - this.subs.forEach((sub) => { - sub.unsubscribe(); - }); - this.subs = []; } /** diff --git a/src/app/search-navbar/search-navbar.component.ts b/src/app/search-navbar/search-navbar.component.ts index 1e509a180b..26849adf6d 100644 --- a/src/app/search-navbar/search-navbar.component.ts +++ b/src/app/search-navbar/search-navbar.component.ts @@ -3,8 +3,6 @@ import { FormBuilder } from '@angular/forms'; import { Router } from '@angular/router'; import { SearchService } from '../core/shared/search/search.service'; import { expandSearchInput } from '../shared/animations/slide'; -import { PaginationService } from '../core/pagination/pagination.service'; -import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; /** * The search box in the header that expands on focus and collapses on focus out @@ -26,9 +24,7 @@ export class SearchNavbarComponent { // Search input field @ViewChild('searchInput') searchField: ElementRef; - constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService, - private paginationService: PaginationService, - private searchConfig: SearchConfigurationService) { + constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService) { this.searchForm = this.formBuilder.group(({ query: '', })); @@ -65,8 +61,12 @@ export class SearchNavbarComponent { */ onSubmit(data: any) { this.collapse(); + const queryParams = Object.assign({}, data); const linkToNavigateTo = this.searchService.getSearchLink().split('/'); this.searchForm.reset(); - this.paginationService.updateRouteWithUrl(this.searchConfig.paginationID, linkToNavigateTo, {page: 1}, data); + this.router.navigate(linkToNavigateTo, { + queryParams: queryParams, + queryParamsHandling: 'merge' + }); } } diff --git a/src/app/search-page/search-page.component.ts b/src/app/search-page/search-page.component.ts index 393af37c27..38647b779b 100644 --- a/src/app/search-page/search-page.component.ts +++ b/src/app/search-page/search-page.component.ts @@ -1,8 +1,16 @@ import { Component } from '@angular/core'; +import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; +import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; @Component({ selector: 'ds-search-page', templateUrl: './search-page.component.html', + providers: [ + { + provide: SEARCH_CONFIG_SERVICE, + useClass: SearchConfigurationService + } + ] }) /** * This component represents the whole search page diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts index cb9b43dbd1..caf6a91046 100644 --- a/src/app/shared/search-form/search-form.component.ts +++ b/src/app/shared/search-form/search-form.component.ts @@ -116,14 +116,11 @@ export class SearchFormComponent implements OnInit { */ updateSearch(data: any) { const queryParams = Object.assign({}, data); - const pageParam = this.paginationService.getPageParam(this.searchConfig.paginationID); - queryParams[pageParam] = 1; this.router.navigate(this.getSearchLinkParts(), { queryParams: queryParams, queryParamsHandling: 'merge' }); - this.paginationService.updateRouteWithUrl(this.searchConfig.paginationID, this.getSearchLinkParts(), { page: 1 }, data); } /** diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 23850f50dd..c383a2fa1a 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,5 +1,5 @@

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

-
+
- + diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index b13771656e..f7c5dcf5b7 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -78,6 +78,13 @@ export class SearchResultsComponent { @Output() selectObject: EventEmitter = new EventEmitter(); + /** + * Check if search results are loading + */ + isLoading() { + return !this.showError() && (hasNoValue(this.searchResults) || hasNoValue(this.searchResults.payload) || this.searchResults.isLoading); + } + showError(): boolean { return this.searchResults?.hasFailed && (!this.searchResults?.errorMessage || this.searchResults?.statusCode !== 400); } diff --git a/src/app/shared/search/search-settings/search-settings.component.html b/src/app/shared/search/search-settings/search-settings.component.html index a31678743d..40bca8e4e8 100644 --- a/src/app/shared/search/search-settings/search-settings.component.html +++ b/src/app/shared/search/search-settings/search-settings.component.html @@ -1,16 +1,14 @@ - +

{{ 'search.sidebar.settings.title' | translate}}

- -
diff --git a/src/app/shared/search/search-settings/search-settings.component.spec.ts b/src/app/shared/search/search-settings/search-settings.component.spec.ts index 6cf8ffc618..06e506ddb0 100644 --- a/src/app/shared/search/search-settings/search-settings.component.spec.ts +++ b/src/app/shared/search/search-settings/search-settings.component.spec.ts @@ -102,14 +102,12 @@ describe('SearchSettingsComponent', () => { fixture = TestBed.createComponent(SearchSettingsComponent); comp = fixture.componentInstance; - comp.sortOptions = [ + comp.sortOptionsList = [ new SortOptions('score', SortDirection.DESC), new SortOptions('dc.title', SortDirection.ASC), new SortOptions('dc.title', SortDirection.DESC) ]; - comp.searchOptions = paginatedSearchOptions; - // SearchPageComponent test instance fixture.detectChanges(); searchServiceObject = (comp as any).service; @@ -123,7 +121,7 @@ describe('SearchSettingsComponent', () => { const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings')); expect(orderSetting).toBeDefined(); const childElements = orderSetting.queryAll(By.css('option')); - expect(childElements.length).toEqual(comp.sortOptions.length); + expect(childElements.length).toEqual(comp.sortOptionsList.length); }); it('it should show the size settings', () => { diff --git a/src/app/shared/search/search-settings/search-settings.component.ts b/src/app/shared/search/search-settings/search-settings.component.ts index c97410fa5f..0efd38b5b2 100644 --- a/src/app/shared/search/search-settings/search-settings.component.ts +++ b/src/app/shared/search/search-settings/search-settings.component.ts @@ -2,7 +2,6 @@ import { Component, Inject, Input } from '@angular/core'; import { SearchService } from '../../../core/shared/search/search.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { ActivatedRoute, Router } from '@angular/router'; -import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { PaginationService } from '../../../core/pagination/pagination.service'; @@ -17,16 +16,15 @@ import { PaginationService } from '../../../core/pagination/pagination.service'; * This component represents the part of the search sidebar that contains the general search settings. */ export class SearchSettingsComponent { - /** - * The configuration for the current paginated search results + * The current sort option used */ - @Input() searchOptions: PaginatedSearchOptions; + @Input() currentSortOption: SortOptions; /** * All sort options that are shown in the settings */ - @Input() sortOptions: SortOptions[]; + @Input() sortOptionsList: SortOptions[]; constructor(private service: SearchService, private route: ActivatedRoute, diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.html b/src/app/shared/search/search-sidebar/search-sidebar.component.html index 624d094d22..c19831d71d 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.html +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.html @@ -10,9 +10,13 @@
diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.ts index 1d858f579d..f9f7165401 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.ts +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.ts @@ -22,11 +22,21 @@ import { SortOptions } from '../../../core/cache/models/sort-options.model'; */ export class SearchSidebarComponent { + /** + * The configuration to use for the search options + */ + @Input() configuration; + /** * The list of available configuration options */ @Input() configurationList: SearchConfigurationOption[]; + /** + * The current sort option used + */ + @Input() currentSortOption: SortOptions; + /** * The total amount of results */ @@ -55,7 +65,7 @@ export class SearchSidebarComponent { /** * All sort options that are shown in the settings */ - @Input() sortOptions: SortOptions[]; + @Input() sortOptionsList: SortOptions[]; /** * Emits when the search filters values may be stale, and so they must be refreshed. @@ -67,4 +77,9 @@ export class SearchSidebarComponent { */ @Output() toggleSidebar = new EventEmitter(); + /** + * Emits event when the user select a new configuration + */ + @Output() changeConfiguration: EventEmitter = new EventEmitter(); + } diff --git a/src/app/shared/search/search-switch-configuration/search-configuration-option.model.ts b/src/app/shared/search/search-switch-configuration/search-configuration-option.model.ts index 6f9a72da48..d59f7b74b1 100644 --- a/src/app/shared/search/search-switch-configuration/search-configuration-option.model.ts +++ b/src/app/shared/search/search-switch-configuration/search-configuration-option.model.ts @@ -1,6 +1,8 @@ /** * Represents a search configuration select option */ +import { Context } from '../../../core/shared/context.model'; + export interface SearchConfigurationOption { /** @@ -12,4 +14,9 @@ export interface SearchConfigurationOption { * The select option label */ label: string; + + /** + * The search context to use with the configuration + */ + context: Context; } diff --git a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html index e66483b645..f63bf9fa84 100644 --- a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html +++ b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html @@ -6,7 +6,7 @@ [compareWith]="compare" [(ngModel)]="selectedOption" (change)="onSelect()"> - diff --git a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.spec.ts b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.spec.ts index 3c0b9d156b..94e05b64fe 100644 --- a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.spec.ts +++ b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.spec.ts @@ -13,6 +13,7 @@ import { SearchService } from '../../../core/shared/search/search.service'; import { MYDSPACE_ROUTE, SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { MyDSpaceConfigurationValueType } from '../../../my-dspace-page/my-dspace-configuration-value-type'; import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; +import { Context } from '../../../core/shared/context.model'; describe('SearchSwitchConfigurationComponent', () => { @@ -25,6 +26,18 @@ describe('SearchSwitchConfigurationComponent', () => { getSearchLink: jasmine.createSpy('getSearchLink') }); + const configurationList = [ + { + value: MyDSpaceConfigurationValueType.Workspace, + label: 'workspace', + context: Context.Workspace + }, + { + value: MyDSpaceConfigurationValueType.Workflow, + label: 'workflow', + context: Context.Workflow + }, + ]; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ @@ -52,16 +65,7 @@ describe('SearchSwitchConfigurationComponent', () => { spyOn(searchConfService, 'getCurrentConfiguration').and.returnValue(observableOf(MyDSpaceConfigurationValueType.Workspace)); - comp.configurationList = [ - { - value: MyDSpaceConfigurationValueType.Workspace, - label: 'workspace' - }, - { - value: MyDSpaceConfigurationValueType.Workflow, - label: 'workflow' - }, - ]; + comp.configurationList = configurationList; // SearchSwitchConfigurationComponent test instance fixture.detectChanges(); @@ -69,7 +73,7 @@ describe('SearchSwitchConfigurationComponent', () => { }); it('should init the current configuration name', () => { - expect(comp.selectedOption).toBe(MyDSpaceConfigurationValueType.Workspace); + expect(comp.selectedOption).toBe(configurationList[0]); }); it('should display select field properly', () => { @@ -95,7 +99,8 @@ describe('SearchSwitchConfigurationComponent', () => { it('should navigate to the route when selecting an option', () => { spyOn((comp as any), 'getSearchLinkParts').and.returnValue([MYDSPACE_ROUTE]); - comp.selectedOption = MyDSpaceConfigurationValueType.Workflow; + spyOn((comp as any).changeConfiguration, 'emit'); + comp.selectedOption = configurationList[1]; const navigationExtras: NavigationExtras = { queryParams: { configuration: MyDSpaceConfigurationValueType.Workflow }, }; @@ -105,5 +110,6 @@ describe('SearchSwitchConfigurationComponent', () => { comp.onSelect(); expect((comp as any).router.navigate).toHaveBeenCalledWith([MYDSPACE_ROUTE], navigationExtras); + expect((comp as any).changeConfiguration.emit).toHaveBeenCalled(); }); }); diff --git a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.ts b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.ts index 061ca96a70..1852277673 100644 --- a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.ts +++ b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { NavigationExtras, Router } from '@angular/router'; import { Subscription } from 'rxjs'; @@ -10,6 +10,7 @@ import { MyDSpaceConfigurationValueType } from '../../../my-dspace-page/my-dspac import { SearchConfigurationOption } from './search-configuration-option.model'; import { SearchService } from '../../../core/shared/search/search.service'; import { currentPath } from '../../utils/route.utils'; +import { findIndex } from 'lodash'; @Component({ selector: 'ds-search-switch-configuration', @@ -29,17 +30,25 @@ export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit { * The list of available configuration options */ @Input() configurationList: SearchConfigurationOption[] = []; - + /** + * The default configuration to use if no defined + */ + @Input() defaultConfiguration: string; /** * The selected option */ - public selectedOption: string; + public selectedOption: SearchConfigurationOption; /** * Subscription to unsubscribe from */ private sub: Subscription; + /** + * Emits event when the user select a new configuration + */ + @Output() changeConfiguration: EventEmitter = new EventEmitter(); + constructor(private router: Router, private searchService: SearchService, @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { @@ -49,8 +58,11 @@ export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit { * Init current configuration */ ngOnInit() { - this.searchConfigService.getCurrentConfiguration('default') - .subscribe((currentConfiguration) => this.selectedOption = currentConfiguration); + this.searchConfigService.getCurrentConfiguration(this.defaultConfiguration) + .subscribe((currentConfiguration) => { + const index = findIndex(this.configurationList, {value: currentConfiguration }); + this.selectedOption = this.configurationList[index]; + }); } /** @@ -58,9 +70,10 @@ export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit { */ onSelect() { const navigationExtras: NavigationExtras = { - queryParams: {configuration: this.selectedOption}, + queryParams: {configuration: this.selectedOption.value}, }; + this.changeConfiguration.emit(this.selectedOption); this.router.navigate(this.getSearchLinkParts(), navigationExtras); } diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index 7886d7190e..f21dbeab22 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -21,7 +21,7 @@
- +
+ [context]="(currentContext$ | async)">
+ [sortOptionsList]="(sortOptionsList$ | async)" + [currentSortOption]="(currentSortOptions$ | async)" + [inPlaceSearch]="inPlaceSearch" + (changeConfiguration)="changeContext($event.context)"> + [sortOptionsList]="(sortOptionsList$ | async)" + [currentSortOption]="(currentSortOptions$ | async)" + (toggleSidebar)="closeSidebar()" + (changeConfiguration)="changeContext($event.context)"> diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts index 0f77e04044..bfa4931670 100644 --- a/src/app/shared/search/search.component.spec.ts +++ b/src/app/shared/search/search.component.spec.ts @@ -4,7 +4,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { Store } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; -import { cold, hot } from 'jasmine-marbles'; +import { cold } from 'jasmine-marbles'; import { of as observableOf } from 'rxjs'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { CommunityDataService } from '../../core/data/community-data.service'; @@ -21,10 +21,11 @@ import { SearchFilterService } from '../../core/shared/search/search-filter.serv import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { RouteService } from '../../core/services/route.service'; -import { SearchConfigurationServiceStub } from '../testing/search-configuration-service.stub'; import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { PaginatedSearchOptions } from './models/paginated-search-options.model'; import { SidebarServiceStub } from '../testing/sidebar-service.stub'; +import { SearchConfig } from '../../core/shared/search/search-filters/search-config.model'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; let comp: SearchComponent; let fixture: ComponentFixture; @@ -36,6 +37,14 @@ const store: Store = jasmine.createSpyObj('store', { /* tslint:enable:no-empty */ select: observableOf(true) }); +const sortOptionsList = [ + new SortOptions('score', SortDirection.DESC), + new SortOptions('dc.title', SortDirection.ASC), + new SortOptions('dc.title', SortDirection.DESC) +]; +const searchConfig = Object.assign(new SearchConfig(), { + sortOptions: sortOptionsList +}); const pagination: PaginationComponentOptions = new PaginationComponentOptions(); pagination.id = 'search-results-pagination'; pagination.currentPage = 1; @@ -47,7 +56,7 @@ const searchServiceStub = jasmine.createSpyObj('SearchService', { search: mockResults, getSearchLink: '/search', getScopes: observableOf(['test-scope']), - getSearchConfigurationFor: createSuccessfulRemoteDataObject$({ sortOptions: [sortOption]}) + getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig) }); const configurationParam = 'default'; const queryParam = 'test query'; @@ -86,6 +95,15 @@ const routeServiceStub = { } }; + +const searchConfigurationServiceStub = jasmine.createSpyObj('SearchConfigurationService', { + getConfigurationSearchConfig: jasmine.createSpy('getConfigurationSearchConfig'), + getCurrentConfiguration: jasmine.createSpy('getCurrentConfiguration'), + getCurrentScope: jasmine.createSpy('getCurrentScope'), + updateFixedFilter: jasmine.createSpy('updateFixedFilter'), + setPaginationId: jasmine.createSpy('setPaginationId') +}); + export function configureSearchComponentTestingModule(compType, additionalDeclarations: any[] = []) { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule], @@ -117,23 +135,10 @@ export function configureSearchComponentTestingModule(compType, additionalDeclar provide: SearchFilterService, useValue: {} }, - { - provide: SearchConfigurationService, - useValue: { - paginatedSearchOptions: hot('a', { - a: paginatedSearchOptions - }), - getCurrentScope: (a) => observableOf('test-id'), - /* tslint:disable:no-empty */ - updateFixedFilter: (newFilter) => { - } - /* tslint:enable:no-empty */ - } - }, { provide: SEARCH_CONFIG_SERVICE, - useValue: new SearchConfigurationServiceStub() - }, + useValue: searchConfigurationServiceStub + } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(compType, { @@ -141,7 +146,7 @@ export function configureSearchComponentTestingModule(compType, additionalDeclar }).compileComponents(); } -describe('SearchComponent', () => { +fdescribe('SearchComponent', () => { beforeEach(waitForAsync(() => { configureSearchComponentTestingModule(SearchComponent); })); @@ -150,9 +155,17 @@ describe('SearchComponent', () => { fixture = TestBed.createComponent(SearchComponent); comp = fixture.componentInstance; // SearchComponent test instance comp.inPlaceSearch = false; + + // searchConfigurationServiceStub.paginatedSearchOptions.and.returnValue(observableOf(paginatedSearchOptions)); + searchConfigurationServiceStub.getConfigurationSearchConfig.and.returnValue(observableOf(searchConfig)); + searchConfigurationServiceStub.getCurrentConfiguration.and.returnValue(observableOf('default')); + searchConfigurationServiceStub.getCurrentScope.and.returnValue(observableOf('test-id')); + + searchServiceObject = TestBed.inject(SearchService); + searchConfigurationServiceObject = TestBed.inject(SEARCH_CONFIG_SERVICE); + searchConfigurationServiceObject.paginatedSearchOptions = new BehaviorSubject(paginatedSearchOptions); + fixture.detectChanges(); - searchServiceObject = (comp as any).service; - searchConfigurationServiceObject = (comp as any).searchConfigService; }); afterEach(() => { @@ -163,14 +176,13 @@ describe('SearchComponent', () => { it('should get the scope and query from the route parameters', () => { - searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions); expect(comp.searchOptions$).toBeObservable(cold('b', { b: paginatedSearchOptions })); }); - describe('when the open sidebar button is clicked in mobile view', () => { + xdescribe('when the open sidebar button is clicked in mobile view', () => { beforeEach(() => { spyOn(comp, 'openSidebar'); @@ -192,7 +204,7 @@ describe('SearchComponent', () => { it('should have initialized the sortOptions$ observable', (done) => { - comp.sortOptions$.subscribe((sortOptions) => { + comp.sortOptionsList$.subscribe((sortOptions) => { expect(sortOptions.length).toEqual(2); expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC)); diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 0fb7ca358a..2f18507652 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -1,14 +1,17 @@ import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { startWith, switchMap } from 'rxjs/operators'; +import { Router } from '@angular/router'; + +import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; +import { uniqueId } from 'lodash'; + import { PaginatedList } from '../../core/data/paginated-list.model'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { pushInOut } from '../animations/push'; import { HostWindowService } from '../host-window.service'; import { SidebarService } from '../sidebar/sidebar.service'; -import { hasValue, isEmpty } from '../empty.util'; -import { getFirstCompletedRemoteData } from '../../core/shared/operators'; +import { hasValue } from '../empty.util'; import { RouteService } from '../../core/services/route.service'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { PaginatedSearchOptions } from './models/paginated-search-options.model'; @@ -16,11 +19,15 @@ import { SearchResult } from './models/search-result.model'; import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; import { SearchService } from '../../core/shared/search/search.service'; import { currentPath } from '../utils/route.utils'; -import { Router } from '@angular/router'; import { Context } from '../../core/shared/context.model'; import { SortOptions } from '../../core/cache/models/sort-options.model'; +import { SearchConfig } from '../../core/shared/search/search-filters/search-config.model'; +import { SearchConfigurationOption } from './search-switch-configuration/search-configuration-option.model'; +import { getFirstCompletedRemoteData } from '../../core/shared/operators'; import { followLink } from '../utils/follow-link-config.model'; import { Item } from '../../core/shared/item.model'; +import { SearchObjects } from './models/search-objects.model'; +import { ViewMode } from '../../core/shared/view-mode.model'; @Component({ selector: 'ds-search', @@ -28,18 +35,82 @@ import { Item } from '../../core/shared/item.model'; templateUrl: './search.component.html', changeDetection: ChangeDetectionStrategy.OnPush, animations: [pushInOut], - providers: [ - { - provide: SEARCH_CONFIG_SERVICE, - useClass: SearchConfigurationService - } - ] }) /** * This component renders a sidebar, a search input bar and the search results. */ export class SearchComponent implements OnInit { + + /** + * The list of available configuration options + */ + @Input() configurationList: SearchConfigurationOption[] = []; + + /** + * The current context + * If empty, 'search' is used + */ + @Input() context: Context = Context.Search; + + /** + * The configuration to use for the search options + * If empty, 'default' is used + */ + @Input() configuration = 'default'; + + /** + * The actual query for the fixed filter. + * If empty, the query will be determined by the route parameter called 'filter' + */ + @Input() fixedFilterQuery: string; + + /** + * If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + */ + @Input() useCachedVersionIfAvailable = true; + + /** + * True when the search component should show results on the current page + */ + @Input() inPlaceSearch = true; + + /** + * The pagination id used in the search + */ + @Input() paginationId = 'spc'; + + /** + * Whether or not the search bar should be visible + */ + @Input() searchEnabled = true; + + /** + * The width of the sidebar (bootstrap columns) + */ + @Input() sideBarWidth = 3; + + /** + * A boolean representing if show search sidebar button + */ + @Input() showSidebar = true; + + /** + * List of available view mode + */ + @Input() viewModeList: ViewMode[]; + + /** + * The current configuration used during the search + */ + currentConfiguration$: BehaviorSubject = new BehaviorSubject(''); + + /** + * The current context used during the search + */ + currentContext$: BehaviorSubject = new BehaviorSubject(null); + /** * The current search results */ @@ -48,56 +119,17 @@ export class SearchComponent implements OnInit { /** * The current paginated search options */ - searchOptions$: Observable; + searchOptions$: BehaviorSubject = new BehaviorSubject(null); /** - * The current available sort options + * The available sort options list */ - sortOptions$: Observable; + sortOptionsList$: BehaviorSubject = new BehaviorSubject([]); /** - * Emits true if were on a small screen + * The current sort options used */ - isXsOrSm$: Observable; - - /** - * Subscription to unsubscribe from - */ - sub: Subscription; - - /** - * True when the search component should show results on the current page - */ - @Input() inPlaceSearch = true; - - /** - * Whether or not the search bar should be visible - */ - @Input() - searchEnabled = true; - - /** - * The width of the sidebar (bootstrap columns) - */ - @Input() - sideBarWidth = 3; - - /** - * The currently applied configuration (determines title of search) - */ - @Input() - configuration$: Observable; - - /** - * The current context - */ - @Input() - context: Context; - - /** - * Link to the search page - */ - searchLink: string; + currentSortOptions$: BehaviorSubject = new BehaviorSubject(null); /** * Observable for whether or not the sidebar is currently collapsed @@ -105,9 +137,20 @@ export class SearchComponent implements OnInit { isSidebarCollapsed$: Observable; /** - * A boolean representing if show search sidebar button + * Emits true if were on a small screen */ - @Input() showSidebar = true; + isXsOrSm$: Observable; + + /** + * Link to the search page + */ + searchLink: string; + + /** + * Subscription to unsubscribe from + */ + sub: Subscription; + constructor(protected service: SearchService, protected sidebarService: SidebarService, protected windowService: HostWindowService, @@ -125,35 +168,67 @@ export class SearchComponent implements OnInit { * If something changes, update the list of scopes for the dropdown */ ngOnInit(): void { - this.isSidebarCollapsed$ = this.isSidebarCollapsed(); - this.searchLink = this.getSearchLink(); - this.searchOptions$ = this.getSearchOptions(); - this.sub = this.searchOptions$.pipe( - switchMap((options) => this.service.search( - options, undefined, false, true, followLink('thumbnail', { isOptional: true }) - ).pipe(getFirstCompletedRemoteData(), startWith(undefined)) - ) - ).subscribe((results) => { - this.resultsRD$.next(results); - }); + // Create an unique pagination id related to the instance of the SearchComponent + this.paginationId = uniqueId(this.paginationId); + this.searchConfigService.setPaginationId(this.paginationId); - if (isEmpty(this.configuration$)) { - this.configuration$ = this.searchConfigService.getCurrentConfiguration('default'); + if (hasValue(this.fixedFilterQuery)) { + this.routeService.setParameter('fixedFilterQuery', this.fixedFilterQuery); } - const searchConfig$ = this.searchConfigService.getConfigurationSearchConfigObservable(this.configuration$, this.service); + this.isSidebarCollapsed$ = this.isSidebarCollapsed(); + this.searchLink = this.getSearchLink(); + this.currentContext$.next(this.context); - this.sortOptions$ = this.searchConfigService.getConfigurationSortOptionsObservable(searchConfig$); - this.searchConfigService.initializeSortOptionsFromConfiguration(searchConfig$); + // Determinate PaginatedSearchOptions and listen to any update on it + const configuration$: Observable = this.searchConfigService + .getCurrentConfiguration(this.configuration).pipe(distinctUntilChanged()); + const searchSortOptions$: Observable = configuration$.pipe( + switchMap((configuration: string) => this.searchConfigService + .getConfigurationSearchConfig(configuration, this.service)), + map((searchConfig: SearchConfig) => this.searchConfigService.getConfigurationSortOptions(searchConfig)), + distinctUntilChanged() + ); + const sortOption$: Observable = searchSortOptions$.pipe( + switchMap((searchSortOptions: SortOptions[]) => { + const defaultSort: SortOptions = searchSortOptions[0]; + return this.searchConfigService.getCurrentSort(this.paginationId, defaultSort); + }), + distinctUntilChanged() + ); + const searchOptions$: Observable = this.getSearchOptions().pipe(distinctUntilChanged()); + this.sub = combineLatest([configuration$, searchSortOptions$, searchOptions$, sortOption$]).pipe( + filter(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { + // filter for search options related to instanced paginated id + return searchOptions.pagination.id === this.paginationId; + }) + ).subscribe(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { + // Build the PaginatedSearchOptions object + const combinedOptions = Object.assign({}, searchOptions, + { + configuration: searchOptions.configuration || configuration, + sort: sortOption || searchOptions.sort + }); + const newSearchOptions = new PaginatedSearchOptions(combinedOptions); + + // Initialize variables + this.currentConfiguration$.next(configuration); + this.currentSortOptions$.next(newSearchOptions.sort); + this.sortOptionsList$.next(searchSortOptions); + this.searchOptions$.next(newSearchOptions); + + // retrieve results + this.retrieveSearchResults(newSearchOptions); + }); } /** - * Get the current paginated search options - * @returns {Observable} + * Change the current context + * @param context */ - protected getSearchOptions(): Observable { - return this.searchConfigService.paginatedSearchOptions; + public changeContext(context: Context) { + this.currentContext$.next(context); } /** @@ -170,6 +245,43 @@ export class SearchComponent implements OnInit { this.sidebarService.expand(); } + /** + * Unsubscribe from the subscription + */ + ngOnDestroy(): void { + if (hasValue(this.sub)) { + this.sub.unsubscribe(); + } + } + + /** + * Get the current paginated search options + * @returns {Observable} + */ + protected getSearchOptions(): Observable { + return this.searchConfigService.paginatedSearchOptions; + } + + /** + * Retrieve search result by the given search options + * @param searchOptions + * @private + */ + private retrieveSearchResults(searchOptions: PaginatedSearchOptions) { + this.resultsRD$.next(null); + this.service.search( + searchOptions, + undefined, + this.useCachedVersionIfAvailable, + true, + followLink('thumbnail', { isOptional: true }) + ).pipe(getFirstCompletedRemoteData()) + .subscribe((results: RemoteData>) => { + console.log('results ', results); + this.resultsRD$.next(results); + }); + } + /** * Check if the sidebar is collapsed * @returns {Observable} emits true if the sidebar is currently collapsed, false if it is expanded @@ -188,12 +300,4 @@ export class SearchComponent implements OnInit { return this.service.getSearchLink(); } - /** - * Unsubscribe from the subscription - */ - ngOnDestroy(): void { - if (hasValue(this.sub)) { - this.sub.unsubscribe(); - } - } } From 97221647057adc0d5751c5cf3705fc4773f5d352 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 17 Dec 2021 19:51:37 +0100 Subject: [PATCH 30/77] [CST-4633] use search.component.ts for the mydspace page --- .../my-dspace-configuration.service.ts | 10 +- .../my-dspace-page.component.html | 62 +-------- .../my-dspace-page.component.ts | 128 ++---------------- .../my-dspace-page/my-dspace-page.module.ts | 2 - .../my-dspace-results.component.html | 14 -- .../my-dspace-results.component.spec.ts | 68 ---------- .../my-dspace-results.component.ts | 69 ---------- src/assets/i18n/en.json5 | 4 + 8 files changed, 30 insertions(+), 327 deletions(-) delete mode 100644 src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.html delete mode 100644 src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts delete mode 100644 src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts diff --git a/src/app/my-dspace-page/my-dspace-configuration.service.ts b/src/app/my-dspace-page/my-dspace-configuration.service.ts index 82f76eb776..7dde8eff77 100644 --- a/src/app/my-dspace-page/my-dspace-configuration.service.ts +++ b/src/app/my-dspace-page/my-dspace-configuration.service.ts @@ -12,6 +12,13 @@ import { PaginationComponentOptions } from '../shared/pagination/pagination-comp import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; import { RouteService } from '../core/services/route.service'; import { PaginationService } from '../core/pagination/pagination.service'; +import { Context } from '../core/shared/context.model'; + +export const MyDSpaceConfigurationToContextMap = new Map([ + [MyDSpaceConfigurationValueType.Workspace, Context.Workspace], + [MyDSpaceConfigurationValueType.Workflow, Context.Workflow] +]); + /** * Service that performs all actions that have to do with the current mydspace configuration @@ -110,7 +117,8 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { availableConfigurationTypes.forEach((type) => { const value = type; const label = `mydspace.show.${value}`; - configurationOptions.push({ value, label }); + const context = MyDSpaceConfigurationToContextMap.get(type); + configurationOptions.push({ value, label, context }); }); return configurationOptions; }) diff --git a/src/app/my-dspace-page/my-dspace-page.component.html b/src/app/my-dspace-page/my-dspace-page.component.html index 5a15abcc08..2b0dc7108a 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.html +++ b/src/app/my-dspace-page/my-dspace-page.component.html @@ -1,56 +1,6 @@ -
- -
- -
- - - -
-
- - -
-
- - -
- -
-
-
-
-
-
+ diff --git a/src/app/my-dspace-page/my-dspace-page.component.ts b/src/app/my-dspace-page/my-dspace-page.component.ts index bac1713230..4fbebcd6a7 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.ts @@ -1,29 +1,18 @@ -import { ChangeDetectionStrategy, Component, Inject, InjectionToken, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject, InjectionToken, OnInit } from '@angular/core'; -import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'; -import { map, switchMap, tap } from 'rxjs/operators'; - -import { PaginatedList } from '../core/data/paginated-list.model'; -import { RemoteData } from '../core/data/remote-data'; -import { DSpaceObject } from '../core/shared/dspace-object.model'; +import { Observable, Subject } from 'rxjs'; +import { take } from 'rxjs/operators'; import { pushInOut } from '../shared/animations/push'; import { HostWindowService } from '../shared/host-window.service'; -import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; import { SearchService } from '../core/shared/search/search.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { hasValue } from '../shared/empty.util'; -import { getFirstCompletedRemoteData } from '../core/shared/operators'; import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service'; import { SearchConfigurationOption } from '../shared/search/search-switch-configuration/search-configuration-option.model'; -import { RoleType } from '../core/roles/role-types'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; import { ViewMode } from '../core/shared/view-mode.model'; import { MyDSpaceRequest } from '../core/data/request.models'; -import { SearchResult } from '../shared/search/models/search-result.model'; import { Context } from '../core/shared/context.model'; -import { SortOptions } from '../core/cache/models/sort-options.model'; -import { SearchObjects } from '../shared/search/models/search-objects.model'; export const MYDSPACE_ROUTE = '/mydspace'; export const SEARCH_CONFIG_SERVICE: InjectionToken = new InjectionToken('searchConfigurationService'); @@ -46,55 +35,26 @@ export const SEARCH_CONFIG_SERVICE: InjectionToken = }) export class MyDSpacePageComponent implements OnInit { - /** - * True when the search component should show results on the current page - */ - @Input() inPlaceSearch = true; - /** * The list of available configuration options */ configurationList$: Observable; /** - * The current search results + * The start context to use in the search: workspace or workflow */ - resultsRD$: BehaviorSubject>>> = new BehaviorSubject(null); + context: Context; /** - * The current paginated search options + * The start configuration to use in the search: workspace or workflow */ - searchOptions$: Observable; - - /** - * The current available sort options - */ - sortOptions$: Observable; - - /** - * Emits true if were on a small screen - */ - isXsOrSm$: Observable; - - /** - * Subscription to unsubscribe from - */ - sub: Subscription; - - /** - * Variable for enumeration RoleType - */ - roleTypeEnum = RoleType; + configuration: string; /** * List of available view mode */ viewModeList = [ViewMode.ListElement, ViewMode.DetailedListElement]; - /** - * The current context of this page: workspace or workflow - */ - context$: Observable; /** * Emit an event every time search sidebars must refresh their contents. @@ -105,7 +65,6 @@ export class MyDSpacePageComponent implements OnInit { private sidebarService: SidebarService, private windowService: HostWindowService, @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: MyDSpaceConfigurationService) { - this.isXsOrSm$ = this.windowService.isXsOrSm(); this.service.setServiceOptions(MyDSpaceResponseParsingService, MyDSpaceRequest); } @@ -123,77 +82,12 @@ export class MyDSpacePageComponent implements OnInit { */ ngOnInit(): void { this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions(); - this.searchOptions$ = this.searchConfigService.paginatedSearchOptions; - this.sub = this.searchOptions$.pipe( - tap(() => this.resultsRD$.next(null)), - switchMap((options: PaginatedSearchOptions) => this.service.search(options).pipe(getFirstCompletedRemoteData()))) - .subscribe((results: RemoteData>) => { - this.resultsRD$.next(results); - }); - this.context$ = this.searchConfigService.getCurrentConfiguration('workspace') - .pipe( - map((configuration: string) => { - if (configuration === 'workspace') { - return Context.Workspace; - } else { - return Context.Workflow; - } - }) - ); - - const configuration$ = this.searchConfigService.getCurrentConfiguration('workspace'); - const searchConfig$ = this.searchConfigService.getConfigurationSearchConfigObservable(configuration$, this.service); - - this.sortOptions$ = this.searchConfigService.getConfigurationSortOptionsObservable(searchConfig$); - this.searchConfigService.initializeSortOptionsFromConfiguration(searchConfig$); + this.configurationList$.pipe(take(1)).subscribe((configurationList: SearchConfigurationOption[]) => { + this.configuration = configurationList[0].value; + this.context = configurationList[0].context; + }); } - /** - * Handle the contentChange event from within the my dspace content. - * Notify search sidebars to refresh their content. - */ - onResultsContentChange() { - this.refreshFilters.next(); - } - - /** - * Set the sidebar to a collapsed state - */ - public closeSidebar(): void { - this.sidebarService.collapse(); - } - - /** - * Set the sidebar to an expanded state - */ - public openSidebar(): void { - this.sidebarService.expand(); - } - - /** - * Check if the sidebar is collapsed - * @returns {Observable} emits true if the sidebar is currently collapsed, false if it is expanded - */ - public isSidebarCollapsed(): Observable { - return this.sidebarService.isCollapsed; - } - - /** - * @returns {string} The base path to the search page - */ - public getSearchLink(): string { - return this.service.getSearchLink(); - } - - /** - * Unsubscribe from the subscription - */ - ngOnDestroy(): void { - if (hasValue(this.sub)) { - this.sub.unsubscribe(); - } - this.refreshFilters.complete(); - } } diff --git a/src/app/my-dspace-page/my-dspace-page.module.ts b/src/app/my-dspace-page/my-dspace-page.module.ts index 183edf2728..2ccddd87f7 100644 --- a/src/app/my-dspace-page/my-dspace-page.module.ts +++ b/src/app/my-dspace-page/my-dspace-page.module.ts @@ -5,7 +5,6 @@ import { SharedModule } from '../shared/shared.module'; import { MyDspacePageRoutingModule } from './my-dspace-page-routing.module'; import { MyDSpacePageComponent } from './my-dspace-page.component'; -import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component'; import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component'; import { MyDSpaceGuard } from './my-dspace.guard'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; @@ -19,7 +18,6 @@ import { SearchModule } from '../shared/search/search.module'; const DECLARATIONS = [ MyDSpacePageComponent, ThemedMyDSpacePageComponent, - MyDSpaceResultsComponent, MyDSpaceNewSubmissionComponent, CollectionSelectorComponent, MyDSpaceNewSubmissionDropdownComponent, diff --git a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.html b/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.html deleted file mode 100644 index 67b13cc49c..0000000000 --- a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
- - -
- - -

{{'mydspace.results.no-results' | translate}}

diff --git a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts b/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts deleted file mode 100644 index 5b069f4ddb..0000000000 --- a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; - -import { TranslateModule } from '@ngx-translate/core'; -import { QueryParamsDirectiveStub } from '../../shared/testing/query-params-directive.stub'; -import { MyDSpaceResultsComponent } from './my-dspace-results.component'; - -describe('MyDSpaceResultsComponent', () => { - let comp: MyDSpaceResultsComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NoopAnimationsModule], - declarations: [ - MyDSpaceResultsComponent, - QueryParamsDirectiveStub], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MyDSpaceResultsComponent); - comp = fixture.componentInstance; // MyDSpaceResultsComponent test instance - }); - - it('should display results when results are not empty', () => { - (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; - (comp as any).searchConfig = {}; - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).not.toBeNull(); - }); - - it('should not display link when results are not empty', () => { - (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; - (comp as any).searchConfig = {}; - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('a'))).toBeNull(); - }); - - it('should display error message if error is 500', () => { - (comp as any).searchResults = { hasFailed: true, statusCode: 500 }; - fixture.detectChanges(); - expect(comp.showError()).toBeTrue(); - expect(comp.errorMessageLabel()).toBe('error.search-results'); - expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull(); - }); - - it('should display error message if error is 422', () => { - (comp as any).searchResults = { hasFailed: true, statusCode: 422 }; - fixture.detectChanges(); - expect(comp.showError()).toBeTrue(); - expect(comp.errorMessageLabel()).toBe('error.invalid-search-query'); - expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull(); - }); - - it('should display a message if search result is empty', () => { - (comp as any).searchResults = { payload: { page: { length: 0 } } }; - (comp as any).searchConfig = { query: 'foobar' }; - fixture.detectChanges(); - - const linkDes = fixture.debugElement.queryAll(By.css('text-muted')); - - expect(linkDes).toBeDefined(); - }); -}); diff --git a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts deleted file mode 100644 index cc8f7c8fc3..0000000000 --- a/src/app/my-dspace-page/my-dspace-results/my-dspace-results.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { RemoteData } from '../../core/data/remote-data'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { fadeIn, fadeInOut } from '../../shared/animations/fade'; -import { PaginatedList } from '../../core/data/paginated-list.model'; -import { ViewMode } from '../../core/shared/view-mode.model'; -import { isEmpty } from '../../shared/empty.util'; -import { Context } from '../../core/shared/context.model'; -import { SearchResult } from '../../shared/search/models/search-result.model'; -import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; - -/** - * Component that represents all results for mydspace page - */ -@Component({ - selector: 'ds-my-dspace-results', - templateUrl: './my-dspace-results.component.html', - animations: [ - fadeIn, - fadeInOut - ] -}) -export class MyDSpaceResultsComponent { - - /** - * The actual search result objects - */ - @Input() searchResults: RemoteData>>; - - /** - * The current configuration of the search - */ - @Input() searchConfig: PaginatedSearchOptions; - - /** - * The current view mode for the search results - */ - @Input() viewMode: ViewMode; - - /** - * The current context for the search results - */ - @Input() context: Context; - - /** - * Emit when one of the results has changed. - */ - @Output() contentChange = new EventEmitter(); - - /** - * A boolean representing if search results entry are separated by a line - */ - hasBorder = true; - - /** - * Check if mydspace search results are loading - */ - isLoading() { - return !this.searchResults || isEmpty(this.searchResults) || this.searchResults.isLoading; - } - - showError(): boolean { - return this.searchResults?.hasFailed && (!this.searchResults?.errorMessage || this.searchResults?.statusCode !== 400); - } - - errorMessageLabel(): string { - return (this.searchResults?.statusCode === 422) ? 'error.invalid-search-query' : 'error.search-results'; - } -} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 8edc01b278..1ab27fdb0e 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4019,8 +4019,12 @@ + "workspace.search.results.head": "Your submissions", + "workflowAdmin.search.results.head": "Administer Workflow", + "workflow.search.results.head": "All tasks", + "workflow-item.edit.breadcrumbs": "Edit workflowitem", From f43317c2ee8c810604f75e6b03aad3fa90daa578 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 17 Dec 2021 19:51:50 +0100 Subject: [PATCH 31/77] [CST-4633] fix build --- .../related-entities-search.component.html | 1 - .../related-entities-search.component.ts | 5 ----- .../configuration-search-page.component.ts | 13 +------------ .../themed-configuration-search-page.component.ts | 2 +- 4 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html index 75f3b7aaad..2a08efeb2c 100644 --- a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html +++ b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html @@ -1,7 +1,6 @@ diff --git a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts index 781e72795b..a3f76c12d7 100644 --- a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts +++ b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts @@ -1,5 +1,4 @@ import { Component, Input, OnInit } from '@angular/core'; -import { Observable, of } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { isNotEmpty } from '../../../../shared/empty.util'; import { getFilterByRelation } from '../../../../shared/utils/relation-query.utils'; @@ -44,15 +43,11 @@ export class RelatedEntitiesSearchComponent implements OnInit { @Input() sideBarWidth = 4; fixedFilter: string; - configuration$: Observable; ngOnInit(): void { if (isNotEmpty(this.relationType) && isNotEmpty(this.item)) { this.fixedFilter = getFilterByRelation(this.relationType, this.item.id); } - if (isNotEmpty(this.configuration)) { - this.configuration$ = of(this.configuration); - } } } diff --git a/src/app/search-page/configuration-search-page.component.ts b/src/app/search-page/configuration-search-page.component.ts index 6daa822e2e..18466452f1 100644 --- a/src/app/search-page/configuration-search-page.component.ts +++ b/src/app/search-page/configuration-search-page.component.ts @@ -1,7 +1,7 @@ import { HostWindowService } from '../shared/host-window.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { SearchComponent } from '../shared/search/search.component'; -import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core'; import { pushInOut } from '../shared/animations/push'; import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; @@ -28,17 +28,6 @@ import { Router } from '@angular/router'; }) export class ConfigurationSearchPageComponent extends SearchComponent implements OnInit { - /** - * The configuration to use for the search options - * If empty, the configuration will be determined by the route parameter called 'configuration' - */ - @Input() configuration: string; - - /** - * The actual query for the fixed filter. - * If empty, the query will be determined by the route parameter called 'filter' - */ - @Input() fixedFilterQuery: string; constructor(protected service: SearchService, protected sidebarService: SidebarService, diff --git a/src/app/search-page/themed-configuration-search-page.component.ts b/src/app/search-page/themed-configuration-search-page.component.ts index 1419d18a88..e4d6e93402 100644 --- a/src/app/search-page/themed-configuration-search-page.component.ts +++ b/src/app/search-page/themed-configuration-search-page.component.ts @@ -55,7 +55,7 @@ export class ThemedConfigurationSearchPageComponent extends ThemedComponent Date: Sun, 19 Dec 2021 17:36:03 +0100 Subject: [PATCH 32/77] [CST-4633] fix tests --- .../search/search-configuration.service.ts | 4 +- .../search-filters/search-config.model.ts | 4 +- .../related-entities-search.component.spec.ts | 6 - .../my-dspace-configuration.service.spec.ts | 7 +- .../my-dspace-page.component.spec.ts | 215 ++++-------------- .../my-dspace-page.component.ts | 14 +- .../search-navbar.component.spec.ts | 25 +- .../search-navbar/search-navbar.component.ts | 3 +- .../shared/search/search.component.spec.ts | 115 ++++++---- src/app/shared/search/search.component.ts | 3 +- 10 files changed, 140 insertions(+), 256 deletions(-) diff --git a/src/app/core/shared/search/search-configuration.service.ts b/src/app/core/shared/search/search-configuration.service.ts index 03e46cac65..40bb8aebcd 100644 --- a/src/app/core/shared/search/search-configuration.service.ts +++ b/src/app/core/shared/search/search-configuration.service.ts @@ -20,7 +20,7 @@ import { RouteService } from '../../services/route.service'; import { getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData } from '../operators'; import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; -import { SearchConfig, SortOption } from './search-filters/search-config.model'; +import { SearchConfig, SortConfig } from './search-filters/search-config.model'; import { SearchService } from './search.service'; import { PaginationService } from '../../pagination/pagination.service'; @@ -204,7 +204,7 @@ export class SearchConfigurationService implements OnDestroy { * @param searchConfig The SearchConfig object */ getConfigurationSortOptions(searchConfig: SearchConfig): SortOptions[] { - return searchConfig.sortOptions.map((entry: SortOption) => ({ + return searchConfig.sortOptions.map((entry: SortConfig) => ({ field: entry.name, direction: entry.sortOrder.toLowerCase() === SortDirection.ASC.toLowerCase() ? SortDirection.ASC : SortDirection.DESC })); diff --git a/src/app/core/shared/search/search-filters/search-config.model.ts b/src/app/core/shared/search/search-filters/search-config.model.ts index 725761fe7b..e789de0f80 100644 --- a/src/app/core/shared/search/search-filters/search-config.model.ts +++ b/src/app/core/shared/search/search-filters/search-config.model.ts @@ -29,7 +29,7 @@ export class SearchConfig implements CacheableObject { * The configured sort options. */ @autoserialize - sortOptions: SortOption[]; + sortOptions: SortConfig[]; /** * The object type. @@ -63,7 +63,7 @@ export interface FilterConfig { /** * Interface to model sort option's configuration. */ -export interface SortOption { +export interface SortConfig { name: string; sortOrder: string; } diff --git a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts index a75a0feae2..a9fd11b9ee 100644 --- a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts +++ b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts @@ -38,10 +38,4 @@ describe('RelatedEntitiesSearchComponent', () => { expect(comp.fixedFilter).toEqual(mockFilter); }); - it('should create a configuration$', () => { - comp.configuration$.subscribe((configuration) => { - expect(configuration).toEqual(mockConfiguration); - }); - }); - }); diff --git a/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts b/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts index b4926d7b92..dc971bc3af 100644 --- a/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts +++ b/src/app/my-dspace-page/my-dspace-configuration.service.spec.ts @@ -10,6 +10,7 @@ import { RoleServiceMock } from '../shared/mocks/role-service.mock'; import { cold, hot } from 'jasmine-marbles'; import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type'; import { PaginationServiceStub } from '../shared/testing/pagination-service.stub'; +import { Context } from '../core/shared/context.model'; describe('MyDSpaceConfigurationService', () => { let service: MyDSpaceConfigurationService; @@ -241,11 +242,13 @@ describe('MyDSpaceConfigurationService', () => { b: [ { value: MyDSpaceConfigurationValueType.Workspace, - label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}` + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}`, + context: Context.Workspace }, { value: MyDSpaceConfigurationValueType.Workflow, - label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}` + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}`, + context: Context.Workflow } ] })); diff --git a/src/app/my-dspace-page/my-dspace-page.component.spec.ts b/src/app/my-dspace-page/my-dspace-page.component.spec.ts index 6d8bfc274c..34bf20d462 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.spec.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.spec.ts @@ -1,213 +1,88 @@ -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ActivatedRoute } from '@angular/router'; -import { By } from '@angular/platform-browser'; import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { Store } from '@ngrx/store'; +import { of as observableOf } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; import { cold } from 'jasmine-marbles'; -import { of as observableOf } from 'rxjs'; -import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; -import { CommunityDataService } from '../core/data/community-data.service'; -import { HostWindowService } from '../shared/host-window.service'; -import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from './my-dspace-page.component'; -import { RouteService } from '../core/services/route.service'; -import { routeServiceStub } from '../shared/testing/route-service.stub'; -import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service.stub'; import { SearchService } from '../core/shared/search/search.service'; -import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; -import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model'; -import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { SearchFilterService } from '../core/shared/search/search-filter.service'; -import { RoleDirective } from '../shared/roles/role.directive'; -import { RoleService } from '../core/roles/role.service'; -import { RoleServiceMock } from '../shared/mocks/role-service.mock'; -import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils'; -import { SidebarServiceStub } from '../shared/testing/sidebar-service.stub'; +import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; +import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type'; +import { Context } from '../core/shared/context.model'; +import SpyObj = jasmine.SpyObj; describe('MyDSpacePageComponent', () => { let comp: MyDSpacePageComponent; let fixture: ComponentFixture; - let searchServiceObject: SearchService; - let searchConfigurationServiceObject: SearchConfigurationService; - const store: Store = jasmine.createSpyObj('store', { - /* tslint:disable:no-empty */ - dispatch: {}, - /* tslint:enable:no-empty */ - select: observableOf(true) + + const searchServiceStub: SpyObj = jasmine.createSpyObj('SearchService', { + setServiceOptions: jasmine.createSpy('setServiceOptions') }); - const pagination: PaginationComponentOptions = new PaginationComponentOptions(); - pagination.id = 'mydspace-results-pagination'; - pagination.currentPage = 1; - pagination.pageSize = 10; - const sortOption = { name: 'score', sortOrder: 'DESC', metadata: null }; - const sort: SortOptions = new SortOptions('score', SortDirection.DESC); - const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']); - const searchServiceStub = jasmine.createSpyObj('SearchService', { - search: mockResults, - getEndpoint: observableOf('discover/search/objects'), - getSearchLink: '/mydspace', - getScopes: observableOf(['test-scope']), - setServiceOptions: {}, - getSearchConfigurationFor: createSuccessfulRemoteDataObject$({ sortOptions: [sortOption]}) + + const myDSpaceConfigurationServiceStub: SpyObj = jasmine.createSpyObj('MyDSpaceConfigurationService', { + getAvailableConfigurationOptions: jasmine.createSpy('getAvailableConfigurationOptions') }); - const configurationParam = 'default'; - const queryParam = 'test query'; - const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; - const paginatedSearchOptions = new PaginatedSearchOptions({ - configuration: configurationParam, - query: queryParam, - scope: scopeParam, - pagination, - sort - }); - const activatedRouteStub = { - snapshot: { - queryParamMap: new Map([ - ['query', queryParam], - ['scope', scopeParam] - ]) + + const configurationList = [ + { + value: MyDSpaceConfigurationValueType.Workspace, + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}`, + context: Context.Workspace }, - queryParams: observableOf({ - query: queryParam, - scope: scopeParam - }) - }; + { + value: MyDSpaceConfigurationValueType.Workflow, + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}`, + context: Context.Workflow + } + ]; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule], - declarations: [MyDSpacePageComponent, RoleDirective], + declarations: [MyDSpacePageComponent], providers: [ { provide: SearchService, useValue: searchServiceStub }, - { - provide: CommunityDataService, - useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll']) - }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: RouteService, useValue: routeServiceStub }, - { - provide: Store, useValue: store - }, - { - provide: HostWindowService, useValue: jasmine.createSpyObj('hostWindowService', - { - isXs: observableOf(true), - isSm: observableOf(false), - isXsOrSm: observableOf(true) - }) - }, - { - provide: SidebarService, - useValue: SidebarServiceStub - }, - { - provide: SearchFilterService, - useValue: {} - }, { - provide: SEARCH_CONFIG_SERVICE, - useValue: new SearchConfigurationServiceStub() - }, - { - provide: RoleService, - useValue: new RoleServiceMock() - }, + { provide: MyDSpaceConfigurationService, useValue: myDSpaceConfigurationServiceStub }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(MyDSpacePageComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } + set: { + providers: [ + { + provide: SEARCH_CONFIG_SERVICE, + useValue: myDSpaceConfigurationServiceStub + } + ] + } }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(MyDSpacePageComponent); comp = fixture.componentInstance; // SearchPageComponent test instance + myDSpaceConfigurationServiceStub.getAvailableConfigurationOptions.and.returnValue(observableOf(configurationList)); + fixture.detectChanges(); - searchServiceObject = (comp as any).service; - searchConfigurationServiceObject = (comp as any).searchConfigService; + }); afterEach(() => { comp = null; - searchServiceObject = null; - searchConfigurationServiceObject = null; }); - it('should get the scope and query from the route parameters', () => { + it('should init properly context and configuration', fakeAsync(() => { - searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions); - expect(comp.searchOptions$).toBeObservable(cold('b', { - b: paginatedSearchOptions + expect(comp.configurationList$).toBeObservable(cold('(a|)', { + a: configurationList })); - }); + flush(); + expect(comp.configuration).toBe(MyDSpaceConfigurationValueType.Workspace); + expect(comp.context).toBe(Context.Workspace); + })); - describe('when the open sidebar button is clicked in mobile view', () => { - - beforeEach(() => { - spyOn(comp, 'openSidebar'); - const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar')); - openSidebarButton.triggerEventHandler('click', null); - }); - - it('should trigger the openSidebar function', () => { - expect(comp.openSidebar).toHaveBeenCalled(); - }); - - }); - - describe('when sidebarCollapsed is true in mobile view', () => { - let menu: HTMLElement; - - beforeEach(() => { - menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement; - comp.isSidebarCollapsed = () => observableOf(true); - fixture.detectChanges(); - }); - - it('should close the sidebar', () => { - expect(menu.classList).not.toContain('active'); - }); - - }); - - describe('when sidebarCollapsed is false in mobile view', () => { - let menu: HTMLElement; - - beforeEach(() => { - menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement; - comp.isSidebarCollapsed = () => observableOf(false); - fixture.detectChanges(); - }); - - it('should open the menu', () => { - expect(menu.classList).toContain('active'); - }); - - }); - - describe('when stable', () => { - - beforeEach(() => { - fixture.detectChanges(); - }); - - it('should have initialized the sortOptions$ observable', (done) => { - - comp.sortOptions$.subscribe((sortOptions) => { - - expect(sortOptions.length).toEqual(2); - expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC)); - expect(sortOptions[1]).toEqual(new SortOptions('score', SortDirection.DESC)); - done(); - }); - - }); - - }); }); diff --git a/src/app/my-dspace-page/my-dspace-page.component.ts b/src/app/my-dspace-page/my-dspace-page.component.ts index 4fbebcd6a7..121d417bf1 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.ts @@ -1,11 +1,8 @@ import { ChangeDetectionStrategy, Component, Inject, InjectionToken, OnInit } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; -import { pushInOut } from '../shared/animations/push'; -import { HostWindowService } from '../shared/host-window.service'; import { SearchService } from '../core/shared/search/search.service'; -import { SidebarService } from '../shared/sidebar/sidebar.service'; import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service'; import { SearchConfigurationOption } from '../shared/search/search-switch-configuration/search-configuration-option.model'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; @@ -25,7 +22,6 @@ export const SEARCH_CONFIG_SERVICE: InjectionToken = styleUrls: ['./my-dspace-page.component.scss'], templateUrl: './my-dspace-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, - animations: [pushInOut], providers: [ { provide: SEARCH_CONFIG_SERVICE, @@ -55,15 +51,7 @@ export class MyDSpacePageComponent implements OnInit { */ viewModeList = [ViewMode.ListElement, ViewMode.DetailedListElement]; - - /** - * Emit an event every time search sidebars must refresh their contents. - */ - refreshFilters: Subject = new Subject(); - constructor(private service: SearchService, - private sidebarService: SidebarService, - private windowService: HostWindowService, @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: MyDSpaceConfigurationService) { this.service.setServiceOptions(MyDSpaceResponseParsingService, MyDSpaceRequest); } diff --git a/src/app/search-navbar/search-navbar.component.spec.ts b/src/app/search-navbar/search-navbar.component.spec.ts index ba08c7ca75..fbdcdc951c 100644 --- a/src/app/search-navbar/search-navbar.component.spec.ts +++ b/src/app/search-navbar/search-navbar.component.spec.ts @@ -2,18 +2,14 @@ import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angul import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { Router } from '@angular/router'; +import { NavigationExtras, Router } from '@angular/router'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { SearchService } from '../core/shared/search/search.service'; import { TranslateLoaderMock } from '../shared/mocks/translate-loader.mock'; import { SearchNavbarComponent } from './search-navbar.component'; -import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; -import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; -import { of as observableOf } from 'rxjs'; -import { PaginationService } from '../core/pagination/pagination.service'; -import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { PaginationServiceStub } from '../shared/testing/pagination-service.stub'; +import { RouterTestingModule } from '@angular/router/testing'; describe('SearchNavbarComponent', () => { let component: SearchNavbarComponent; @@ -41,6 +37,7 @@ describe('SearchNavbarComponent', () => { FormsModule, ReactiveFormsModule, BrowserAnimationsModule, + RouterTestingModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, @@ -49,10 +46,7 @@ describe('SearchNavbarComponent', () => { })], declarations: [SearchNavbarComponent], providers: [ - { provide: SearchService, useValue: mockSearchService }, - { provide: PaginationService, useValue: paginationService }, - { provide: Router, useValue: routerStub }, - { provide: SearchConfigurationService, useValue: {paginationID: 'page-id'} } + { provide: SearchService, useValue: mockSearchService } ] }) .compileComponents(); @@ -61,8 +55,8 @@ describe('SearchNavbarComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(SearchNavbarComponent); component = fixture.componentInstance; + router = TestBed.inject(Router); fixture.detectChanges(); - router = (component as any).router; }); it('should create', () => { @@ -73,7 +67,7 @@ describe('SearchNavbarComponent', () => { beforeEach(fakeAsync(() => { spyOn(component, 'expand').and.callThrough(); spyOn(component, 'onSubmit').and.callThrough(); - spyOn(router, 'navigate').and.callThrough(); + spyOn(router, 'navigate'); const searchIcon = fixture.debugElement.query(By.css('#search-navbar-container form .submit-icon')); searchIcon.triggerEventHandler('click', { preventDefault: () => {/**/ @@ -99,8 +93,9 @@ describe('SearchNavbarComponent', () => { fixture.detectChanges(); })); it('to search page with empty query', () => { + const extras: NavigationExtras = {queryParams: { query: '' }, queryParamsHandling: 'merge'}; expect(component.onSubmit).toHaveBeenCalledWith({ query: '' }); - expect(paginationService.updateRouteWithUrl).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(['search'], extras); }); }); }); @@ -123,8 +118,10 @@ describe('SearchNavbarComponent', () => { fixture.detectChanges(); })); it('to search page with query', async () => { + const extras: NavigationExtras = { queryParams: { query: 'test' }, queryParamsHandling: 'merge'}; expect(component.onSubmit).toHaveBeenCalledWith({ query: 'test' }); - expect(paginationService.updateRouteWithUrl).toHaveBeenCalled(); + + expect(router.navigate).toHaveBeenCalledWith(['search'], extras); }); }); }); diff --git a/src/app/search-navbar/search-navbar.component.ts b/src/app/search-navbar/search-navbar.component.ts index 26849adf6d..ccdaa27861 100644 --- a/src/app/search-navbar/search-navbar.component.ts +++ b/src/app/search-navbar/search-navbar.component.ts @@ -62,8 +62,9 @@ export class SearchNavbarComponent { onSubmit(data: any) { this.collapse(); const queryParams = Object.assign({}, data); - const linkToNavigateTo = this.searchService.getSearchLink().split('/'); + const linkToNavigateTo = [this.searchService.getSearchLink().replace('/', '')]; this.searchForm.reset(); + this.router.navigate(linkToNavigateTo, { queryParams: queryParams, queryParamsHandling: 'merge' diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts index bfa4931670..25b0814579 100644 --- a/src/app/shared/search/search.component.spec.ts +++ b/src/app/shared/search/search.component.spec.ts @@ -1,11 +1,11 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { Store } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; import { cold } from 'jasmine-marbles'; -import { of as observableOf } from 'rxjs'; +import { BehaviorSubject, of as observableOf } from 'rxjs'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { CommunityDataService } from '../../core/data/community-data.service'; import { HostWindowService } from '../host-window.service'; @@ -21,11 +21,10 @@ import { SearchFilterService } from '../../core/shared/search/search-filter.serv import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component'; import { RouteService } from '../../core/services/route.service'; -import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; +import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { PaginatedSearchOptions } from './models/paginated-search-options.model'; import { SidebarServiceStub } from '../testing/sidebar-service.stub'; -import { SearchConfig } from '../../core/shared/search/search-filters/search-config.model'; -import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { SearchConfig, SortConfig } from '../../core/shared/search/search-filters/search-config.model'; let comp: SearchComponent; let fixture: ComponentFixture; @@ -37,23 +36,29 @@ const store: Store = jasmine.createSpyObj('store', { /* tslint:enable:no-empty */ select: observableOf(true) }); -const sortOptionsList = [ +const sortConfigList: SortConfig[] = [ + { name: 'score', sortOrder: SortDirection.DESC }, + { name: 'dc.title', sortOrder: SortDirection.ASC }, + { name: 'dc.title', sortOrder: SortDirection.DESC } +]; +const sortOptionsList: SortOptions[] = [ new SortOptions('score', SortDirection.DESC), new SortOptions('dc.title', SortDirection.ASC), new SortOptions('dc.title', SortDirection.DESC) ]; const searchConfig = Object.assign(new SearchConfig(), { - sortOptions: sortOptionsList + sortOptions: sortConfigList }); +const paginationId = 'search-test-page-id'; const pagination: PaginationComponentOptions = new PaginationComponentOptions(); -pagination.id = 'search-results-pagination'; +pagination.id = paginationId; pagination.currentPage = 1; pagination.pageSize = 10; -const sortOption = { name: 'score', sortOrder: 'DESC', metadata: null }; + const sort: SortOptions = new SortOptions('score', SortDirection.DESC); -const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']); +const mockResults$ = createSuccessfulRemoteDataObject$(['test', 'data']); const searchServiceStub = jasmine.createSpyObj('SearchService', { - search: mockResults, + search: mockResults$, getSearchLink: '/search', getScopes: observableOf(['test-scope']), getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig) @@ -62,6 +67,11 @@ const configurationParam = 'default'; const queryParam = 'test query'; const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; const fixedFilter = 'fixed filter'; + +const defaultSearchOptions = new PaginatedSearchOptions({ pagination }); + +const paginatedSearchOptions$ = new BehaviorSubject(defaultSearchOptions); + const paginatedSearchOptions = new PaginatedSearchOptions({ configuration: configurationParam, query: queryParam, @@ -97,12 +107,14 @@ const routeServiceStub = { const searchConfigurationServiceStub = jasmine.createSpyObj('SearchConfigurationService', { + getConfigurationSortOptions: jasmine.createSpy('getConfigurationSortOptions'), getConfigurationSearchConfig: jasmine.createSpy('getConfigurationSearchConfig'), getCurrentConfiguration: jasmine.createSpy('getCurrentConfiguration'), getCurrentScope: jasmine.createSpy('getCurrentScope'), + getCurrentSort: jasmine.createSpy('getCurrentSort'), updateFixedFilter: jasmine.createSpy('updateFixedFilter'), setPaginationId: jasmine.createSpy('setPaginationId') -}); +}, ['paginatedSearchOptions']); export function configureSearchComponentTestingModule(compType, additionalDeclarations: any[] = []) { TestBed.configureTestingModule({ @@ -146,7 +158,7 @@ export function configureSearchComponentTestingModule(compType, additionalDeclar }).compileComponents(); } -fdescribe('SearchComponent', () => { +describe('SearchComponent', () => { beforeEach(waitForAsync(() => { configureSearchComponentTestingModule(SearchComponent); })); @@ -155,17 +167,25 @@ fdescribe('SearchComponent', () => { fixture = TestBed.createComponent(SearchComponent); comp = fixture.componentInstance; // SearchComponent test instance comp.inPlaceSearch = false; + comp.paginationId = paginationId; - // searchConfigurationServiceStub.paginatedSearchOptions.and.returnValue(observableOf(paginatedSearchOptions)); searchConfigurationServiceStub.getConfigurationSearchConfig.and.returnValue(observableOf(searchConfig)); + searchConfigurationServiceStub.getConfigurationSortOptions.and.returnValue(sortOptionsList); searchConfigurationServiceStub.getCurrentConfiguration.and.returnValue(observableOf('default')); searchConfigurationServiceStub.getCurrentScope.and.returnValue(observableOf('test-id')); + searchConfigurationServiceStub.getCurrentSort.and.returnValue(observableOf(sortOptionsList[0])); + searchConfigurationServiceStub.setPaginationId.and.callFake((pageId) => { + paginatedSearchOptions$.next(Object.assign(paginatedSearchOptions$.value, { + pagination: Object.assign(new PaginationComponentOptions(), { + id: pageId + }) + })); + }); + spyOn((comp as any), 'getSearchOptions').and.returnValue(paginatedSearchOptions$.asObservable()); - searchServiceObject = TestBed.inject(SearchService); + searchServiceObject = TestBed.inject(SearchService); searchConfigurationServiceObject = TestBed.inject(SEARCH_CONFIG_SERVICE); - searchConfigurationServiceObject.paginatedSearchOptions = new BehaviorSubject(paginatedSearchOptions); - fixture.detectChanges(); }); afterEach(() => { @@ -174,45 +194,52 @@ fdescribe('SearchComponent', () => { searchConfigurationServiceObject = null; }); - it('should get the scope and query from the route parameters', () => { + it('should init search parameters properly and call retrieveSearchResults', fakeAsync(() => { + spyOn((comp as any), 'retrieveSearchResults').and.callThrough(); + fixture.detectChanges(); + flush(); - expect(comp.searchOptions$).toBeObservable(cold('b', { - b: paginatedSearchOptions + const expectedSearchOptions = Object.assign(paginatedSearchOptions$.value, { + configuration: 'default', + sort: sortOptionsList[0] + }); + expect(comp.currentConfiguration$).toBeObservable(cold('b', { + b: 'default' })); + expect(comp.currentSortOptions$).toBeObservable(cold('b', { + b: sortOptionsList[0] + })); + expect(comp.sortOptionsList$).toBeObservable(cold('b', { + b: sortOptionsList + })); + expect(comp.searchOptions$).toBeObservable(cold('b', { + b: expectedSearchOptions + })); + expect((comp as any).retrieveSearchResults).toHaveBeenCalledWith(expectedSearchOptions); + })); - }); + it('should retrieve SearchResults', fakeAsync(() => { + fixture.detectChanges(); + flush(); + const expectedResults = createSuccessfulRemoteDataObject(['test', 'data']); + expect(comp.resultsRD$).toBeObservable(cold('b', { + b: expectedResults + })); + })); - xdescribe('when the open sidebar button is clicked in mobile view', () => { + describe('when the open sidebar button is clicked in mobile view', () => { - beforeEach(() => { + beforeEach(fakeAsync(() => { spyOn(comp, 'openSidebar'); + fixture.detectChanges(); + flush(); const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar')); openSidebarButton.triggerEventHandler('click', null); - }); + })); it('should trigger the openSidebar function', () => { expect(comp.openSidebar).toHaveBeenCalled(); }); }); - - describe('when stable', () => { - - beforeEach(() => { - fixture.detectChanges(); - }); - - it('should have initialized the sortOptions$ observable', (done) => { - - comp.sortOptionsList$.subscribe((sortOptions) => { - - expect(sortOptions.length).toEqual(2); - expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC)); - expect(sortOptions[1]).toEqual(new SortOptions('score', SortDirection.DESC)); - done(); - }); - - }); - - }); }); diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 2f18507652..a27f9ff0da 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -204,6 +204,7 @@ export class SearchComponent implements OnInit { return searchOptions.pagination.id === this.paginationId; }) ).subscribe(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { + // Build the PaginatedSearchOptions object const combinedOptions = Object.assign({}, searchOptions, { @@ -211,7 +212,6 @@ export class SearchComponent implements OnInit { sort: sortOption || searchOptions.sort }); const newSearchOptions = new PaginatedSearchOptions(combinedOptions); - // Initialize variables this.currentConfiguration$.next(configuration); this.currentSortOptions$.next(newSearchOptions.sort); @@ -277,7 +277,6 @@ export class SearchComponent implements OnInit { followLink('thumbnail', { isOptional: true }) ).pipe(getFirstCompletedRemoteData()) .subscribe((results: RemoteData>) => { - console.log('results ', results); this.resultsRD$.next(results); }); } From 21e78e33e525b95a6ea64040f5b9636abadbf87c Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Tue, 14 Sep 2021 10:20:29 +0200 Subject: [PATCH 33/77] [CST-5065] Admin is unable to reset other user password (cherry pick from DSC-215) --- .../eperson-form/eperson-form.component.html | 4 ++++ .../eperson-form/eperson-form.component.ts | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 45326c1abc..5d80f24990 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -36,9 +36,13 @@ + +
{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
+ + = observableOf(false); + canReset$: Observable; /** * Observable whether or not the admin is allowed to delete the EPerson @@ -310,6 +310,11 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.canDelete$ = activeEPerson$.pipe( switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined)) ); + this.canReset$ = activeEPerson$.pipe( + switchMap((eperson) => { + return observableOf(true); + }) + ); }); } From 6a1bbc8afc9551728ba662303e4018ecb7408f9a Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 12:43:13 +0100 Subject: [PATCH 34/77] [CST-5065] Admin is unable to reset other user password (function implementation) --- .../eperson-form/eperson-form.component.html | 4 +- .../eperson-form.component.spec.ts | 28 ++++++++++- .../eperson-form/eperson-form.component.ts | 47 ++++++++++++++----- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 5d80f24990..41ae67423c 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -19,7 +19,7 @@ class="btn btn-outline-secondary"> {{messagePrefix + '.return' | translate}}
-
@@ -42,7 +42,7 @@
{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
- + { @@ -42,6 +43,7 @@ describe('EPersonFormComponent', () => { let authService: AuthServiceStub; let authorizationService: AuthorizationDataService; let groupsDataService: GroupDataService; + let epersonRegistrationService: EpersonRegistrationService; let paginationService; @@ -205,6 +207,10 @@ describe('EPersonFormComponent', () => { }).compileComponents(); })); + epersonRegistrationService = jasmine.createSpyObj('epersonRegistrationService', { + registerEmail: createSuccessfulRemoteDataObject$(null) + }); + beforeEach(() => { fixture = TestBed.createComponent(EPersonFormComponent); component = fixture.componentInstance; @@ -514,4 +520,24 @@ describe('EPersonFormComponent', () => { expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson); }); }); + + + describe('Reset Password', () => { + let ePersonId; + let ePersonEmail; + + beforeEach(() => { + ePersonId = 'testEPersonId'; + ePersonEmail = 'person.email@4science.it'; + component.epersonInitial = Object.assign(new EPerson(), { + id: ePersonId, + email: ePersonEmail + }); + component.resetPassword(); + }); + + it('should call epersonRegistrationService.registerEmail', () => { + expect(epersonRegistrationService.registerEmail).toHaveBeenCalledWith(ePersonEmail); + }); + }); }); diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts index 8e248a17d8..0d6d9feaec 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts @@ -34,6 +34,8 @@ import { NoContent } from '../../../core/shared/NoContent.model'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { followLink } from '../../../shared/utils/follow-link-config.model'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; +import { Registration } from '../../../core/shared/registration.model'; +import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; @Component({ selector: 'ds-eperson-form', @@ -167,17 +169,20 @@ export class EPersonFormComponent implements OnInit, OnDestroy { */ emailValueChangeSubscribe: Subscription; - constructor(protected changeDetectorRef: ChangeDetectorRef, - public epersonService: EPersonDataService, - public groupsDataService: GroupDataService, - private formBuilderService: FormBuilderService, - private translateService: TranslateService, - private notificationsService: NotificationsService, - private authService: AuthService, - private authorizationService: AuthorizationDataService, - private modalService: NgbModal, - private paginationService: PaginationService, - public requestService: RequestService) { + constructor( + protected changeDetectorRef: ChangeDetectorRef, + public epersonService: EPersonDataService, + public groupsDataService: GroupDataService, + private formBuilderService: FormBuilderService, + private translateService: TranslateService, + private notificationsService: NotificationsService, + private authService: AuthService, + private authorizationService: AuthorizationDataService, + private modalService: NgbModal, + private paginationService: PaginationService, + public requestService: RequestService, + private epersonRegistrationService: EpersonRegistrationService, + ) { this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => { this.epersonInitial = eperson; if (hasValue(eperson)) { @@ -484,6 +489,26 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.isImpersonated = false; } + /** + * Sends an email to current eperson address with the information + * to reset password + */ + resetPassword() { + if (hasValue(this.epersonInitial.email)) { + this.epersonRegistrationService.registerEmail(this.epersonInitial.email).pipe(getFirstCompletedRemoteData()) + .subscribe((response: RemoteData) => { + if (response.hasSucceeded) { + this.notificationsService.success(this.translateService.get('admin.access-control.epeople.actions.reset'), + this.translateService.get('forgot-email.form.success.content', {email: this.epersonInitial.email})); + } else { + this.notificationsService.error(this.translateService.get('forgot-email.form.error.head'), + this.translateService.get('forgot-email.form.error.content', {email: this.epersonInitial.email})); + } + } + ); + } + } + /** * Cancel the current edit when component is destroyed & unsub all subscriptions */ From f46767be890f04af8204c6afe030aa81c893eb71 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 13:06:16 +0100 Subject: [PATCH 35/77] [CST-5065] Tests fixed --- .../eperson-form/eperson-form.component.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index 5593c77523..644b893265 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -2,7 +2,7 @@ import { Observable, of as observableOf } from 'rxjs'; import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { BrowserModule, By } from '@angular/platform-browser'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; @@ -14,6 +14,7 @@ import { EPerson } from '../../../core/eperson/models/eperson.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { EPeopleRegistryComponent } from '../epeople-registry.component'; import { EPersonFormComponent } from './eperson-form.component'; import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; @@ -28,11 +29,9 @@ import { createPaginatedList } from '../../../shared/testing/utils.test'; import { RequestService } from '../../../core/data/request.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; - describe('EPersonFormComponent', () => { let component: EPersonFormComponent; let fixture: ComponentFixture; @@ -201,7 +200,9 @@ describe('EPersonFormComponent', () => { { provide: AuthService, useValue: authService }, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: PaginationService, useValue: paginationService }, - { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring']) } + { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}, + { provide: EpersonRegistrationService, useValue: epersonRegistrationService }, + EPeopleRegistryComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -521,7 +522,6 @@ describe('EPersonFormComponent', () => { }); }); - describe('Reset Password', () => { let ePersonId; let ePersonEmail; From 8f2ef71e3c223196326d21f52364a9c66905214d Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 21 Dec 2021 13:53:17 +0100 Subject: [PATCH 36/77] [CST-5065] Fix --- .../epeople-registry/eperson-form/eperson-form.component.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts index 0d6d9feaec..05fc3189d0 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts @@ -315,11 +315,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { this.canDelete$ = activeEPerson$.pipe( switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined)) ); - this.canReset$ = activeEPerson$.pipe( - switchMap((eperson) => { - return observableOf(true); - }) - ); + this.canReset$ = observableOf(true); }); } From e594cabe4a1b4aa26c0f3aa71d90512c34acb6d1 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Wed, 22 Dec 2021 18:01:37 +0100 Subject: [PATCH 37/77] [CST4981] finished task, working on unit testing --- .../admin-sidebar/admin-sidebar.component.ts | 18 ++-- .../collection-page-routing.module.ts | 1 + .../collection-page.component.ts | 16 +-- .../community-page-routing.module.ts | 1 + .../statistics-administrator.guard.ts | 28 +++++ .../data/feature-authorization/feature-id.ts | 1 + src/app/home-page/home-page-routing.module.ts | 1 + src/app/item-page/item-page-routing.module.ts | 1 + .../navbar-section.component.html | 5 +- src/app/navbar/navbar.component.html | 13 +-- src/app/navbar/navbar.component.ts | 13 ++- src/app/shared/menu/menu.component.spec.ts | 66 +++++++++++- src/app/shared/menu/menu.component.ts | 70 ++++++++++-- src/app/shared/menu/menu.effects.ts | 8 +- .../statistics-page-routing.module.ts | 101 +++++++++--------- src/test.ts | 2 +- .../dspace/app/navbar/navbar.component.html | 14 +-- 17 files changed, 256 insertions(+), 103 deletions(-) create mode 100644 src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index f0d583744c..c81b2e6e93 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -21,6 +21,7 @@ import { MenuService } from '../../shared/menu/menu.service'; import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service'; import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../core/data/feature-authorization/feature-id'; +import { Router, ActivatedRoute } from '@angular/router'; /** * Component representing the admin sidebar @@ -63,14 +64,15 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { inFocus$: BehaviorSubject; constructor(protected menuService: MenuService, - protected injector: Injector, - private variableService: CSSVariableService, - private authService: AuthService, - private modalService: NgbModal, - private authorizationService: AuthorizationDataService, - private scriptDataService: ScriptDataService, + protected injector: Injector, + private variableService: CSSVariableService, + private authService: AuthService, + private modalService: NgbModal, + public authorizationService: AuthorizationDataService, + private scriptDataService: ScriptDataService, + public route: ActivatedRoute ) { - super(menuService, injector); + super(menuService, injector, authorizationService, route); this.inFocus$ = new BehaviorSubject(false); } @@ -144,7 +146,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { type: MenuItemType.TEXT, text: 'menu.section.new' } as TextMenuItemModel, - icon: 'plus', + icon: 'plus', index: 0 }, { diff --git a/src/app/collection-page/collection-page-routing.module.ts b/src/app/collection-page/collection-page-routing.module.ts index 5879e523af..b92c5bf414 100644 --- a/src/app/collection-page/collection-page-routing.module.ts +++ b/src/app/collection-page/collection-page-routing.module.ts @@ -72,6 +72,7 @@ import { ThemedCollectionPageComponent } from './themed-collection-page.componen id: 'statistics_collection_:id', active: true, visible: true, + type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/collection-page/collection-page.component.ts b/src/app/collection-page/collection-page.component.ts index 366e1da7b1..62d072c249 100644 --- a/src/app/collection-page/collection-page.component.ts +++ b/src/app/collection-page/collection-page.component.ts @@ -103,20 +103,20 @@ export class CollectionPageComponent implements OnInit { const currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, this.sortConfig); this.itemRD$ = observableCombineLatest([currentPagination$, currentSort$]).pipe( - switchMap(([currentPagination, currentSort ]) => this.collectionRD$.pipe( + switchMap(([currentPagination, currentSort]) => this.collectionRD$.pipe( getFirstSucceededRemoteData(), map((rd) => rd.payload.id), switchMap((id: string) => { return this.searchService.search( - new PaginatedSearchOptions({ - scope: id, - pagination: currentPagination, - sort: currentSort, - dsoTypes: [DSpaceObjectType.ITEM] - })).pipe(toDSpaceObjectListRD()) as Observable>>; + new PaginatedSearchOptions({ + scope: id, + pagination: currentPagination, + sort: currentSort, + dsoTypes: [DSpaceObjectType.ITEM] + })).pipe(toDSpaceObjectListRD()) as Observable>>; }), startWith(undefined) // Make sure switching pages shows loading component - ) + ) ) ); diff --git a/src/app/community-page/community-page-routing.module.ts b/src/app/community-page/community-page-routing.module.ts index ad1b1fd2f2..1be5472010 100644 --- a/src/app/community-page/community-page-routing.module.ts +++ b/src/app/community-page/community-page-routing.module.ts @@ -55,6 +55,7 @@ import { ThemedCommunityPageComponent } from './themed-community-page.component' id: 'statistics_community_:id', active: true, visible: true, + type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts b/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts new file mode 100644 index 0000000000..41ea8550a7 --- /dev/null +++ b/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { SingleFeatureAuthorizationGuard } from './single-feature-authorization.guard'; +import { AuthorizationDataService } from '../authorization-data.service'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { AuthService } from '../../../auth/auth.service'; +import { Observable, of as observableOf } from 'rxjs'; +import { FeatureID } from '../feature-id'; +import { tap } from 'rxjs/operators'; + +/** + * Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have group + * management rights + */ +@Injectable({ + providedIn: 'root' +}) +export class StatisticsAdministratorGuard extends SingleFeatureAuthorizationGuard { + constructor(protected authorizationService: AuthorizationDataService, protected router: Router, protected authService: AuthService) { + super(authorizationService, router, authService); + } + + /** + * Check group management rights + */ + getFeatureID(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return observableOf(FeatureID.CanViewUsageStatistics); + } +} diff --git a/src/app/core/data/feature-authorization/feature-id.ts b/src/app/core/data/feature-authorization/feature-id.ts index 15eba0e5db..b32292559e 100644 --- a/src/app/core/data/feature-authorization/feature-id.ts +++ b/src/app/core/data/feature-authorization/feature-id.ts @@ -25,4 +25,5 @@ export enum FeatureID { CanEditVersion = 'canEditVersion', CanDeleteVersion = 'canDeleteVersion', CanCreateVersion = 'canCreateVersion', + CanViewUsageStatistics = 'canViewUsageStatistics', } diff --git a/src/app/home-page/home-page-routing.module.ts b/src/app/home-page/home-page-routing.module.ts index 2a41c079da..2356170d4b 100644 --- a/src/app/home-page/home-page-routing.module.ts +++ b/src/app/home-page/home-page-routing.module.ts @@ -21,6 +21,7 @@ import { ThemedHomePageComponent } from './themed-home-page.component'; active: true, visible: true, index: 2, + type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/item-page/item-page-routing.module.ts b/src/app/item-page/item-page-routing.module.ts index 7d7912bb42..b0412e5a0b 100644 --- a/src/app/item-page/item-page-routing.module.ts +++ b/src/app/item-page/item-page-routing.module.ts @@ -58,6 +58,7 @@ import { REQUEST_COPY_MODULE_PATH } from '../app-routing-paths'; id: 'statistics_item_:id', active: true, visible: true, + type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/navbar/navbar-section/navbar-section.component.html b/src/app/navbar/navbar-section/navbar-section.component.html index b5f6848050..d77b57515e 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.html +++ b/src/app/navbar/navbar-section/navbar-section.component.html @@ -1,4 +1,3 @@ + + \ No newline at end of file diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 3fa7598e74..fc5d1a2ef3 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -1,18 +1,15 @@ - \ No newline at end of file diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts index e741cea285..df4dd72477 100644 --- a/src/app/navbar/navbar.component.ts +++ b/src/app/navbar/navbar.component.ts @@ -7,6 +7,11 @@ import { TextMenuItemModel } from '../shared/menu/menu-item/models/text.model'; import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model'; import { HostWindowService } from '../shared/host-window.service'; import { environment } from '../../environments/environment'; +import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; +import { Router, ActivatedRoute } from '@angular/router'; +import { map, take } from 'rxjs/operators'; +import { RemoteData } from '../core/data/remote-data'; +import { Collection } from 'src/app/core/shared/collection.model'; /** * Component representing the public navbar @@ -25,10 +30,12 @@ export class NavbarComponent extends MenuComponent { menuID = MenuID.PUBLIC; constructor(protected menuService: MenuService, - protected injector: Injector, - public windowService: HostWindowService + protected injector: Injector, + public windowService: HostWindowService, + public authorizationService: AuthorizationDataService, + public route: ActivatedRoute ) { - super(menuService, injector); + super(menuService, injector, authorizationService, route); } ngOnInit(): void { diff --git a/src/app/shared/menu/menu.component.spec.ts b/src/app/shared/menu/menu.component.spec.ts index 883969137b..14e28591f3 100644 --- a/src/app/shared/menu/menu.component.spec.ts +++ b/src/app/shared/menu/menu.component.spec.ts @@ -7,9 +7,12 @@ import { MenuComponent } from './menu.component'; import { MenuServiceStub } from '../testing/menu-service.stub'; import { of as observableOf } from 'rxjs'; import { MenuSection } from './menu.reducer'; -import { Router } from '@angular/router'; +import { Router, ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MenuID } from './initial-menus-state'; +import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; +import { createSuccessfulRemoteDataObject } from 'src/app/shared/remote-data.utils'; +import { Item } from '../../core/shared/item.model'; describe('MenuComponent', () => { let comp: MenuComponent; @@ -19,13 +22,38 @@ describe('MenuComponent', () => { const mockMenuID = 'mock-menuID' as MenuID; + const authorizationService = jasmine.createSpyObj('authorizationService', { + isAuthorized: observableOf(true) + }); + + const mockItem = Object.assign(new Item(), { + id: 'fake-id', + uuid: 'fake-id', + handle: 'fake/handle', + lastModified: '2018', + _links: { + self: { + href: 'https://localhost:8000/items/fake-id' + } + } + }); + + const routeStub = { + data: observableOf({ + dso: createSuccessfulRemoteDataObject(mockItem) + }), + children: [] + }; + beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule], declarations: [MenuComponent], providers: [ Injector, - { provide: MenuService, useClass: MenuServiceStub } + { provide: MenuService, useClass: MenuServiceStub }, + { provide: AuthorizationDataService, useValue: authorizationService }, + { provide: ActivatedRoute, useValue: routeStub }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(MenuComponent, { @@ -95,4 +123,38 @@ describe('MenuComponent', () => { expect(menuService.collapseMenuPreview).toHaveBeenCalledWith(comp.menuID); })); }); + + describe('when unauthorized statistics', () => { + + beforeEach(() => { + comp.sections = observableOf([{ 'id': 'browse_global_communities_and_collections', 'active': false, 'visible': true, 'index': 0, 'model': { 'type': 1, 'text': 'menu.section.browse_global_communities_and_collections', 'link': '/community-list' }, 'shouldPersistOnRouteChange': true }, { 'id': 'browse_global', 'active': false, 'visible': true, 'index': 1, 'model': { 'type': 0, 'text': 'menu.section.browse_global' }, 'shouldPersistOnRouteChange': true }, { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }]); + authorizationService.isAuthorized().and.returnValue(observableOf(false)); + fixture.detectChanges(); + }); + + it('when authorized statistics', (done => { + comp.sections.subscribe((sections) => { + expect(sections.length).toEqual(2); + done(); + }); + })); + }); + + describe('get authorized statistics', () => { + + beforeEach(() => { + comp.sections = observableOf([{ 'id': 'browse_global_communities_and_collections', 'active': false, 'visible': true, 'index': 0, 'model': { 'type': 1, 'text': 'menu.section.browse_global_communities_and_collections', 'link': '/community-list' }, 'shouldPersistOnRouteChange': true }, { 'id': 'browse_global', 'active': false, 'visible': true, 'index': 1, 'model': { 'type': 0, 'text': 'menu.section.browse_global' }, 'shouldPersistOnRouteChange': true }, { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }]); + fixture.detectChanges(); + }); + + it('get authorized statistics', (done => { + comp.sections.subscribe((sections) => { + expect(sections.length).toEqual(3); + done(); + }); + })); + }); + + + }); diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts index 32fd938f4e..1070521704 100644 --- a/src/app/shared/menu/menu.component.ts +++ b/src/app/shared/menu/menu.component.ts @@ -1,14 +1,17 @@ import { ChangeDetectionStrategy, Component, Injector, OnDestroy, OnInit } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, of as observableOf } from 'rxjs'; import { MenuService } from './menu.service'; import { MenuID } from './initial-menus-state'; import { MenuSection } from './menu.reducer'; -import { distinctUntilChanged, map, switchMap } from 'rxjs/operators'; +import { distinctUntilChanged, map, switchMap, mergeMap, tap, isEmpty } from 'rxjs/operators'; import { GenericConstructor } from '../../core/shared/generic-constructor'; -import { hasValue } from '../empty.util'; +import { hasValue, isNotEmpty, hasValueOperator, isNotEmptyOperator } from '../empty.util'; import { MenuSectionComponent } from './menu-section/menu-section.component'; import { getComponentForMenu } from './menu-section.decorator'; import { compareArraysUsingIds } from '../../item-page/simple/item-types/shared/item-relationships-utils'; +import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; +import { FeatureID } from 'src/app/core/data/feature-authorization/feature-id'; +import { Router, ActivatedRoute } from '@angular/router'; /** * A basic implementation of a MenuComponent @@ -67,27 +70,39 @@ export class MenuComponent implements OnInit, OnDestroy { */ subs: Subscription[] = []; - constructor(protected menuService: MenuService, protected injector: Injector) { + private activatedRouteLastChild: ActivatedRoute; + + constructor(protected menuService: MenuService, protected injector: Injector, public authorizationService: AuthorizationDataService, public route: ActivatedRoute) { } /** * Sets all instance variables to their initial values */ ngOnInit(): void { + this.activatedRouteLastChild = this.getActivatedRoute(this.route); this.menuCollapsed = this.menuService.isMenuCollapsed(this.menuID); this.menuPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID); this.menuVisible = this.menuService.isMenuVisible(this.menuID); this.sections = this.menuService.getMenuTopSections(this.menuID).pipe(distinctUntilChanged(compareArraysUsingIds())); + this.subs.push( this.sections.pipe( + tap(t => console.log(t)), // if you return an array from a switchMap it will emit each element as a separate event. // So this switchMap is equivalent to a subscribe with a forEach inside switchMap((sections: MenuSection[]) => sections), + switchMap((section: MenuSection) => { + if (section.id.includes('statistics')) { + return this.getAuthorizedStatistics(section); + } + return observableOf(section); + }), + isNotEmptyOperator(), switchMap((section: MenuSection) => this.getSectionComponent(section).pipe( - map((component: GenericConstructor) => ({ section, component })) + map((component: GenericConstructor) => ({ section, component })) )), - distinctUntilChanged((x,y) => x.section.id === y.section.id) - ).subscribe(({ section, component}) => { + distinctUntilChanged((x, y) => x.section.id === y.section.id) + ).subscribe(({ section, component }) => { const nextMap = this.sectionMap$.getValue(); nextMap.set(section.id, { injector: this.getSectionDataInjector(section), @@ -98,6 +113,43 @@ export class MenuComponent implements OnInit, OnDestroy { ); } + /** + * Get activated route of the deepest activated route + */ + getActivatedRoute(route) { + if (route.children.length > 0) { + return this.getActivatedRoute(route.firstChild); + } else { + return route; + } + } + + /** + * Get section of statistics after checking authorization + */ + getAuthorizedStatistics(section) { + return this.activatedRouteLastChild.data.pipe( + switchMap((data) => { + return this.authorizationService.isAuthorized(FeatureID.CanViewUsageStatistics, this.getObjectUrl(data)).pipe( + map((canViewUsageStatistics: boolean) => { + if (!canViewUsageStatistics) { + return {}; + } else { + return section; + } + })); + }) + ); + } + + /** + * Get statistics route dso data + */ + getObjectUrl(data) { + const object = data.site ? data.site : data.dso.payload; + return object._links.self.href; + } + /** * Collapse this menu when it's currently expanded, expand it when its currently collapsed * @param {Event} event The user event that triggered this method @@ -164,8 +216,8 @@ export class MenuComponent implements OnInit, OnDestroy { private getSectionComponent(section: MenuSection): Observable> { return this.menuService.hasSubSections(this.menuID, section.id).pipe( map((expandable: boolean) => { - return getComponentForMenu(this.menuID, expandable); - } + return getComponentForMenu(this.menuID, expandable); + } ), ); } diff --git a/src/app/shared/menu/menu.effects.ts b/src/app/shared/menu/menu.effects.ts index 47cff90209..5eafad7a98 100644 --- a/src/app/shared/menu/menu.effects.ts +++ b/src/app/shared/menu/menu.effects.ts @@ -19,7 +19,7 @@ export class MenuEffects { /** * On route change, build menu sections for every menu type depending on the current route data */ - @Effect({dispatch: false}) + @Effect({ dispatch: false }) public buildRouteMenuSections$: Observable = this.actions$ .pipe( ofType(ROUTER_NAVIGATED), @@ -31,8 +31,8 @@ export class MenuEffects { ); constructor(private actions$: Actions, - private menuService: MenuService, - private route: ActivatedRoute) { + private menuService: MenuService, + private route: ActivatedRoute) { } /** @@ -72,7 +72,6 @@ export class MenuEffects { const last: boolean = hasNoValue(route.firstChild); if (hasValue(data) && hasValue(data.menu) && hasValue(data.menu[menuID])) { - let menuSections: MenuSection[] | MenuSection = data.menu[menuID]; menuSections = this.resolveSubstitutions(menuSections, params); @@ -120,4 +119,5 @@ export class MenuEffects { } return resolved; } + } diff --git a/src/app/statistics-page/statistics-page-routing.module.ts b/src/app/statistics-page/statistics-page-routing.module.ts index 3c88e096e7..6047a82f1e 100644 --- a/src/app/statistics-page/statistics-page-routing.module.ts +++ b/src/app/statistics-page/statistics-page-routing.module.ts @@ -10,64 +10,69 @@ import { ThemedCommunityStatisticsPageComponent } from './community-statistics-p import { ThemedItemStatisticsPageComponent } from './item-statistics-page/themed-item-statistics-page.component'; import { ThemedSiteStatisticsPageComponent } from './site-statistics-page/themed-site-statistics-page.component'; import { ItemResolver } from '../item-page/item.resolver'; +import { StatisticsAdministratorGuard } from 'src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard'; @NgModule({ imports: [ StatisticsPageModule, RouterModule.forChild([ - { - path: '', - resolve: { - breadcrumb: I18nBreadcrumbResolver - }, - data: { - title: 'statistics.title', - breadcrumbKey: 'statistics' - }, - children: [ - { - path: '', - component: ThemedSiteStatisticsPageComponent, - }, - ] + { + path: '', + resolve: { + breadcrumb: I18nBreadcrumbResolver }, - { - path: `items/:id`, - resolve: { - scope: ItemResolver, - breadcrumb: I18nBreadcrumbResolver - }, - data: { - title: 'statistics.title', - breadcrumbKey: 'statistics' - }, - component: ThemedItemStatisticsPageComponent, + data: { + title: 'statistics.title', + breadcrumbKey: 'statistics' }, - { - path: `collections/:id`, - resolve: { - scope: CollectionPageResolver, - breadcrumb: I18nBreadcrumbResolver + children: [ + { + path: '', + component: ThemedSiteStatisticsPageComponent, }, - data: { - title: 'statistics.title', - breadcrumbKey: 'statistics' - }, - component: ThemedCollectionStatisticsPageComponent, + ], + canActivate: [StatisticsAdministratorGuard] + }, + { + path: `items/:id`, + resolve: { + scope: ItemResolver, + breadcrumb: I18nBreadcrumbResolver }, - { - path: `communities/:id`, - resolve: { - scope: CommunityPageResolver, - breadcrumb: I18nBreadcrumbResolver - }, - data: { - title: 'statistics.title', - breadcrumbKey: 'statistics' - }, - component: ThemedCommunityStatisticsPageComponent, + data: { + title: 'statistics.title', + breadcrumbKey: 'statistics' }, - ] + component: ThemedItemStatisticsPageComponent, + canActivate: [StatisticsAdministratorGuard] + }, + { + path: `collections/:id`, + resolve: { + scope: CollectionPageResolver, + breadcrumb: I18nBreadcrumbResolver + }, + data: { + title: 'statistics.title', + breadcrumbKey: 'statistics' + }, + component: ThemedCollectionStatisticsPageComponent, + canActivate: [StatisticsAdministratorGuard] + }, + { + path: `communities/:id`, + resolve: { + scope: CommunityPageResolver, + breadcrumb: I18nBreadcrumbResolver + }, + data: { + title: 'statistics.title', + breadcrumbKey: 'statistics' + }, + component: ThemedCommunityStatisticsPageComponent, + canActivate: [StatisticsAdministratorGuard] + }, + ] ) ], providers: [ diff --git a/src/test.ts b/src/test.ts index 16317897b1..c77b4bb2f0 100644 --- a/src/test.ts +++ b/src/test.ts @@ -15,6 +15,6 @@ getTestBed().initTestEnvironment( platformBrowserDynamicTesting() ); // Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); +const context = require.context('./app/shared/menu', true, /\.spec\.ts$/); // And load the modules. context.keys().map(context); diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index 5af30db632..f061c7cb3b 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -1,17 +1,14 @@ - \ No newline at end of file From 2fe5587e0257a9f7587a01cefcf11a144aea582f Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Thu, 16 Dec 2021 14:17:28 +0100 Subject: [PATCH 38/77] move the correlation id to the ngrx store --- src/app/app.module.ts | 15 ----- src/app/app.reducer.ts | 3 + src/app/core/log/log.interceptor.ts | 9 ++- .../correlation-id/correlation-id.actions.ts | 15 +++++ .../correlation-id/correlation-id.reducer.ts | 21 ++++++ .../correlation-id/correlation-id.service.ts | 64 +++++++++++++++++++ src/modules/app/browser-app.module.ts | 17 ++--- src/modules/app/server-app.module.ts | 16 +++-- 8 files changed, 125 insertions(+), 35 deletions(-) create mode 100644 src/app/correlation-id/correlation-id.actions.ts create mode 100644 src/app/correlation-id/correlation-id.reducer.ts create mode 100644 src/app/correlation-id/correlation-id.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 98b2d9fe92..4a404e3200 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -156,21 +156,6 @@ const PROVIDERS = [ useClass: LogInterceptor, multi: true }, - // insert the unique id of the user that is using the application utilizing cookies - { - provide: APP_INITIALIZER, - useFactory: (cookieService: CookieService, uuidService: UUIDService) => { - const correlationId = cookieService.get('CORRELATION-ID'); - - // Check if cookie exists, if don't, set it with unique id - if (!correlationId) { - cookieService.set('CORRELATION-ID', uuidService.generate()); - } - return () => true; - }, - multi: true, - deps: [CookieService, UUIDService] - }, { provide: DYNAMIC_ERROR_MESSAGES_MATCHER, useValue: ValidateEmailErrorStateMatcher diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index a02095d834..5bd4f745d9 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -49,6 +49,7 @@ import { import { sidebarReducer, SidebarState } from './shared/sidebar/sidebar.reducer'; import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer'; import { ThemeState, themeReducer } from './shared/theme-support/theme.reducer'; +import { correlationIdReducer } from './correlation-id/correlation-id.reducer'; export interface AppState { router: fromRouter.RouterReducerState; @@ -69,6 +70,7 @@ export interface AppState { communityList: CommunityListState; epeopleRegistry: EPeopleRegistryState; groupRegistry: GroupRegistryState; + correlationId: string; } export const appReducers: ActionReducerMap = { @@ -90,6 +92,7 @@ export const appReducers: ActionReducerMap = { communityList: CommunityListReducer, epeopleRegistry: ePeopleRegistryReducer, groupRegistry: groupRegistryReducer, + correlationId: correlationIdReducer }; export const routerStateSelector = (state: AppState) => state.router; diff --git a/src/app/core/log/log.interceptor.ts b/src/app/core/log/log.interceptor.ts index bf843f1da8..aff1a24963 100644 --- a/src/app/core/log/log.interceptor.ts +++ b/src/app/core/log/log.interceptor.ts @@ -3,9 +3,8 @@ import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/c import { Router } from '@angular/router'; import { Observable } from 'rxjs'; - -import { CookieService } from '../services/cookie.service'; import { hasValue } from '../../shared/empty.util'; +import { CorrelationIdService } from '../../correlation-id/correlation-id.service'; /** * Log Interceptor intercepting Http Requests & Responses to @@ -15,12 +14,12 @@ import { hasValue } from '../../shared/empty.util'; @Injectable() export class LogInterceptor implements HttpInterceptor { - constructor(private cookieService: CookieService, private router: Router) {} + constructor(private cidService: CorrelationIdService, private router: Router) {} intercept(request: HttpRequest, next: HttpHandler): Observable> { - // Get Unique id of the user from the cookies - const correlationId = this.cookieService.get('CORRELATION-ID'); + // Get the correlation id for the user from the store + const correlationId = this.cidService.getCorrelationId(); // Add headers from the intercepted request let headers = request.headers; diff --git a/src/app/correlation-id/correlation-id.actions.ts b/src/app/correlation-id/correlation-id.actions.ts new file mode 100644 index 0000000000..0901974a4c --- /dev/null +++ b/src/app/correlation-id/correlation-id.actions.ts @@ -0,0 +1,15 @@ +import { type } from '../shared/ngrx/type'; +import { Action } from '@ngrx/store'; + +export const CorrelationIDActionTypes = { + SET: type('dspace/core/correlationId/SET') +}; + +export class SetCorrelationIdAction implements Action { + type = CorrelationIDActionTypes.SET; + + constructor(public payload: string) { + } +} + +export type CorrelationIdAction = SetCorrelationIdAction; diff --git a/src/app/correlation-id/correlation-id.reducer.ts b/src/app/correlation-id/correlation-id.reducer.ts new file mode 100644 index 0000000000..e8071a3108 --- /dev/null +++ b/src/app/correlation-id/correlation-id.reducer.ts @@ -0,0 +1,21 @@ +import { + CorrelationIdAction, + CorrelationIDActionTypes, + SetCorrelationIdAction +} from './correlation-id.actions'; +import { AppState } from '../app.reducer'; + +const initialState = null; + +export const correlationIdSelector = (state: AppState) => state.correlationId; + +export const correlationIdReducer = (state = initialState, action: CorrelationIdAction): string => { + switch (action.type) { + case CorrelationIDActionTypes.SET: { + return (action as SetCorrelationIdAction).payload; + } + default: { + return state; + } + } +}; diff --git a/src/app/correlation-id/correlation-id.service.ts b/src/app/correlation-id/correlation-id.service.ts new file mode 100644 index 0000000000..6f4b2a5341 --- /dev/null +++ b/src/app/correlation-id/correlation-id.service.ts @@ -0,0 +1,64 @@ +import { CookieService } from '../core/services/cookie.service'; +import { UUIDService } from '../core/shared/uuid.service'; +import { Store, select } from '@ngrx/store'; +import { AppState } from '../app.reducer'; +import { isEmpty } from '../shared/empty.util'; +import { correlationIdSelector } from './correlation-id.reducer'; +import { take } from 'rxjs/operators'; +import { SetCorrelationIdAction } from './correlation-id.actions'; +import { Injectable } from '@angular/core'; + +/** + * Service to manage the correlation id, an id used to give context to server side logs + */ +@Injectable({ + providedIn: 'root' +}) +export class CorrelationIdService { + + constructor( + protected cookieService: CookieService, + protected uuidService: UUIDService, + protected store: Store, + ) { + } + + /** + * Initialize the correlation id based on the cookie or the ngrx store + */ + initCorrelationId(): void { + // first see of there's a cookie with a correlation-id + let correlationId = this.cookieService.get('CORRELATION-ID'); + + // if there isn't see if there's an ID in the store + if (isEmpty(correlationId)) { + correlationId = this.getCorrelationId(); + } + + // if no id was found, create a new id + if (isEmpty(correlationId)) { + correlationId = this.uuidService.generate(); + } + + // Store the correct id both in the store and as a cookie to ensure they're in sync + this.store.dispatch(new SetCorrelationIdAction(correlationId)); + this.cookieService.set('CORRELATION-ID', correlationId); + } + + /** + * Get the correlation id from the store + */ + getCorrelationId(): string { + let correlationId; + + this.store.pipe( + select(correlationIdSelector), + take(1) + ).subscribe((storeId: string) => { + // we can do this because ngrx selects are synchronous + correlationId = storeId; + }); + + return correlationId; + } +} diff --git a/src/modules/app/browser-app.module.ts b/src/modules/app/browser-app.module.ts index 86497d4599..88a59eb157 100644 --- a/src/modules/app/browser-app.module.ts +++ b/src/modules/app/browser-app.module.ts @@ -36,6 +36,7 @@ import { BrowserAuthRequestService } from '../../app/core/auth/browser-auth-requ import { AppConfig, APP_CONFIG_STATE } from '../../config/app-config.interface'; import { DefaultAppConfig } from '../../config/default-app-config'; import { extendEnvironmentWithAppConfig } from '../../config/config.util'; +import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service'; import { environment } from '../../environments/environment'; @@ -81,16 +82,21 @@ export function getRequest(transferState: TransferState): any { providers: [ { provide: APP_INITIALIZER, - useFactory: (transferState: TransferState) => { + useFactory: ( + transferState: TransferState, + dspaceTransferState: DSpaceTransferState, + correlationIdService: CorrelationIdService + ) => { if (transferState.hasKey(APP_CONFIG_STATE)) { const appConfig = transferState.get(APP_CONFIG_STATE, new DefaultAppConfig()); // extend environment with app config for browser extendEnvironmentWithAppConfig(environment, appConfig); } - + dspaceTransferState.transfer(); + correlationIdService.initCorrelationId(); return () => true; }, - deps: [TransferState], + deps: [TransferState, DSpaceTransferState, CorrelationIdService], multi: true }, { @@ -137,9 +143,4 @@ export function getRequest(transferState: TransferState): any { ] }) export class BrowserAppModule { - constructor( - private transferState: DSpaceTransferState, - ) { - this.transferState.transfer(); - } } diff --git a/src/modules/app/server-app.module.ts b/src/modules/app/server-app.module.ts index 8c49554de9..01a5548948 100644 --- a/src/modules/app/server-app.module.ts +++ b/src/modules/app/server-app.module.ts @@ -32,6 +32,7 @@ import { ServerHardRedirectService } from '../../app/core/services/server-hard-r import { Angulartics2Mock } from '../../app/shared/mocks/angulartics2.service.mock'; import { AuthRequestService } from '../../app/core/auth/auth-request.service'; import { ServerAuthRequestService } from '../../app/core/auth/server-auth-request.service'; +import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service'; import { AppConfig, APP_CONFIG_STATE } from '../../config/app-config.interface'; import { environment } from '../../environments/environment'; @@ -65,11 +66,17 @@ export function createTranslateLoader() { // Initialize app config and extend environment { provide: APP_INITIALIZER, - useFactory: (transferState: TransferState) => { + useFactory: ( + transferState: TransferState, + dspaceTransferState: DSpaceTransferState, + correlationIdService: CorrelationIdService, + ) => { transferState.set(APP_CONFIG_STATE, environment as AppConfig); + dspaceTransferState.transfer(); + correlationIdService.initCorrelationId(); return () => true; }, - deps: [TransferState], + deps: [TransferState, DSpaceTransferState, CorrelationIdService], multi: true }, { @@ -117,9 +124,4 @@ export function createTranslateLoader() { ] }) export class ServerAppModule { - constructor( - private transferState: DSpaceTransferState, - ) { - this.transferState.transfer(); - } } From 3c8c425843985d2bd461690aed876dfe0d850279 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Fri, 17 Dec 2021 17:05:53 +0100 Subject: [PATCH 39/77] 86016: Add unit tests for correlationId reducer & service --- .../correlation-id.reducer.spec.ts | 23 +++++ .../correlation-id.service.spec.ts | 83 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/app/correlation-id/correlation-id.reducer.spec.ts create mode 100644 src/app/correlation-id/correlation-id.service.spec.ts diff --git a/src/app/correlation-id/correlation-id.reducer.spec.ts b/src/app/correlation-id/correlation-id.reducer.spec.ts new file mode 100644 index 0000000000..c784def1d9 --- /dev/null +++ b/src/app/correlation-id/correlation-id.reducer.spec.ts @@ -0,0 +1,23 @@ +import { correlationIdReducer } from './correlation-id.reducer'; +import { SetCorrelationIdAction } from './correlation-id.actions'; + +describe('correlationIdReducer', () => { + it('should set the correlatinId with SET action', () => { + const initialState = null; + const currentState = correlationIdReducer(initialState, new SetCorrelationIdAction('new ID')); + + expect(currentState).toBe('new ID'); + }); + + it('should leave correlatinId unchanged otherwise', () => { + const initialState = null; + + let currentState = correlationIdReducer(initialState, { type: 'unknown' } as any); + expect(currentState).toBe(null); + + currentState = correlationIdReducer(currentState, new SetCorrelationIdAction('new ID')); + currentState = correlationIdReducer(currentState, { type: 'unknown' } as any); + + expect(currentState).toBe('new ID'); + }); +}); diff --git a/src/app/correlation-id/correlation-id.service.spec.ts b/src/app/correlation-id/correlation-id.service.spec.ts new file mode 100644 index 0000000000..003924c123 --- /dev/null +++ b/src/app/correlation-id/correlation-id.service.spec.ts @@ -0,0 +1,83 @@ +import { CorrelationIdService } from './correlation-id.service'; +import { CookieServiceMock } from '../shared/mocks/cookie.service.mock'; +import { UUIDService } from '../core/shared/uuid.service'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { TestBed } from '@angular/core/testing'; +import { Store, StoreModule } from '@ngrx/store'; +import { appReducers, AppState, storeModuleConfig } from '../app.reducer'; +import { SetCorrelationIdAction } from './correlation-id.actions'; + +fdescribe('CorrelationIdService', () => { + let service: CorrelationIdService; + + let cookieService; + let uuidService; + let store; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot(appReducers, storeModuleConfig), + ], + }).compileComponents(); + }); + + beforeEach(() => { + cookieService = new CookieServiceMock(); + uuidService = new UUIDService(); + store = TestBed.inject(Store) as MockStore; + service = new CorrelationIdService(cookieService, uuidService, store); + }); + + describe('getCorrelationId', () => { + it('should get from from store', () => { + expect(service.getCorrelationId()).toBe(null); + store.dispatch(new SetCorrelationIdAction('some value')); + expect(service.getCorrelationId()).toBe('some value'); + }); + }); + + + describe('initCorrelationId', () => { + const cookieCID = 'cookie CID'; + const storeCID = 'store CID'; + + it('should set cookie and store values to a newly generated value if neither ex', () => { + service.initCorrelationId(); + + expect(cookieService.get('CORRELATION-ID')).toBeTruthy(); + expect(service.getCorrelationId()).toBeTruthy(); + expect(cookieService.get('CORRELATION-ID')).toEqual(service.getCorrelationId()); + }); + + it('should set store value to cookie value if present', () => { + expect(service.getCorrelationId()).toBe(null); + + cookieService.set('CORRELATION-ID', cookieCID); + + service.initCorrelationId(); + + expect(cookieService.get('CORRELATION-ID')).toBe(cookieCID); + expect(service.getCorrelationId()).toBe(cookieCID); + }); + + it('should set cookie value to store value if present', () => { + store.dispatch(new SetCorrelationIdAction(storeCID)); + + service.initCorrelationId(); + + expect(cookieService.get('CORRELATION-ID')).toBe(storeCID); + expect(service.getCorrelationId()).toBe(storeCID); + }); + + it('should set store value to cookie value if both are present', () => { + cookieService.set('CORRELATION-ID', cookieCID); + store.dispatch(new SetCorrelationIdAction(storeCID)); + + service.initCorrelationId(); + + expect(cookieService.get('CORRELATION-ID')).toBe(cookieCID); + expect(service.getCorrelationId()).toBe(cookieCID); + }); + }); +}); From 50d8719c41d1ecf7d069b84403353aa6c34c170f Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Mon, 20 Dec 2021 16:09:08 +0100 Subject: [PATCH 40/77] Remove stray fdescribe --- src/app/correlation-id/correlation-id.service.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/correlation-id/correlation-id.service.spec.ts b/src/app/correlation-id/correlation-id.service.spec.ts index 003924c123..64a4d1068a 100644 --- a/src/app/correlation-id/correlation-id.service.spec.ts +++ b/src/app/correlation-id/correlation-id.service.spec.ts @@ -7,7 +7,7 @@ import { Store, StoreModule } from '@ngrx/store'; import { appReducers, AppState, storeModuleConfig } from '../app.reducer'; import { SetCorrelationIdAction } from './correlation-id.actions'; -fdescribe('CorrelationIdService', () => { +describe('CorrelationIdService', () => { let service: CorrelationIdService; let cookieService; From a2515c11e1623ab30d99505977f903f231c441ff Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Tue, 21 Dec 2021 09:51:56 +0100 Subject: [PATCH 41/77] 86016: Update log.interceptor.spec.ts --- src/app/core/log/log.interceptor.spec.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/app/core/log/log.interceptor.spec.ts b/src/app/core/log/log.interceptor.spec.ts index 9bda4b7934..cae9c32202 100644 --- a/src/app/core/log/log.interceptor.spec.ts +++ b/src/app/core/log/log.interceptor.spec.ts @@ -9,12 +9,17 @@ import { RestRequestMethod } from '../data/rest-request-method'; import { CookieService } from '../services/cookie.service'; import { CookieServiceMock } from '../../shared/mocks/cookie.service.mock'; import { RouterStub } from '../../shared/testing/router.stub'; +import { CorrelationIdService } from '../../correlation-id/correlation-id.service'; +import { UUIDService } from '../shared/uuid.service'; +import { StoreModule } from '@ngrx/store'; +import { appReducers, storeModuleConfig } from '../../app.reducer'; describe('LogInterceptor', () => { let service: DspaceRestService; let httpMock: HttpTestingController; let cookieService: CookieService; + let correlationIdService: CorrelationIdService; const router = Object.assign(new RouterStub(),{url : '/statistics'}); // Mock payload/statuses are dummy content as we are not testing the results @@ -28,7 +33,10 @@ describe('LogInterceptor', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], + imports: [ + HttpClientTestingModule, + StoreModule.forRoot(appReducers, storeModuleConfig), + ], providers: [ DspaceRestService, // LogInterceptor, @@ -39,14 +47,18 @@ describe('LogInterceptor', () => { }, { provide: CookieService, useValue: new CookieServiceMock() }, { provide: Router, useValue: router }, + { provide: CorrelationIdService, useClass: CorrelationIdService }, + { provide: UUIDService, useClass: UUIDService }, ], }); - service = TestBed.get(DspaceRestService); - httpMock = TestBed.get(HttpTestingController); - cookieService = TestBed.get(CookieService); + service = TestBed.inject(DspaceRestService); + httpMock = TestBed.inject(HttpTestingController); + cookieService = TestBed.inject(CookieService); + correlationIdService = TestBed.inject(CorrelationIdService); cookieService.set('CORRELATION-ID','123455'); + correlationIdService.initCorrelationId(); }); From c1e8bbbeaeb00e0d160f6f8b8189dbb89a1b0f79 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Thu, 23 Dec 2021 16:42:14 +0100 Subject: [PATCH 42/77] 86016: Add typedocs --- src/app/correlation-id/correlation-id.actions.ts | 6 ++++++ src/app/correlation-id/correlation-id.reducer.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/app/correlation-id/correlation-id.actions.ts b/src/app/correlation-id/correlation-id.actions.ts index 0901974a4c..d57d41a637 100644 --- a/src/app/correlation-id/correlation-id.actions.ts +++ b/src/app/correlation-id/correlation-id.actions.ts @@ -5,6 +5,9 @@ export const CorrelationIDActionTypes = { SET: type('dspace/core/correlationId/SET') }; +/** + * Action for setting a new correlation ID + */ export class SetCorrelationIdAction implements Action { type = CorrelationIDActionTypes.SET; @@ -12,4 +15,7 @@ export class SetCorrelationIdAction implements Action { } } +/** + * Type alias for all correlation ID actions + */ export type CorrelationIdAction = SetCorrelationIdAction; diff --git a/src/app/correlation-id/correlation-id.reducer.ts b/src/app/correlation-id/correlation-id.reducer.ts index e8071a3108..b7525b0b1c 100644 --- a/src/app/correlation-id/correlation-id.reducer.ts +++ b/src/app/correlation-id/correlation-id.reducer.ts @@ -9,6 +9,12 @@ const initialState = null; export const correlationIdSelector = (state: AppState) => state.correlationId; +/** + * Reducer that handles actions to update the correlation ID + * @param {string} state the previous correlation ID (null if unset) + * @param {CorrelationIdAction} action the action to perform + * @return {string} the new correlation ID + */ export const correlationIdReducer = (state = initialState, action: CorrelationIdAction): string => { switch (action.type) { case CorrelationIDActionTypes.SET: { From fc059520a007cc11482b95c34281cfc5a8430a07 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Thu, 23 Dec 2021 17:09:44 +0100 Subject: [PATCH 43/77] Fix LGTM issues --- src/app/app.module.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4a404e3200..32c3c78348 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -55,9 +55,6 @@ import { ThemedBreadcrumbsComponent } from './breadcrumbs/themed-breadcrumbs.com import { ThemedHeaderNavbarWrapperComponent } from './header-nav-wrapper/themed-header-navbar-wrapper.component'; import { IdleModalComponent } from './shared/idle-modal/idle-modal.component'; -import { UUIDService } from './core/shared/uuid.service'; -import { CookieService } from './core/services/cookie.service'; - import { AppConfig, APP_CONFIG } from '../config/app-config.interface'; export function getConfig() { From 13db7c8c19bfbf11d38fbef113454dd6143a79f6 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 23 Dec 2021 10:27:49 -0600 Subject: [PATCH 44/77] Update docker-compose for runtime configs. Remove all config files & replace with env variables --- README.md | 4 +--- docker/README.md | 4 ---- docker/cli.yml | 13 +++++++++++-- docker/docker-compose-ci.yml | 14 +++++++++++++- docker/docker-compose-rest.yml | 23 ++++++++++++++++++++++- docker/docker-compose.yml | 14 ++++++++------ docker/environment.dev.ts | 18 ------------------ docker/local.cfg | 6 ------ 8 files changed, 55 insertions(+), 41 deletions(-) delete mode 100644 docker/environment.dev.ts delete mode 100644 docker/local.cfg diff --git a/README.md b/README.md index 065d313005..201e488373 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,7 @@ dspace-angular │ ├── plugins * Folder for Cypress plugins (if any) │ ├── support * Folder for global e2e test actions/commands (run for all tests) │ └── tsconfig.json * TypeScript configuration file for e2e tests -├── docker * +├── docker * See docker/README.md for details │ ├── cli.assetstore.yml * │ ├── cli.ingest.yml * │ ├── cli.yml * @@ -367,8 +367,6 @@ dspace-angular │ ├── docker-compose-ci.yml * │ ├── docker-compose-rest.yml * │ ├── docker-compose.yml * -│ ├── environment.dev.ts * -│ ├── local.cfg * │ └── README.md * ├── docs * Folder for documentation │ └── Configuration.md * Configuration documentation diff --git a/docker/README.md b/docker/README.md index b0943562af..a2f4ef3362 100644 --- a/docker/README.md +++ b/docker/README.md @@ -29,10 +29,6 @@ docker push dspace/dspace-angular:dspace-7_x - Docker compose file that provides a DSpace CLI container to work with a running DSpace REST container. - cli.assetstore.yml - Docker compose file that will download and install data into a DSpace REST assetstore. This script points to a default dataset that will be utilized for CI testing. -- environment.dev.ts - - Environment file for running DSpace Angular in Docker -- local.cfg - - Environment file for running the DSpace 7 REST API in Docker. ## To refresh / pull DSpace images from Dockerhub diff --git a/docker/cli.yml b/docker/cli.yml index 36f63b2cff..54b83d4503 100644 --- a/docker/cli.yml +++ b/docker/cli.yml @@ -18,10 +18,19 @@ services: dspace-cli: image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}" container_name: dspace-cli - #environment: + environment: + # Below syntax may look odd, but it is how to override dspace.cfg settings via env variables. + # See https://github.com/DSpace/DSpace/blob/main/dspace/config/config-definition.xml + # __P__ => "." (e.g. dspace__P__dir => dspace.dir) + # __D__ => "-" (e.g. google__D__metadata => google-metadata) + # dspace.dir + dspace__P__dir: /dspace + # db.url: Ensure we are using the 'dspacedb' image for our database + db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace' + # solr.server: Ensure we are using the 'dspacesolr' image for Solr + solr__P__server: http://dspacesolr:8983/solr volumes: - "assetstore:/dspace/assetstore" - - "./local.cfg:/dspace/config/local.cfg" entrypoint: /dspace/bin/dspace command: help networks: diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index 18fa152c9d..a895314a17 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -17,6 +17,19 @@ services: # DSpace (backend) webapp container dspace: container_name: dspace + environment: + # Below syntax may look odd, but it is how to override dspace.cfg settings via env variables. + # See https://github.com/DSpace/DSpace/blob/main/dspace/config/config-definition.xml + # __P__ => "." (e.g. dspace__P__dir => dspace.dir) + # __D__ => "-" (e.g. google__D__metadata => google-metadata) + # dspace.dir, dspace.server.url and dspace.ui.url + dspace__P__dir: /dspace + dspace__P__server__P__url: http://localhost:8080/server + dspace__P__ui__P__url: http://localhost:4000 + # db.url: Ensure we are using the 'dspacedb' image for our database + db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace' + # solr.server: Ensure we are using the 'dspacesolr' image for Solr + solr__P__server: http://dspacesolr:8983/solr depends_on: - dspacedb image: dspace/dspace:dspace-7_x-test @@ -29,7 +42,6 @@ services: tty: true volumes: - assetstore:/dspace/assetstore - - "./local.cfg:/dspace/config/local.cfg" # Mount DSpace's solr configs to a volume, so that we can share to 'dspacesolr' container (see below) - solr_configs:/dspace/solr # Ensure that the database is ready BEFORE starting tomcat diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml index 3534682afc..b73f1b7a39 100644 --- a/docker/docker-compose-rest.yml +++ b/docker/docker-compose-rest.yml @@ -13,10 +13,32 @@ version: '3.7' networks: dspacenet: + ipam: + config: + # Define a custom subnet for our DSpace network, so that we can easily trust requests from host to container. + # If you customize this value, be sure to customize the 'proxies.trusted.ipranges' env variable below. + - subnet: 172.23.0.0/16 services: # DSpace (backend) webapp container dspace: container_name: dspace + environment: + # Below syntax may look odd, but it is how to override dspace.cfg settings via env variables. + # See https://github.com/DSpace/DSpace/blob/main/dspace/config/config-definition.xml + # __P__ => "." (e.g. dspace__P__dir => dspace.dir) + # __D__ => "-" (e.g. google__D__metadata => google-metadata) + # dspace.dir, dspace.server.url, dspace.ui.url and dspace.name + dspace__P__dir: /dspace + dspace__P__server__P__url: http://localhost:8080/server + dspace__P__ui__P__url: http://localhost:4000 + dspace__P__name: 'DSpace Started with Docker Compose' + # db.url: Ensure we are using the 'dspacedb' image for our database + db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace' + # solr.server: Ensure we are using the 'dspacesolr' image for Solr + solr__P__server: http://dspacesolr:8983/solr + # proxies.trusted.ipranges: This setting is required for a REST API running in Docker to trust requests + # from the host machine. This IP range MUST correspond to the 'dspacenet' subnet defined above. + proxies__P__trusted__P__ipranges: '172.23.0' image: dspace/dspace:dspace-7_x-test depends_on: - dspacedb @@ -29,7 +51,6 @@ services: tty: true volumes: - assetstore:/dspace/assetstore - - "./local.cfg:/dspace/config/local.cfg" # Mount DSpace's solr configs to a volume, so that we can share to 'dspacesolr' container (see below) - solr_configs:/dspace/solr # Ensure that the database is ready BEFORE starting tomcat diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e518dc99d2..adeb61dfc6 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -16,10 +16,14 @@ services: dspace-angular: container_name: dspace-angular environment: - DSPACE_HOST: dspace-angular - DSPACE_NAMESPACE: / - DSPACE_PORT: '4000' - DSPACE_SSL: "false" + DSPACE_UI_SSL: false + DSPACE_UI_HOST: dspace-angular + DSPACE_UI_PORT: '4000' + DSPACE_UI_NAMESPACE: / + DSPACE_REST_SSL: false + DSPACE_REST_HOST: localhost + DSPACE_REST_PORT: 8080 + DSPACE_REST_NAMESPACE: /server image: dspace/dspace-angular:dspace-7_x build: context: .. @@ -33,5 +37,3 @@ services: target: 9876 stdin_open: true tty: true - volumes: - - ./environment.dev.ts:/app/src/environments/environment.dev.ts diff --git a/docker/environment.dev.ts b/docker/environment.dev.ts deleted file mode 100644 index 0e603ef11d..0000000000 --- a/docker/environment.dev.ts +++ /dev/null @@ -1,18 +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/ - */ -// This file is based on environment.template.ts provided by Angular UI -export const environment = { - // Default to using the local REST API (running in Docker) - rest: { - ssl: false, - host: 'localhost', - port: 8080, - // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript - nameSpace: '/server' - } -}; diff --git a/docker/local.cfg b/docker/local.cfg deleted file mode 100644 index a511c25789..0000000000 --- a/docker/local.cfg +++ /dev/null @@ -1,6 +0,0 @@ -dspace.dir=/dspace -db.url=jdbc:postgresql://dspacedb:5432/dspace -dspace.server.url=http://localhost:8080/server -dspace.ui.url=http://localhost:4000 -dspace.name=DSpace Started with Docker Compose -solr.server=http://dspacesolr:8983/solr From 0550cd55d1fad7faca49fcd66c7ea826e5341c3e Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Thu, 23 Dec 2021 20:12:25 +0100 Subject: [PATCH 45/77] [CST-5064] Show submitter in version history table --- src/app/core/shared/version.model.ts | 6 +++ .../item-versions.component.html | 8 ++-- .../item-versions/item-versions.component.ts | 38 +++++++++++++++++-- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/app/core/shared/version.model.ts b/src/app/core/shared/version.model.ts index 48d6eb0b68..7207637a21 100644 --- a/src/app/core/shared/version.model.ts +++ b/src/app/core/shared/version.model.ts @@ -47,6 +47,12 @@ export class Version extends DSpaceObject { @autoserialize summary: string; + /** + * The name of the submitter of this version + */ + @autoserialize + submitterName: string; + /** * The Date this version was created */ diff --git a/src/app/shared/item/item-versions/item-versions.component.html b/src/app/shared/item/item-versions/item-versions.component.html index d8850bc544..432b10e8f1 100644 --- a/src/app/shared/item/item-versions/item-versions.component.html +++ b/src/app/shared/item/item-versions/item-versions.component.html @@ -17,7 +17,7 @@ {{"item.version.history.table.version" | translate}} - {{"item.version.history.table.editor" | translate}} + {{"item.version.history.table.editor" | translate}} {{"item.version.history.table.date" | translate}} {{"item.version.history.table.summary" | translate}} @@ -87,10 +87,8 @@ - - - {{eperson?.name}} - + + {{version?.submitterName}} {{version?.created | date : 'yyyy-MM-dd HH:mm:ss'}} diff --git a/src/app/shared/item/item-versions/item-versions.component.ts b/src/app/shared/item/item-versions/item-versions.component.ts index e7d65919d6..8ca8acf007 100644 --- a/src/app/shared/item/item-versions/item-versions.component.ts +++ b/src/app/shared/item/item-versions/item-versions.component.ts @@ -5,7 +5,6 @@ import { RemoteData } from '../../../core/data/remote-data'; import { BehaviorSubject, combineLatest, - combineLatest as observableCombineLatest, Observable, of, Subscription, @@ -48,6 +47,7 @@ import { ItemVersionsSharedService } from './item-versions-shared.service'; import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service'; +import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; @Component({ selector: 'ds-item-versions', @@ -180,6 +180,7 @@ export class ItemVersionsComponent implements OnInit { private authorizationService: AuthorizationDataService, private workspaceItemDataService: WorkspaceitemDataService, private workflowItemDataService: WorkflowItemDataService, + private configurationService: ConfigurationDataService, ) { } @@ -375,6 +376,37 @@ export class ItemVersionsComponent implements OnInit { return this.authorizationService.isAuthorized(FeatureID.CanEditVersion, version.self); } + /** + * Show submitter in version history table + */ + showSubmitter() { + + const includeSubmitter$ = this.configurationService.findByPropertyName('versioning.item.history.include.submitter').pipe( + getFirstSucceededRemoteDataPayload(), + map((configurationProperty) => configurationProperty.values[0]), + startWith(false), + ); + + const isAdmin$ = combineLatest([ + this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin), + this.authorizationService.isAuthorized(FeatureID.IsCommunityAdmin), + this.authorizationService.isAuthorized(FeatureID.AdministratorOf), + ]).pipe( + map(([isCollectionAdmin, isCommunityAdmin, isSiteAdmin]) => { + return isCollectionAdmin || isCommunityAdmin || isSiteAdmin; + }), + take(1), + tap((res) => { console.log('isAdmin = ' + res); }) + ); + + return combineLatest([includeSubmitter$, isAdmin$]).pipe( + map(([includeSubmitter, isAdmin]) => { + return includeSubmitter && isAdmin; + }) + ); + + } + /** * Check if the current user can delete the version * @param version @@ -389,7 +421,7 @@ export class ItemVersionsComponent implements OnInit { */ getAllVersions(versionHistory$: Observable): void { const currentPagination = this.paginationService.getCurrentPagination(this.options.id, this.options); - observableCombineLatest([versionHistory$, currentPagination]).pipe( + combineLatest([versionHistory$, currentPagination]).pipe( switchMap(([versionHistory, options]: [VersionHistory, PaginationComponentOptions]) => { return this.versionHistoryService.getVersions(versionHistory.id, new PaginatedSearchOptions({pagination: Object.assign({}, options, {currentPage: options.currentPage})}), @@ -486,7 +518,7 @@ export class ItemVersionsComponent implements OnInit { ); this.itemPageRoutes$ = this.versionsRD$.pipe( getAllSucceededRemoteDataPayload(), - switchMap((versions) => observableCombineLatest(...versions.page.map((version) => version.item.pipe(getAllSucceededRemoteDataPayload())))), + switchMap((versions) => combineLatest(versions.page.map((version) => version.item.pipe(getAllSucceededRemoteDataPayload())))), map((versions) => { const itemPageRoutes = {}; versions.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item)); From 12ab877ae4965b8acc7102a05be0972dd07bf114 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Thu, 23 Dec 2021 21:59:24 +0100 Subject: [PATCH 46/77] [CST-4981] fixed and finished unit testing --- .../admin-sidebar.component.spec.ts | 43 +++++++++++++++---- .../community-authorizations.component.ts | 4 +- src/app/navbar/navbar.component.spec.ts | 35 ++++++++++++++- src/app/navbar/navbar.component.ts | 7 +-- src/app/shared/menu/menu.component.spec.ts | 36 ++++------------ src/app/shared/menu/menu.component.ts | 7 ++- .../resource-policy-form.component.spec.ts | 4 +- .../statistics-page-routing.module.ts | 2 +- src/test.ts | 2 +- 9 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts index 948d7d86bc..65026c1504 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts @@ -18,6 +18,8 @@ import { ActivatedRoute } from '@angular/router'; import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../core/data/feature-authorization/feature-id'; import createSpy = jasmine.createSpy; +import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils'; +import { Item } from '../../core/shared/item.model'; describe('AdminSidebarComponent', () => { let comp: AdminSidebarComponent; @@ -26,6 +28,28 @@ describe('AdminSidebarComponent', () => { let authorizationService: AuthorizationDataService; let scriptService; + + const mockItem = Object.assign(new Item(), { + id: 'fake-id', + uuid: 'fake-id', + handle: 'fake/handle', + lastModified: '2018', + _links: { + self: { + href: 'https://localhost:8000/items/fake-id' + } + } + }); + + + const routeStub = { + data: observableOf({ + dso: createSuccessfulRemoteDataObject(mockItem) + }), + children: [] + }; + + beforeEach(waitForAsync(() => { authorizationService = jasmine.createSpyObj('authorizationService', { isAuthorized: observableOf(true) @@ -42,6 +66,7 @@ describe('AdminSidebarComponent', () => { { provide: ActivatedRoute, useValue: {} }, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: ScriptDataService, useValue: scriptService }, + { provide: ActivatedRoute, useValue: routeStub }, { provide: NgbModal, useValue: { open: () => {/*comment*/ @@ -229,19 +254,19 @@ describe('AdminSidebarComponent', () => { it('should contain site admin section', () => { expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'admin_search', visible: true, + id: 'admin_search', visible: true, })); expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'registries', visible: true, + id: 'registries', visible: true, })); expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - parentID: 'registries', visible: true, + parentID: 'registries', visible: true, })); expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'curation_tasks', visible: true, + id: 'curation_tasks', visible: true, })); expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'workflow', visible: true, + id: 'workflow', visible: true, })); }); }); @@ -259,7 +284,7 @@ describe('AdminSidebarComponent', () => { it('should show edit_community', () => { expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'edit_community', visible: true, + id: 'edit_community', visible: true, })); }); }); @@ -277,7 +302,7 @@ describe('AdminSidebarComponent', () => { it('should show edit_collection', () => { expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'edit_collection', visible: true, + id: 'edit_collection', visible: true, })); }); }); @@ -295,10 +320,10 @@ describe('AdminSidebarComponent', () => { it('should show access control section', () => { expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - id: 'access_control', visible: true, + id: 'access_control', visible: true, })); expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({ - parentID: 'access_control', visible: true, + parentID: 'access_control', visible: true, })); }); }); diff --git a/src/app/community-page/edit-community-page/community-authorizations/community-authorizations.component.ts b/src/app/community-page/edit-community-page/community-authorizations/community-authorizations.component.ts index 8b241af667..d2a95b1941 100644 --- a/src/app/community-page/edit-community-page/community-authorizations/community-authorizations.component.ts +++ b/src/app/community-page/edit-community-page/community-authorizations/community-authorizations.component.ts @@ -2,8 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { first, map } from 'rxjs/operators'; -import { RemoteData } from 'src/app/core/data/remote-data'; -import { DSpaceObject } from 'src/app/core/shared/dspace-object.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { RemoteData } from '../../../core/data/remote-data'; @Component({ selector: 'ds-community-authorizations', diff --git a/src/app/navbar/navbar.component.spec.ts b/src/app/navbar/navbar.component.spec.ts index cbe6738241..e8c9fae591 100644 --- a/src/app/navbar/navbar.component.spec.ts +++ b/src/app/navbar/navbar.component.spec.ts @@ -13,10 +13,39 @@ import { MenuService } from '../shared/menu/menu.service'; import { MenuServiceStub } from '../shared/testing/menu-service.stub'; import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { Item } from '../core/shared/item.model'; +import { createSuccessfulRemoteDataObject } from '../shared/remote-data.utils'; +import { By } from '@angular/platform-browser'; +import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; let comp: NavbarComponent; let fixture: ComponentFixture; +const authorizationService = jasmine.createSpyObj('authorizationService', { + isAuthorized: observableOf(true) +}); + +const mockItem = Object.assign(new Item(), { + id: 'fake-id', + uuid: 'fake-id', + handle: 'fake/handle', + lastModified: '2018', + _links: { + self: { + href: 'https://localhost:8000/items/fake-id' + } + } +}); + +const routeStub = { + data: observableOf({ + dso: createSuccessfulRemoteDataObject(mockItem) + }), + children: [] +}; + + + describe('NavbarComponent', () => { const menuService = new MenuServiceStub(); @@ -33,7 +62,8 @@ describe('NavbarComponent', () => { Injector, { provide: MenuService, useValue: menuService }, { provide: HostWindowService, useValue: new HostWindowServiceStub(800) }, - { provide: ActivatedRoute, useValue: {} } + { provide: AuthorizationDataService, useValue: authorizationService }, + { provide: ActivatedRoute, useValue: routeStub }, ], schemas: [NO_ERRORS_SCHEMA] }) @@ -42,7 +72,6 @@ describe('NavbarComponent', () => { // synchronous beforeEach beforeEach(() => { - spyOn(menuService, 'getMenuTopSections').and.returnValue(observableOf([])); fixture = TestBed.createComponent(NavbarComponent); @@ -53,4 +82,6 @@ describe('NavbarComponent', () => { it('should create', () => { expect(comp).toBeTruthy(); }); + + }); diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts index df4dd72477..103449ff71 100644 --- a/src/app/navbar/navbar.component.ts +++ b/src/app/navbar/navbar.component.ts @@ -7,11 +7,8 @@ import { TextMenuItemModel } from '../shared/menu/menu-item/models/text.model'; import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model'; import { HostWindowService } from '../shared/host-window.service'; import { environment } from '../../environments/environment'; -import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; -import { Router, ActivatedRoute } from '@angular/router'; -import { map, take } from 'rxjs/operators'; -import { RemoteData } from '../core/data/remote-data'; -import { Collection } from 'src/app/core/shared/collection.model'; +import { ActivatedRoute } from '@angular/router'; +import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; /** * Component representing the public navbar diff --git a/src/app/shared/menu/menu.component.spec.ts b/src/app/shared/menu/menu.component.spec.ts index 14e28591f3..ce764d7757 100644 --- a/src/app/shared/menu/menu.component.spec.ts +++ b/src/app/shared/menu/menu.component.spec.ts @@ -10,9 +10,9 @@ import { MenuSection } from './menu.reducer'; import { Router, ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MenuID } from './initial-menus-state'; -import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; -import { createSuccessfulRemoteDataObject } from 'src/app/shared/remote-data.utils'; import { Item } from '../../core/shared/item.model'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { createSuccessfulRemoteDataObject } from '../remote-data.utils'; describe('MenuComponent', () => { let comp: MenuComponent; @@ -22,6 +22,8 @@ describe('MenuComponent', () => { 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 authorizationService = jasmine.createSpyObj('authorizationService', { isAuthorized: observableOf(true) }); @@ -38,6 +40,7 @@ describe('MenuComponent', () => { } }); + const routeStub = { data: observableOf({ dso: createSuccessfulRemoteDataObject(mockItem) @@ -125,36 +128,15 @@ describe('MenuComponent', () => { }); describe('when unauthorized statistics', () => { - - beforeEach(() => { - comp.sections = observableOf([{ 'id': 'browse_global_communities_and_collections', 'active': false, 'visible': true, 'index': 0, 'model': { 'type': 1, 'text': 'menu.section.browse_global_communities_and_collections', 'link': '/community-list' }, 'shouldPersistOnRouteChange': true }, { 'id': 'browse_global', 'active': false, 'visible': true, 'index': 1, 'model': { 'type': 0, 'text': 'menu.section.browse_global' }, 'shouldPersistOnRouteChange': true }, { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }]); - authorizationService.isAuthorized().and.returnValue(observableOf(false)); - fixture.detectChanges(); + it('should get observable of empty object', () => { + expect(comp.getAuthorizedStatistics(mockStatisticSection)).toBeObservable({}); }); - - it('when authorized statistics', (done => { - comp.sections.subscribe((sections) => { - expect(sections.length).toEqual(2); - done(); - }); - })); }); describe('get authorized statistics', () => { - - beforeEach(() => { - comp.sections = observableOf([{ 'id': 'browse_global_communities_and_collections', 'active': false, 'visible': true, 'index': 0, 'model': { 'type': 1, 'text': 'menu.section.browse_global_communities_and_collections', 'link': '/community-list' }, 'shouldPersistOnRouteChange': true }, { 'id': 'browse_global', 'active': false, 'visible': true, 'index': 1, 'model': { 'type': 0, 'text': 'menu.section.browse_global' }, 'shouldPersistOnRouteChange': true }, { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }]); - fixture.detectChanges(); + it('should get observable of empty object', () => { + expect(comp.getAuthorizedStatistics(mockStatisticSection)).toBeObservable(mockStatisticSection); }); - - it('get authorized statistics', (done => { - comp.sections.subscribe((sections) => { - expect(sections.length).toEqual(3); - done(); - }); - })); }); - - }); diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts index 1070521704..584bee0b22 100644 --- a/src/app/shared/menu/menu.component.ts +++ b/src/app/shared/menu/menu.component.ts @@ -9,9 +9,9 @@ import { hasValue, isNotEmpty, hasValueOperator, isNotEmptyOperator } from '../e import { MenuSectionComponent } from './menu-section/menu-section.component'; import { getComponentForMenu } from './menu-section.decorator'; import { compareArraysUsingIds } from '../../item-page/simple/item-types/shared/item-relationships-utils'; -import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; -import { FeatureID } from 'src/app/core/data/feature-authorization/feature-id'; -import { Router, ActivatedRoute } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { FeatureID } from '../../core/data/feature-authorization/feature-id'; /** * A basic implementation of a MenuComponent @@ -87,7 +87,6 @@ export class MenuComponent implements OnInit, OnDestroy { this.subs.push( this.sections.pipe( - tap(t => console.log(t)), // if you return an array from a switchMap it will emit each element as a separate event. // So this switchMap is equivalent to a subscribe with a forEach inside switchMap((sections: MenuSection[]) => sections), diff --git a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts index 7f66eb052c..d65f7346a8 100644 --- a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts +++ b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts @@ -32,13 +32,13 @@ import { RESOURCE_POLICY } from '../../../core/resource-policy/models/resource-p import { EPersonMock } from '../../testing/eperson.mock'; import { isNotEmptyOperator } from '../../empty.util'; import { ActivatedRoute, Router } from '@angular/router'; -import { RemoteData } from 'src/app/core/data/remote-data'; import { RouterMock } from '../../mocks/router.mock'; import { Store } from '@ngrx/store'; import { PaginationServiceStub } from '../../testing/pagination-service.stub'; -import { PaginationService } from 'src/app/core/pagination/pagination.service'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { StoreMock } from '../../testing/store.mock'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginationService } from '../../../core/pagination/pagination.service'; export const mockResourcePolicyFormData = { name: [ diff --git a/src/app/statistics-page/statistics-page-routing.module.ts b/src/app/statistics-page/statistics-page-routing.module.ts index 6047a82f1e..ef6f68d557 100644 --- a/src/app/statistics-page/statistics-page-routing.module.ts +++ b/src/app/statistics-page/statistics-page-routing.module.ts @@ -10,7 +10,7 @@ import { ThemedCommunityStatisticsPageComponent } from './community-statistics-p import { ThemedItemStatisticsPageComponent } from './item-statistics-page/themed-item-statistics-page.component'; import { ThemedSiteStatisticsPageComponent } from './site-statistics-page/themed-site-statistics-page.component'; import { ItemResolver } from '../item-page/item.resolver'; -import { StatisticsAdministratorGuard } from 'src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard'; +import { StatisticsAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard'; @NgModule({ imports: [ diff --git a/src/test.ts b/src/test.ts index c77b4bb2f0..16317897b1 100644 --- a/src/test.ts +++ b/src/test.ts @@ -15,6 +15,6 @@ getTestBed().initTestEnvironment( platformBrowserDynamicTesting() ); // Then we find all the tests. -const context = require.context('./app/shared/menu', true, /\.spec\.ts$/); +const context = require.context('./', true, /\.spec\.ts$/); // And load the modules. context.keys().map(context); From d2a4a5550775b0595c48c4b7aa1583ff91f6aeba Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 23 Dec 2021 23:41:56 +0100 Subject: [PATCH 47/77] [CST-4633] fix issue with filter scope and configuration --- .../search-filters.component.ts | 19 +++++++++++++++---- .../search-sidebar.component.html | 5 ++++- .../search-sidebar.component.ts | 5 +++++ src/app/shared/search/search.component.html | 6 ++++-- src/app/shared/search/search.component.ts | 18 ++++++++++++++---- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 8b870f6467..b3850f3b49 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -1,7 +1,7 @@ import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { map, switchMap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { RemoteData } from '../../../core/data/remote-data'; @@ -36,6 +36,16 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { */ clearParams; + /** + * The configuration to use for the search options + */ + @Input() currentConfiguration; + + /** + * The current search scope + */ + @Input() currentScope: string; + /** * True when the search component should show results on the current page */ @@ -56,8 +66,9 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { /** * Initialize instance variables * @param {SearchService} searchService - * @param {SearchConfigurationService} searchConfigService * @param {SearchFilterService} filterService + * @param {Router} router + * @param {SearchConfigurationService} searchConfigService */ constructor( private searchService: SearchService, @@ -82,8 +93,8 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { } initFilters() { - this.filters = this.searchConfigService.searchOptions.pipe( - switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getFirstSucceededRemoteData())), + this.filters = this.searchService.getConfig(this.currentScope, this.currentConfiguration).pipe( + getFirstSucceededRemoteData() ); } diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.html b/src/app/shared/search/search-sidebar/search-sidebar.component.html index c19831d71d..c9e34d5007 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.html +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.html @@ -15,7 +15,10 @@ [defaultConfiguration]="configuration" [inPlaceSearch]="inPlaceSearch" (changeConfiguration)="changeConfiguration.emit($event)"> - + diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.ts index f9f7165401..1b22144565 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.ts +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.ts @@ -32,6 +32,11 @@ export class SearchSidebarComponent { */ @Input() configurationList: SearchConfigurationOption[]; + /** + * The current search scope + */ + @Input() currentScope: string; + /** * The current sort option used */ diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index f21dbeab22..02f59b2163 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -6,11 +6,11 @@ -
+
- + @@ -41,6 +41,7 @@ = new BehaviorSubject(null); + /** + * The current sort options used + */ + currentScope$: BehaviorSubject = new BehaviorSubject(''); + + /** + * The current sort options used + */ + currentSortOptions$: BehaviorSubject = new BehaviorSubject(null); + /** * The current search results */ @@ -127,9 +137,9 @@ export class SearchComponent implements OnInit { sortOptionsList$: BehaviorSubject = new BehaviorSubject([]); /** - * The current sort options used + * TRUE if the search option are initialized */ - currentSortOptions$: BehaviorSubject = new BehaviorSubject(null); + initialized$: BehaviorSubject = new BehaviorSubject(false); /** * Observable for whether or not the sidebar is currently collapsed @@ -204,7 +214,6 @@ export class SearchComponent implements OnInit { return searchOptions.pagination.id === this.paginationId; }) ).subscribe(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => { - // Build the PaginatedSearchOptions object const combinedOptions = Object.assign({}, searchOptions, { @@ -215,9 +224,10 @@ export class SearchComponent implements OnInit { // Initialize variables this.currentConfiguration$.next(configuration); this.currentSortOptions$.next(newSearchOptions.sort); + this.currentScope$.next(newSearchOptions.scope); this.sortOptionsList$.next(searchSortOptions); this.searchOptions$.next(newSearchOptions); - + this.initialized$.next(true); // retrieve results this.retrieveSearchResults(newSearchOptions); }); From ffaebabd3bb544f4f9cb450272ed4fd2f931f36f Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Fri, 24 Dec 2021 00:47:31 +0100 Subject: [PATCH 48/77] [CST-5064] Tests WIP --- .../item/item-versions/item-versions.component.spec.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/shared/item/item-versions/item-versions.component.spec.ts b/src/app/shared/item/item-versions/item-versions.component.spec.ts index fff0744aba..4600f6a165 100644 --- a/src/app/shared/item/item-versions/item-versions.component.spec.ts +++ b/src/app/shared/item/item-versions/item-versions.component.spec.ts @@ -24,8 +24,9 @@ import { AuthorizationDataService } from '../../../core/data/feature-authorizati import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service'; +import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; -describe('ItemVersionsComponent', () => { +fdescribe('ItemVersionsComponent', () => { let component: ItemVersionsComponent; let fixture: ComponentFixture; let authenticationService: AuthService; @@ -109,6 +110,10 @@ describe('ItemVersionsComponent', () => { findById: EMPTY, }); + const configurationServiceSpy = jasmine.createSpyObj('configurationService', { + findByPropertyName: of(true), + }); + beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -125,6 +130,7 @@ describe('ItemVersionsComponent', () => { {provide: VersionDataService, useValue: versionServiceSpy}, {provide: WorkspaceitemDataService, useValue: workspaceItemDataServiceSpy}, {provide: WorkflowItemDataService, useValue: workflowItemDataServiceSpy}, + {provide: ConfigurationDataService, useValue: configurationServiceSpy()}, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); From 9fd34034b9459433bd495cb4f2997628bdd566ce Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Fri, 24 Dec 2021 10:13:50 +0100 Subject: [PATCH 49/77] [CST-5064] Tests --- .../item/item-versions/item-versions.component.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/item/item-versions/item-versions.component.spec.ts b/src/app/shared/item/item-versions/item-versions.component.spec.ts index 4600f6a165..8bb5554b77 100644 --- a/src/app/shared/item/item-versions/item-versions.component.spec.ts +++ b/src/app/shared/item/item-versions/item-versions.component.spec.ts @@ -26,7 +26,7 @@ import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service'; import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; -fdescribe('ItemVersionsComponent', () => { +describe('ItemVersionsComponent', () => { let component: ItemVersionsComponent; let fixture: ComponentFixture; let authenticationService: AuthService; @@ -35,6 +35,7 @@ fdescribe('ItemVersionsComponent', () => { let workspaceItemDataService: WorkspaceitemDataService; let workflowItemDataService: WorkflowItemDataService; let versionService: VersionDataService; + let configurationService: ConfigurationDataService; const versionHistory = Object.assign(new VersionHistory(), { id: '1', @@ -130,7 +131,7 @@ fdescribe('ItemVersionsComponent', () => { {provide: VersionDataService, useValue: versionServiceSpy}, {provide: WorkspaceitemDataService, useValue: workspaceItemDataServiceSpy}, {provide: WorkflowItemDataService, useValue: workflowItemDataServiceSpy}, - {provide: ConfigurationDataService, useValue: configurationServiceSpy()}, + {provide: ConfigurationDataService, useValue: configurationServiceSpy}, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -141,6 +142,7 @@ fdescribe('ItemVersionsComponent', () => { workspaceItemDataService = TestBed.inject(WorkspaceitemDataService); workflowItemDataService = TestBed.inject(WorkflowItemDataService); versionService = TestBed.inject(VersionDataService); + configurationService = TestBed.inject(ConfigurationDataService); })); From 6f86824f2302a64f27d1b09bcf0af92a5327e700 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 24 Dec 2021 11:16:16 +0100 Subject: [PATCH 50/77] [CST-4633] restored ds-my-dspace-new-submission from mydspace page --- src/app/my-dspace-page/my-dspace-page.component.html | 4 ++++ src/app/my-dspace-page/my-dspace-page.component.ts | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/app/my-dspace-page/my-dspace-page.component.html b/src/app/my-dspace-page/my-dspace-page.component.html index 2b0dc7108a..45cade0804 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.html +++ b/src/app/my-dspace-page/my-dspace-page.component.html @@ -1,3 +1,7 @@ +
+ +
+ = new InjectionToken('searchConfigurationService'); @@ -46,6 +47,11 @@ export class MyDSpacePageComponent implements OnInit { */ configuration: string; + /** + * Variable for enumeration RoleType + */ + roleTypeEnum = RoleType; + /** * List of available view mode */ From cff29539fbf58b7afbe9943e61c845950f06b5d1 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 24 Dec 2021 11:41:23 +0100 Subject: [PATCH 51/77] [CST-4633] fix issue with view mode list --- .../search-sidebar/search-sidebar.component.ts | 3 ++- src/app/shared/search/search.component.html | 2 ++ src/app/shared/search/search.component.ts | 12 ++++++++++-- .../view-mode-switch/view-mode-switch.component.ts | 6 +++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.ts index 1b22144565..39207bdbd6 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.ts +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.ts @@ -4,6 +4,7 @@ import { SearchConfigurationOption } from '../search-switch-configuration/search import { Observable } from 'rxjs'; import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; +import { ViewMode } from '../../../core/shared/view-mode.model'; /** * This component renders a simple item page. @@ -50,7 +51,7 @@ export class SearchSidebarComponent { /** * The list of available view mode options */ - @Input() viewModeList; + @Input() viewModeList: ViewMode[]; /** * Whether to show the view mode switch diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index 02f59b2163..e445b0669c 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -47,6 +47,7 @@ [sortOptionsList]="(sortOptionsList$ | async)" [currentSortOption]="(currentSortOptions$ | async)" [inPlaceSearch]="inPlaceSearch" + [viewModeList]="viewModeList" (changeConfiguration)="changeContext($event.context)">
diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 04bb5a2a7b..f739242357 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -96,6 +96,11 @@ export class SearchComponent implements OnInit { */ @Input() showSidebar = true; + /** + * List of available view mode + */ + @Input() useUniquePageId: false; + /** * List of available view mode */ @@ -178,8 +183,11 @@ export class SearchComponent implements OnInit { * If something changes, update the list of scopes for the dropdown */ ngOnInit(): void { - // Create an unique pagination id related to the instance of the SearchComponent - this.paginationId = uniqueId(this.paginationId); + if (this.useUniquePageId) { + // Create an unique pagination id related to the instance of the SearchComponent + this.paginationId = uniqueId(this.paginationId); + } + this.searchConfigService.setPaginationId(this.paginationId); if (hasValue(this.fixedFilterQuery)) { diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.ts b/src/app/shared/view-mode-switch/view-mode-switch.component.ts index 4feb8927c2..146cb042f3 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.ts +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.ts @@ -17,13 +17,17 @@ import { Router } from '@angular/router'; templateUrl: './view-mode-switch.component.html' }) export class ViewModeSwitchComponent implements OnInit, OnDestroy { - @Input() viewModeList: ViewMode[]; /** * True when the search component should show results on the current page */ @Input() inPlaceSearch; + /** + * List of available view mode + */ + @Input() viewModeList: ViewMode[]; + /** * The current view mode */ From e76514ca39f0a17a5597ab59b289284c76635321 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 24 Dec 2021 11:51:06 +0100 Subject: [PATCH 52/77] [CST-4633] fix issue with view mode --- .../object-collection/object-collection.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts index 52881f5eaf..b567a6f0ba 100644 --- a/src/app/shared/object-collection/object-collection.component.ts +++ b/src/app/shared/object-collection/object-collection.component.ts @@ -2,14 +2,14 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } fro import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; -import { filter, map, startWith } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { RemoteData } from '../../core/data/remote-data'; import { PageInfo } from '../../core/shared/page-info.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { ListableObject } from './shared/listable-object.model'; -import { isNotEmpty } from '../empty.util'; +import { isEmpty, isNotEmpty } from '../empty.util'; import { ViewMode } from '../../core/shared/view-mode.model'; import { CollectionElementLinkType } from './collection-element-link.type'; import { PaginatedList } from '../../core/data/paginated-list.model'; @@ -137,8 +137,8 @@ export class ObjectCollectionComponent implements OnInit { .queryParams .pipe( filter((params) => isNotEmpty(params.view)), - map((params) => params.view), - startWith(ViewMode.ListElement) + map((params) => isEmpty(params?.view) ? ViewMode.ListElement : params.view), + distinctUntilChanged() ); } From f154fb60e09a19dd4500198c096a69a154371593 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Fri, 24 Dec 2021 17:49:55 +0100 Subject: [PATCH 53/77] [CST-4981] Fixed unit testing --- src/app/shared/menu/menu.component.spec.ts | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/app/shared/menu/menu.component.spec.ts b/src/app/shared/menu/menu.component.spec.ts index ce764d7757..b84fad2b33 100644 --- a/src/app/shared/menu/menu.component.spec.ts +++ b/src/app/shared/menu/menu.component.spec.ts @@ -24,9 +24,7 @@ describe('MenuComponent', () => { const mockStatisticSection = { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }; - const authorizationService = jasmine.createSpyObj('authorizationService', { - isAuthorized: observableOf(true) - }); + let authorizationService: AuthorizationDataService; const mockItem = Object.assign(new Item(), { id: 'fake-id', @@ -49,6 +47,11 @@ describe('MenuComponent', () => { }; beforeEach(waitForAsync(() => { + + authorizationService = jasmine.createSpyObj('authorizationService', { + isAuthorized: observableOf(false) + }); + TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule], declarations: [MenuComponent], @@ -128,14 +131,32 @@ describe('MenuComponent', () => { }); describe('when unauthorized statistics', () => { - it('should get observable of empty object', () => { - expect(comp.getAuthorizedStatistics(mockStatisticSection)).toBeObservable({}); + + beforeEach(() => { + (authorizationService as any).isAuthorized.and.returnValue(observableOf(false)); + fixture.detectChanges(); + }); + + it('should return observable of empty object', done => { + comp.getAuthorizedStatistics(mockStatisticSection).subscribe((res) => { + expect(res).toEqual({}); + done(); + }); }); }); describe('get authorized statistics', () => { - it('should get observable of empty object', () => { - expect(comp.getAuthorizedStatistics(mockStatisticSection)).toBeObservable(mockStatisticSection); + + beforeEach(() => { + (authorizationService as any).isAuthorized.and.returnValue(observableOf(true)); + fixture.detectChanges(); + }); + + it('should return observable of statistics section menu', done => { + comp.getAuthorizedStatistics(mockStatisticSection).subscribe((res) => { + expect(res).toEqual(mockStatisticSection); + done(); + }); }); }); From 99aef984431ac35f98e054382e74913dd71bd640 Mon Sep 17 00:00:00 2001 From: Rezart Vata Date: Fri, 24 Dec 2021 19:34:10 +0100 Subject: [PATCH 54/77] [CST-4981] structure improvement,removed unecessary informations --- src/app/collection-page/collection-page-routing.module.ts | 1 - src/app/community-page/community-page-routing.module.ts | 1 - .../statistics-administrator.guard.ts | 1 - src/app/home-page/home-page-routing.module.ts | 1 - src/app/item-page/item-page-routing.module.ts | 1 - 5 files changed, 5 deletions(-) diff --git a/src/app/collection-page/collection-page-routing.module.ts b/src/app/collection-page/collection-page-routing.module.ts index b92c5bf414..5879e523af 100644 --- a/src/app/collection-page/collection-page-routing.module.ts +++ b/src/app/collection-page/collection-page-routing.module.ts @@ -72,7 +72,6 @@ import { ThemedCollectionPageComponent } from './themed-collection-page.componen id: 'statistics_collection_:id', active: true, visible: true, - type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/community-page/community-page-routing.module.ts b/src/app/community-page/community-page-routing.module.ts index 1be5472010..ad1b1fd2f2 100644 --- a/src/app/community-page/community-page-routing.module.ts +++ b/src/app/community-page/community-page-routing.module.ts @@ -55,7 +55,6 @@ import { ThemedCommunityPageComponent } from './themed-community-page.component' id: 'statistics_community_:id', active: true, visible: true, - type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts b/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts index 41ea8550a7..680495686e 100644 --- a/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts +++ b/src/app/core/data/feature-authorization/feature-authorization-guard/statistics-administrator.guard.ts @@ -5,7 +5,6 @@ import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/ro import { AuthService } from '../../../auth/auth.service'; import { Observable, of as observableOf } from 'rxjs'; import { FeatureID } from '../feature-id'; -import { tap } from 'rxjs/operators'; /** * Prevent unauthorized activating and loading of routes when the current authenticated user doesn't have group diff --git a/src/app/home-page/home-page-routing.module.ts b/src/app/home-page/home-page-routing.module.ts index 2356170d4b..2a41c079da 100644 --- a/src/app/home-page/home-page-routing.module.ts +++ b/src/app/home-page/home-page-routing.module.ts @@ -21,7 +21,6 @@ import { ThemedHomePageComponent } from './themed-home-page.component'; active: true, visible: true, index: 2, - type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', diff --git a/src/app/item-page/item-page-routing.module.ts b/src/app/item-page/item-page-routing.module.ts index b0412e5a0b..7d7912bb42 100644 --- a/src/app/item-page/item-page-routing.module.ts +++ b/src/app/item-page/item-page-routing.module.ts @@ -58,7 +58,6 @@ import { REQUEST_COPY_MODULE_PATH } from '../app-routing-paths'; id: 'statistics_item_:id', active: true, visible: true, - type: 'statistics', model: { type: MenuItemType.LINK, text: 'menu.section.statistics', From 3b00d0146661869ee396a365b056dab9cdcbc1c2 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 4 Jan 2022 12:59:52 +0100 Subject: [PATCH 55/77] [CST-4633] fix issue with view mode when not in params --- .../shared/object-collection/object-collection.component.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts index b567a6f0ba..29fdb37ea1 100644 --- a/src/app/shared/object-collection/object-collection.component.ts +++ b/src/app/shared/object-collection/object-collection.component.ts @@ -2,14 +2,14 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } fro import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; -import { distinctUntilChanged, filter, map } from 'rxjs/operators'; +import { distinctUntilChanged, map } from 'rxjs/operators'; import { RemoteData } from '../../core/data/remote-data'; import { PageInfo } from '../../core/shared/page-info.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { ListableObject } from './shared/listable-object.model'; -import { isEmpty, isNotEmpty } from '../empty.util'; +import { isEmpty } from '../empty.util'; import { ViewMode } from '../../core/shared/view-mode.model'; import { CollectionElementLinkType } from './collection-element-link.type'; import { PaginatedList } from '../../core/data/paginated-list.model'; @@ -136,7 +136,6 @@ export class ObjectCollectionComponent implements OnInit { this.currentMode$ = this.route .queryParams .pipe( - filter((params) => isNotEmpty(params.view)), map((params) => isEmpty(params?.view) ? ViewMode.ListElement : params.view), distinctUntilChanged() ); From 216eb40ab5bfa37bc857c64f742eea4694f73dfa Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Mon, 10 Jan 2022 10:30:11 +0100 Subject: [PATCH 56/77] [CST-5064] console.log removed --- src/app/shared/item/item-versions/item-versions.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/shared/item/item-versions/item-versions.component.ts b/src/app/shared/item/item-versions/item-versions.component.ts index 8ca8acf007..6796dfd1ad 100644 --- a/src/app/shared/item/item-versions/item-versions.component.ts +++ b/src/app/shared/item/item-versions/item-versions.component.ts @@ -396,7 +396,6 @@ export class ItemVersionsComponent implements OnInit { return isCollectionAdmin || isCommunityAdmin || isSiteAdmin; }), take(1), - tap((res) => { console.log('isAdmin = ' + res); }) ); return combineLatest([includeSubmitter$, isAdmin$]).pipe( From 7e7ad9a4f375e6592fe1d53e02ad6115ea6705d7 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 12 Jan 2022 18:32:33 +0100 Subject: [PATCH 57/77] [CST-4880] Add fallback strategy for hanging server check cached requests --- src/app/core/server-check/server-check.guard.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index af216bef0e..7c3329f51d 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -1,8 +1,8 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; -import { Observable } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { interval, Observable, race } from 'rxjs'; +import { map, mergeMapTo, tap } from 'rxjs/operators'; import { RootDataService } from '../data/root-data.service'; import { RemoteData } from '../data/remote-data'; @@ -27,7 +27,11 @@ export class ServerCheckGuard implements CanActivateChild { route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.rootDataService.findRoot(false).pipe( + const uncachedCheck$ = this.rootDataService.findRoot(false); + // fallback observable used if the uncached one hangs and doesn't emit value + const cachedCheck$ = interval(200).pipe(mergeMapTo((this.rootDataService.findRoot()))); + + return race([uncachedCheck$, cachedCheck$]).pipe( getFirstCompletedRemoteData(), map((res: RemoteData) => res.hasSucceeded), tap((hasSucceeded: boolean) => { From 6d1674cc8a31d66f9d9ca9e8a41501c1be1e3353 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 12 Jan 2022 20:09:21 +0100 Subject: [PATCH 58/77] [CST-4981] Fix issue with missing statistics menu --- src/app/shared/menu/menu.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts index 584bee0b22..caf613a33f 100644 --- a/src/app/shared/menu/menu.component.ts +++ b/src/app/shared/menu/menu.component.ts @@ -1,11 +1,11 @@ import { ChangeDetectionStrategy, Component, Injector, OnDestroy, OnInit } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription, of as observableOf } from 'rxjs'; +import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; import { MenuService } from './menu.service'; import { MenuID } from './initial-menus-state'; import { MenuSection } from './menu.reducer'; -import { distinctUntilChanged, map, switchMap, mergeMap, tap, isEmpty } from 'rxjs/operators'; +import { distinctUntilChanged, map, mergeMap, switchMap } from 'rxjs/operators'; import { GenericConstructor } from '../../core/shared/generic-constructor'; -import { hasValue, isNotEmpty, hasValueOperator, isNotEmptyOperator } from '../empty.util'; +import { hasValue, isNotEmptyOperator } from '../empty.util'; import { MenuSectionComponent } from './menu-section/menu-section.component'; import { getComponentForMenu } from './menu-section.decorator'; import { compareArraysUsingIds } from '../../item-page/simple/item-types/shared/item-relationships-utils'; @@ -90,7 +90,7 @@ export class MenuComponent implements OnInit, OnDestroy { // if you return an array from a switchMap it will emit each element as a separate event. // So this switchMap is equivalent to a subscribe with a forEach inside switchMap((sections: MenuSection[]) => sections), - switchMap((section: MenuSection) => { + mergeMap((section: MenuSection) => { if (section.id.includes('statistics')) { return this.getAuthorizedStatistics(section); } From 0c9dc4286c43e8ac73a784a5803c2b1fcc5cb075 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 12 Jan 2022 20:09:48 +0100 Subject: [PATCH 59/77] [CST-4981] Fix error with yarn clean command --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 403973ef98..278afdf6c3 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "clean:json": "rimraf *.records.json", "clean:node": "rimraf node_modules", "clean:prod": "yarn run clean:dist && yarn run clean:log && yarn run clean:doc && yarn run clean:coverage && yarn run clean:json", - "clean": "yarn run clean:prod && yarn run clean:node && yarn run clean:dev:config", + "clean": "yarn run clean:prod && yarn run clean:dev:config && yarn run clean:node", "sync-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/sync-i18n-files.ts", "build:mirador": "webpack --config webpack/webpack.mirador.config.ts", "merge-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/merge-i18n-files.ts", From 8666ae74f6caf172e955220c392746ce79ae1aaa Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 13 Jan 2022 10:48:46 +0100 Subject: [PATCH 60/77] 86367: Process empty parameters fix --- .../process-page/form/process-form.component.spec.ts | 11 +++++++++++ src/app/process-page/form/process-form.component.ts | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app/process-page/form/process-form.component.spec.ts b/src/app/process-page/form/process-form.component.spec.ts index fce7368d54..10bc8294d3 100644 --- a/src/app/process-page/form/process-form.component.spec.ts +++ b/src/app/process-page/form/process-form.component.spec.ts @@ -87,4 +87,15 @@ describe('ProcessFormComponent', () => { component.submitForm({ controls: {} } as any); expect(scriptService.invoke).toHaveBeenCalled(); }); + + describe('when undefined parameters are provided', () => { + beforeEach(() => { + component.parameters = undefined; + }); + + it('should invoke the script with an empty array of parameters', () => { + component.submitForm({ controls: {} } as any); + expect(scriptService.invoke).toHaveBeenCalledWith(script.id, [], jasmine.anything()); + }); + }); }); diff --git a/src/app/process-page/form/process-form.component.ts b/src/app/process-page/form/process-form.component.ts index 1507fe05e9..70eb3160a8 100644 --- a/src/app/process-page/form/process-form.component.ts +++ b/src/app/process-page/form/process-form.component.ts @@ -12,6 +12,7 @@ import { Router } from '@angular/router'; import { getFirstCompletedRemoteData } from '../../core/shared/operators'; import { RemoteData } from '../../core/data/remote-data'; import { getProcessListRoute } from '../process-page-routing.paths'; +import { isEmpty } from '../../shared/empty.util'; /** * Component to create a new script @@ -35,7 +36,7 @@ export class ProcessFormComponent implements OnInit { /** * The parameter values to use to start the process */ - @Input() public parameters: ProcessParameter[]; + @Input() public parameters: ProcessParameter[] = []; /** * Optional files that are used as parameter values @@ -69,6 +70,9 @@ export class ProcessFormComponent implements OnInit { * @param form */ submitForm(form: NgForm) { + if (isEmpty(this.parameters)) { + this.parameters = []; + } if (!this.validateForm(form) || this.isRequiredMissing()) { return; } From 539ae50214755e66b5cf227e16c6ee9edeca64f9 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 13 Jan 2022 15:16:40 +0100 Subject: [PATCH 61/77] [CST-4633] Change label translations --- src/assets/i18n/en.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 1ab27fdb0e..6b47238f5b 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2588,7 +2588,7 @@ "mydspace.search-form.placeholder": "Search in mydspace...", - "mydspace.show.workflow": "All tasks", + "mydspace.show.workflow": "Workflow tasks", "mydspace.show.workspace": "Your Submissions", @@ -4023,7 +4023,7 @@ "workflowAdmin.search.results.head": "Administer Workflow", - "workflow.search.results.head": "All tasks", + "workflow.search.results.head": "Workflow tasks", From 6b2efd2b1622d049a5c2dab0799058e488d24a5d Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 13 Jan 2022 15:17:06 +0100 Subject: [PATCH 62/77] [CST-4633] Change view mode labels --- src/app/core/shared/view-mode.model.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/core/shared/view-mode.model.ts b/src/app/core/shared/view-mode.model.ts index c2f076a5e5..a27cb6954b 100644 --- a/src/app/core/shared/view-mode.model.ts +++ b/src/app/core/shared/view-mode.model.ts @@ -3,8 +3,8 @@ */ export enum ViewMode { - ListElement = 'listElement', - GridElement = 'gridElement', - DetailedListElement = 'detailedListElement', - StandalonePage = 'standalonePage', + ListElement = 'list', + GridElement = 'grid', + DetailedListElement = 'detailed', + StandalonePage = 'standalone', } From 0d73b6d164979f122522b5e0ba5ffb4b637fdb4c Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 14 Jan 2022 12:15:12 +0100 Subject: [PATCH 63/77] [CST-4633] Fix issue with detail view mode --- .../search-sidebar.component.html | 4 +- .../search-sidebar.component.ts | 5 + src/app/shared/search/search.component.html | 6 +- src/app/shared/search/search.component.ts | 7 ++ .../view-mode-switch.component.html | 2 +- .../view-mode-switch.component.spec.ts | 93 ++++++++++++++----- .../view-mode-switch.component.ts | 22 ++++- 7 files changed, 110 insertions(+), 29 deletions(-) diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.html b/src/app/shared/search/search-sidebar/search-sidebar.component.html index c9e34d5007..e17fe941ba 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.html +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.html @@ -8,7 +8,9 @@
- +
- + + + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts index 09929f1973..72c026e42e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts @@ -4,7 +4,6 @@ import { DsDynamicLookupRelationSearchTabComponent } from './dynamic-lookup-rela import { SearchService } from '../../../../../../core/shared/search/search.service'; import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; -import { RouteService } from '../../../../../../core/services/route.service'; import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { VarDirective } from '../../../../../utils/var.directive'; @@ -15,13 +14,13 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../remote-data.ut import { buildPaginatedList } from '../../../../../../core/data/paginated-list.model'; import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; import { Item } from '../../../../../../core/shared/item.model'; -import { ActivatedRoute } from '@angular/router'; import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; import { RelationshipService } from '../../../../../../core/data/relationship.service'; import { relatedRelationships } from '../../../../../testing/related-relationships.mock'; import { RelationshipType } from '../../../../../../core/shared/item-relationships/relationship-type.model'; +import { SearchObjects } from '../../../../../search/models/search-objects.model'; describe('DsDynamicLookupRelationSearchTabComponent', () => { @@ -41,6 +40,7 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { let selection$; let results; + let searchResult; let selectableListService; let lookupRelationService; const relationshipService = jasmine.createSpyObj('searchByItemsAndType',{ @@ -79,6 +79,9 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { selection$ = observableOf([searchResult1, searchResult2]); results = buildPaginatedList(undefined, [searchResult1, searchResult2, searchResult3]); + searchResult = Object.assign(new SearchObjects(), { + page: [searchResult1, searchResult2, searchResult3] + }); selectableListService = jasmine.createSpyObj('selectableListService', ['deselect', 'select', 'deselectAll']); lookupRelationService = jasmine.createSpyObj('lookupRelationService', { getLocalResults: createSuccessfulRemoteDataObject$(results) @@ -101,14 +104,6 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { paginatedSearchOptions: observableOf(pSearchOptions) } }, - { - provide: RouteService, useValue: { - setParameter: () => { - // do nothing - } - } - }, - { provide: ActivatedRoute, useValue: { snapshot: { queryParams: {} } } }, { provide: LookupRelationService, useValue: lookupRelationService }, { provide: PaginationService, useValue: new PaginationServiceStub() }, { provide: RelationshipService, useValue: relationshipService } @@ -186,6 +181,7 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { describe('check searchByItemsAndType', () => { it('should call relationshipService.searchByItemsAndType', () => { + component.onResultFound(searchResult); expect(relationshipService.searchByItemsAndType).toHaveBeenCalled(); }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts index 23dd97601e..5a6b07fd44 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts @@ -4,18 +4,15 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search import { Item } from '../../../../../../core/shared/item.model'; import { SearchResult } from '../../../../../search/models/search-result.model'; import { PaginatedList } from '../../../../../../core/data/paginated-list.model'; -import { RemoteData } from '../../../../../../core/data/remote-data'; import { Observable } from 'rxjs'; import { RelationshipOptions } from '../../../models/relationship-options.model'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; import { ListableObject } from '../../../../../object-collection/shared/listable-object.model'; import { SearchService } from '../../../../../../core/shared/search/search.service'; -import { ActivatedRoute, Router } from '@angular/router'; import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service'; import { hasValue } from '../../../../../empty.util'; -import { map, mapTo, startWith, switchMap, take, tap } from 'rxjs/operators'; +import { map, mapTo, switchMap, take, tap } from 'rxjs/operators'; import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../../../../../core/shared/operators'; -import { RouteService } from '../../../../../../core/services/route.service'; import { CollectionElementLinkType } from '../../../../../object-collection/collection-element-link.type'; import { Context } from '../../../../../../core/shared/context.model'; import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service'; @@ -24,6 +21,9 @@ import { RelationshipService } from '../../../../../../core/data/relationship.se import { RelationshipType } from '../../../../../../core/shared/item-relationships/relationship-type.model'; import { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model'; +import { SearchObjects } from '../../../../../search/models/search-objects.model'; +import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; @Component({ @@ -107,7 +107,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest /** * Search results */ - resultsRD$: Observable>>>; + resultsRD$: BehaviorSubject> = new BehaviorSubject>(null); /** * Are all results selected? @@ -142,13 +142,15 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest */ linkTypes = CollectionElementLinkType; + /** + * Emits an event with the current search result entries + */ + @Output() resultFound: EventEmitter> = new EventEmitter>(); + constructor( private searchService: SearchService, - private router: Router, - private route: ActivatedRoute, private selectableListService: SelectableListService, public searchConfigService: SearchConfigurationService, - private routeService: RouteService, public lookupRelationService: LookupRelationService, private relationshipService: RelationshipService, private paginationService: PaginationService @@ -160,21 +162,6 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest */ ngOnInit(): void { this.resetRoute(); - this.routeService.setParameter('fixedFilterQuery', this.relationship.filter); - this.routeService.setParameter('configuration', this.relationship.searchConfiguration); - this.resultsRD$ = this.searchConfigService.paginatedSearchOptions.pipe( - switchMap((options) => this.lookupRelationService.getLocalResults(this.relationship, options).pipe( - tap( res => { - if ( !!res && res.hasSucceeded && this.isEditRelationship ) { - const idOfItems = res.payload.page.map( itemSearchResult => { - return itemSearchResult.indexableObject.uuid; - }); - this.setSelectedIds(idOfItems,res.payload.page); - } - }), - startWith(undefined), - )) - ); } /** @@ -188,7 +175,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest * Selects a page in the store * @param page The page to select */ - selectPage(page: SearchResult[]) { + selectPage(page: SearchResult[]) { this.selection$ .pipe(take(1)) .subscribe((selection: SearchResult[]) => { @@ -202,7 +189,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest * Deselects a page in the store * @param page the page to deselect */ - deselectPage(page: SearchResult[]) { + deselectPage(page: SearchResult[]) { this.allSelected = false; this.selection$ .pipe(take(1)) @@ -306,4 +293,16 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest this.subscription.unsubscribe(); } } + + onResultFound($event: SearchObjects) { + console.log($event); + this.resultsRD$.next($event); + this.resultFound.emit($event); + if (this.isEditRelationship ) { + const idOfItems = $event.page.map( itemSearchResult => { + return itemSearchResult.indexableObject.uuid; + }); + this.setSelectedIds(idOfItems, $event); + } + } } From b7c46ffe29b40280314afa34ff9b1849d6219d0d Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 14 Jan 2022 12:37:29 +0100 Subject: [PATCH 66/77] [CST-4633] Fix e2e test --- cypress/integration/search-page.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/search-page.spec.ts b/cypress/integration/search-page.spec.ts index a2bfbe6a5b..859c765d2e 100644 --- a/cypress/integration/search-page.spec.ts +++ b/cypress/integration/search-page.spec.ts @@ -53,7 +53,7 @@ describe('Search Page', () => { // Click to display grid view // TODO: These buttons should likely have an easier way to uniquely select - cy.get('#search-sidebar-content > ds-view-mode-switch > .btn-group > [href="/search?spc.sf=score&spc.sd=DESC&view=grid"] > .fas').click(); + cy.get('#search-sidebar-content > ds-view-mode-switch > .btn-group > [href="/search?view=grid"] > .fas').click(); // tag must be loaded cy.get('ds-search-page').should('exist'); From fd610dbf4d5db093cedce46f0a5d32342c5e36c1 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 20 Jan 2022 14:24:54 +0100 Subject: [PATCH 67/77] [CST-4880] Set 500 response status to internal server error page --- src/app/core/services/server-response.service.ts | 4 ++++ .../page-internal-server-error.component.ts | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/app/core/services/server-response.service.ts b/src/app/core/services/server-response.service.ts index df5662991d..02e00446bc 100644 --- a/src/app/core/services/server-response.service.ts +++ b/src/app/core/services/server-response.service.ts @@ -31,4 +31,8 @@ export class ServerResponseService { setNotFound(message = 'Not found'): this { return this.setStatus(404, message); } + + setInternalServerError(message = 'Internal Server Error'): this { + return this.setStatus(500, message); + } } diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts index 09b441969a..7ecb0a7609 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.ts +++ b/src/app/page-internal-server-error/page-internal-server-error.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ServerResponseService } from '../core/services/server-response.service'; /** - * This component representing the `PageNotFound` DSpace page. + * This component representing the `PageInternalServer` DSpace page. */ @Component({ selector: 'ds-page-internal-server-error', @@ -10,4 +11,13 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; changeDetection: ChangeDetectionStrategy.Default }) export class PageInternalServerErrorComponent { + + /** + * Initialize instance variables + * + * @param {ServerResponseService} responseService + */ + constructor(private responseService: ServerResponseService) { + this.responseService.setInternalServerError(); + } } From 98bdc59c2869480629e3f58cf2068760363ddc24 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 20 Jan 2022 14:26:04 +0100 Subject: [PATCH 68/77] [CST-4880] use getPageInternalServerErrorRoute function to determinate 500 page route --- src/app/root/root.component.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index b70573e42b..c0ccc712e9 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -1,5 +1,5 @@ import { map } from 'rxjs/operators'; -import { Component, Inject, OnInit, Input } from '@angular/core'; +import { Component, Inject, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs'; @@ -19,6 +19,7 @@ import { ThemeConfig } from '../../config/theme.model'; import { Angulartics2DSpace } from '../statistics/angulartics/dspace-provider'; import { environment } from '../../environments/environment'; import { slideSidebarPadding } from '../shared/animations/slide'; +import { getPageInternalServerErrorRoute } from '../app-routing-paths'; @Component({ selector: 'ds-root', @@ -67,12 +68,12 @@ export class RootComponent implements OnInit { this.totalSidebarWidth = this.cssService.getVariable('totalSidebarWidth'); const sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN); - this.slideSidebarOver = combineLatestObservable(sidebarCollapsed, this.windowService.isXsOrSm()) + this.slideSidebarOver = combineLatestObservable([sidebarCollapsed, this.windowService.isXsOrSm()]) .pipe( map(([collapsed, mobile]) => collapsed || mobile) ); - if (this.router.url === '/500') { + if (this.router.url === getPageInternalServerErrorRoute()) { this.shouldShowRouteLoader = false; } } From 016bf4b368cf0165d5a0a6bfb201be894e04fb63 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 20 Jan 2022 18:08:57 +0100 Subject: [PATCH 69/77] [CST-4633] Add flag to hide view mode switcher --- .../dynamic-lookup-relation-search-tab.component.html | 1 + src/app/shared/search/search.component.html | 2 ++ src/app/shared/search/search.component.ts | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html index 08d5198f08..54ac149d48 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html @@ -7,6 +7,7 @@ [searchFormPlaceholder]="'submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder'" [selectable]="true" [selectionConfig]="{ repeatable: repeatable, listId: listId }" + [showViewModes]="false" (resultFound)="onResultFound($event)" (deselectObject)="deselectObject.emit($event)" (selectObject)="selectObject.emit($event)"> diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index d1aa1390db..5ca3e925a5 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -54,6 +54,7 @@ [currentSortOption]="(currentSortOptions$ | async)" [inPlaceSearch]="inPlaceSearch" [viewModeList]="viewModeList" + [showViewModes]="showViewModes" (changeConfiguration)="changeContext($event.context)" (changeViewMode)="changeViewMode()"> diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index feebb90d03..c017a5065b 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -119,6 +119,11 @@ export class SearchComponent implements OnInit { */ @Input() showSidebar = true; + /** + * Whether to show the view mode switch + */ + @Input() showViewModes = true; + /** * List of available view mode */ From a95bf63ad0d2643a12f92c128aea458f50249d1a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 20 Jan 2022 18:14:29 +0100 Subject: [PATCH 70/77] [CST-4633] Fix issue with already selected relationship in the dynamic-lookup-relation-search-tab.component --- .../dynamic-lookup-relation-search-tab.component.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts index 5a6b07fd44..f70f073743 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts @@ -234,7 +234,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest * @param idOfItems the uuid of items that are being checked * @param resultListOfItems the list of results of the items */ - setSelectedIds(idOfItems, resultListOfItems) { + setSelectedIds(idOfItems: string[], resultListOfItems: SearchResult[]) { let relationType = this.relationshipType.rightwardType; if ( this.isLeft ) { relationType = this.relationshipType.leftwardType; @@ -254,7 +254,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest } const uuid = arrUrl[ arrUrl.length - 1 ]; - return this.getRelatedItem(uuid,resultListOfItems); + return this.getRelatedItem(uuid, resultListOfItems); }); selectableObject = selectableObject.filter( (selObject) => { @@ -274,11 +274,11 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest this.allSelected = false; this.selection$ .pipe(take(1)) - .subscribe((selection: SearchResult[]) => this.deselectObject.emit(...selection)); + .subscribe((selection: SearchResult[]) => this.deselectObject.emit(...selection)); this.selectableListService.deselectAll(this.listId); } - getRelatedItem(uuid: string, resultList: SearchResult[]) { + getRelatedItem(uuid: string, resultList: SearchResult[]) { return resultList.find( (resultItem) => { return resultItem.indexableObject.uuid === uuid; }); @@ -295,14 +295,13 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest } onResultFound($event: SearchObjects) { - console.log($event); this.resultsRD$.next($event); this.resultFound.emit($event); if (this.isEditRelationship ) { const idOfItems = $event.page.map( itemSearchResult => { return itemSearchResult.indexableObject.uuid; }); - this.setSelectedIds(idOfItems, $event); + this.setSelectedIds(idOfItems, $event.page); } } } From bcb96c522c3086349ed0eda8888dcc201aa2a16e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 20 Jan 2022 14:08:22 -0600 Subject: [PATCH 71/77] Environment variables must be strings or numbers, not booleans --- docker/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index adeb61dfc6..1387b1de39 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -16,11 +16,11 @@ services: dspace-angular: container_name: dspace-angular environment: - DSPACE_UI_SSL: false + DSPACE_UI_SSL: 'false' DSPACE_UI_HOST: dspace-angular DSPACE_UI_PORT: '4000' DSPACE_UI_NAMESPACE: / - DSPACE_REST_SSL: false + DSPACE_REST_SSL: 'false' DSPACE_REST_HOST: localhost DSPACE_REST_PORT: 8080 DSPACE_REST_NAMESPACE: /server From e61de0682f47315c1a2298af6f55df82ae6f8e70 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 21 Jan 2022 11:50:08 -0600 Subject: [PATCH 72/77] Revert "Show an error page if the rest api is not available" --- src/app/app-routing-paths.ts | 6 -- src/app/app-routing.module.ts | 39 ++++------- src/app/app.module.ts | 6 +- src/app/core/data/root-data.service.ts | 7 -- .../server-check/server-check.guard.spec.ts | 68 ------------------- .../core/server-check/server-check.guard.ts | 46 ------------- .../core/services/server-response.service.ts | 4 -- .../page-internal-server-error.component.html | 10 --- .../page-internal-server-error.component.scss | 0 .../page-internal-server-error.component.ts | 23 ------- ...ed-page-internal-server-error.component.ts | 26 ------- src/app/root/root.component.ts | 9 +-- src/assets/i18n/en.json5 | 5 -- 13 files changed, 15 insertions(+), 234 deletions(-) delete mode 100644 src/app/core/server-check/server-check.guard.spec.ts delete mode 100644 src/app/core/server-check/server-check.guard.ts delete mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.html delete mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.scss delete mode 100644 src/app/page-internal-server-error/page-internal-server-error.component.ts delete mode 100644 src/app/page-internal-server-error/themed-page-internal-server-error.component.ts diff --git a/src/app/app-routing-paths.ts b/src/app/app-routing-paths.ts index d9c3410931..db6b22a023 100644 --- a/src/app/app-routing-paths.ts +++ b/src/app/app-routing-paths.ts @@ -89,12 +89,6 @@ export function getPageNotFoundRoute() { return `/${PAGE_NOT_FOUND_PATH}`; } -export const INTERNAL_SERVER_ERROR = '500'; - -export function getPageInternalServerErrorRoute() { - return `/${INTERNAL_SERVER_ERROR}`; -} - export const INFO_MODULE_PATH = 'info'; export function getInfoModulePath() { return `/${INFO_MODULE_PATH}`; diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 88f7791b1b..04d2c55bdd 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -11,12 +11,10 @@ import { FORBIDDEN_PATH, FORGOT_PASSWORD_PATH, INFO_MODULE_PATH, - INTERNAL_SERVER_ERROR, - LEGACY_BITSTREAM_MODULE_PATH, PROFILE_MODULE_PATH, REGISTER_PATH, - REQUEST_COPY_MODULE_PATH, WORKFLOW_ITEM_MODULE_PATH, + LEGACY_BITSTREAM_MODULE_PATH, REQUEST_COPY_MODULE_PATH, } from './app-routing-paths'; import { COLLECTION_MODULE_PATH } from './collection-page/collection-page-routing-paths'; import { COMMUNITY_MODULE_PATH } from './community-page/community-page-routing-paths'; @@ -28,25 +26,14 @@ import { SiteRegisterGuard } from './core/data/feature-authorization/feature-aut import { ThemedPageNotFoundComponent } from './pagenotfound/themed-pagenotfound.component'; import { ThemedForbiddenComponent } from './forbidden/themed-forbidden.component'; import { GroupAdministratorGuard } from './core/data/feature-authorization/feature-authorization-guard/group-administrator.guard'; -import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component'; -import { ServerCheckGuard } from './core/server-check/server-check.guard'; @NgModule({ imports: [ - RouterModule.forRoot([ - { path: INTERNAL_SERVER_ERROR, component: ThemedPageInternalServerErrorComponent }, - { - path: '', - canActivate: [AuthBlockingGuard], - canActivateChild: [ServerCheckGuard], + RouterModule.forRoot([{ + path: '', canActivate: [AuthBlockingGuard], children: [ { path: '', redirectTo: '/home', pathMatch: 'full' }, - { - path: 'reload/:rnd', - component: ThemedPageNotFoundComponent, - pathMatch: 'full', - canActivate: [ReloadGuard] - }, + { path: 'reload/:rnd', component: ThemedPageNotFoundComponent, pathMatch: 'full', canActivate: [ReloadGuard] }, { path: 'home', loadChildren: () => import('./home-page/home-page.module') @@ -102,8 +89,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; .then((m) => m.ItemPageModule), canActivate: [EndUserAgreementCurrentUserGuard] }, - { - path: 'entities/:entity-type', + { path: 'entities/:entity-type', loadChildren: () => import('./item-page/item-page.module') .then((m) => m.ItemPageModule), canActivate: [EndUserAgreementCurrentUserGuard] @@ -147,12 +133,12 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; { path: 'login', loadChildren: () => import('./login-page/login-page.module') - .then((m) => m.LoginPageModule) + .then((m) => m.LoginPageModule), }, { path: 'logout', loadChildren: () => import('./logout-page/logout-page.module') - .then((m) => m.LogoutPageModule) + .then((m) => m.LogoutPageModule), }, { path: 'submit', @@ -192,7 +178,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; }, { path: INFO_MODULE_PATH, - loadChildren: () => import('./info/info.module').then((m) => m.InfoModule) + loadChildren: () => import('./info/info.module').then((m) => m.InfoModule), }, { path: REQUEST_COPY_MODULE_PATH, @@ -206,7 +192,7 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; { path: 'statistics', loadChildren: () => import('./statistics-page/statistics-page-routing.module') - .then((m) => m.StatisticsPageRoutingModule) + .then((m) => m.StatisticsPageRoutingModule), }, { path: ACCESS_CONTROL_MODULE_PATH, @@ -214,10 +200,9 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard'; canActivate: [GroupAdministratorGuard], }, { path: '**', pathMatch: 'full', component: ThemedPageNotFoundComponent }, - ] - } - ], { - onSameUrlNavigation: 'reload', + ]} + ],{ + onSameUrlNavigation: 'reload', }) ], exports: [RouterModule], diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ceda63e7ec..32c3c78348 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -54,8 +54,6 @@ import { ThemedFooterComponent } from './footer/themed-footer.component'; import { ThemedBreadcrumbsComponent } from './breadcrumbs/themed-breadcrumbs.component'; import { ThemedHeaderNavbarWrapperComponent } from './header-nav-wrapper/themed-header-navbar-wrapper.component'; import { IdleModalComponent } from './shared/idle-modal/idle-modal.component'; -import { ThemedPageInternalServerErrorComponent } from './page-internal-server-error/themed-page-internal-server-error.component'; -import { PageInternalServerErrorComponent } from './page-internal-server-error/page-internal-server-error.component'; import { AppConfig, APP_CONFIG } from '../config/app-config.interface'; @@ -183,9 +181,7 @@ const DECLARATIONS = [ ThemedBreadcrumbsComponent, ForbiddenComponent, ThemedForbiddenComponent, - IdleModalComponent, - ThemedPageInternalServerErrorComponent, - PageInternalServerErrorComponent + IdleModalComponent ]; const EXPORTS = [ diff --git a/src/app/core/data/root-data.service.ts b/src/app/core/data/root-data.service.ts index ce1b33a9e3..8b4e836671 100644 --- a/src/app/core/data/root-data.service.ts +++ b/src/app/core/data/root-data.service.ts @@ -106,12 +106,5 @@ export class RootDataService { findAllByHref(href: string | Observable, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.dataService.findAllByHref(href, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } - - /** - * Set to sale the root endpoint cache hit - */ - invalidateRootCache() { - this.requestService.setStaleByHrefSubstring('server/api'); - } } /* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts deleted file mode 100644 index 30d07234a3..0000000000 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ServerCheckGuard } from './server-check.guard'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; -import { take } from 'rxjs/operators'; -import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; -import { Router } from '@angular/router'; -import { RootDataService } from '../data/root-data.service'; -import { Root } from '../data/root.model'; -import SpyObj = jasmine.SpyObj; - -describe('ServerCheckGuard', () => { - let guard: ServerCheckGuard; - let router: SpyObj; - let rootDataServiceStub: SpyObj; - - rootDataServiceStub = jasmine.createSpyObj('RootDataService', { - findRoot: jasmine.createSpy('findRoot'), - invalidateRootCache: jasmine.createSpy('invalidateRootCache') - }); - router = jasmine.createSpyObj('Router', { - navigateByUrl: jasmine.createSpy('navigateByUrl') - }); - - beforeEach(() => { - guard = new ServerCheckGuard(router, rootDataServiceStub); - }); - - afterEach(() => { - router.navigateByUrl.calls.reset(); - rootDataServiceStub.invalidateRootCache.calls.reset(); - rootDataServiceStub.findRoot.calls.reset(); - }); - - it('should be created', () => { - expect(guard).toBeTruthy(); - }); - - describe('when root endpoint has succeeded', () => { - beforeEach(() => { - rootDataServiceStub.findRoot.and.returnValue(createSuccessfulRemoteDataObject$({} as any)); - }); - - it('should not redirect to error page', () => { - guard.canActivateChild({} as any, {} as any).pipe( - take(1) - ).subscribe((canActivate: boolean) => { - expect(canActivate).toEqual(true); - expect(rootDataServiceStub.invalidateRootCache).not.toHaveBeenCalled(); - expect(router.navigateByUrl).not.toHaveBeenCalled(); - }); - }); - }); - - describe('when root endpoint has not succeeded', () => { - beforeEach(() => { - rootDataServiceStub.findRoot.and.returnValue(createFailedRemoteDataObject$()); - }); - - it('should redirect to error page', () => { - guard.canActivateChild({} as any, {} as any).pipe( - take(1) - ).subscribe((canActivate: boolean) => { - expect(canActivate).toEqual(false); - expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalled(); - expect(router.navigateByUrl).toHaveBeenCalledWith(getPageInternalServerErrorRoute()); - }); - }); - }); -}); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts deleted file mode 100644 index 7c3329f51d..0000000000 --- a/src/app/core/server-check/server-check.guard.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; - -import { interval, Observable, race } from 'rxjs'; -import { map, mergeMapTo, tap } from 'rxjs/operators'; - -import { RootDataService } from '../data/root-data.service'; -import { RemoteData } from '../data/remote-data'; -import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; -import { getFirstCompletedRemoteData } from '../shared/operators'; - -@Injectable({ - providedIn: 'root' -}) -/** - * A guard that checks if root api endpoint is reachable. - * If not redirect to 500 error page - */ -export class ServerCheckGuard implements CanActivateChild { - constructor(private router: Router, private rootDataService: RootDataService) { - } - - /** - * True when root api endpoint is reachable. - */ - canActivateChild( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot): Observable { - - const uncachedCheck$ = this.rootDataService.findRoot(false); - // fallback observable used if the uncached one hangs and doesn't emit value - const cachedCheck$ = interval(200).pipe(mergeMapTo((this.rootDataService.findRoot()))); - - return race([uncachedCheck$, cachedCheck$]).pipe( - getFirstCompletedRemoteData(), - map((res: RemoteData) => res.hasSucceeded), - tap((hasSucceeded: boolean) => { - if (!hasSucceeded) { - this.rootDataService.invalidateRootCache(); - this.router.navigateByUrl(getPageInternalServerErrorRoute()); - } - }), - ); - - } -} diff --git a/src/app/core/services/server-response.service.ts b/src/app/core/services/server-response.service.ts index 02e00446bc..df5662991d 100644 --- a/src/app/core/services/server-response.service.ts +++ b/src/app/core/services/server-response.service.ts @@ -31,8 +31,4 @@ export class ServerResponseService { setNotFound(message = 'Not found'): this { return this.setStatus(404, message); } - - setInternalServerError(message = 'Internal Server Error'): this { - return this.setStatus(500, message); - } } diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.html b/src/app/page-internal-server-error/page-internal-server-error.component.html deleted file mode 100644 index 09b499b496..0000000000 --- a/src/app/page-internal-server-error/page-internal-server-error.component.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.scss b/src/app/page-internal-server-error/page-internal-server-error.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts deleted file mode 100644 index 7ecb0a7609..0000000000 --- a/src/app/page-internal-server-error/page-internal-server-error.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { ServerResponseService } from '../core/services/server-response.service'; - -/** - * This component representing the `PageInternalServer` DSpace page. - */ -@Component({ - selector: 'ds-page-internal-server-error', - styleUrls: ['./page-internal-server-error.component.scss'], - templateUrl: './page-internal-server-error.component.html', - changeDetection: ChangeDetectionStrategy.Default -}) -export class PageInternalServerErrorComponent { - - /** - * Initialize instance variables - * - * @param {ServerResponseService} responseService - */ - constructor(private responseService: ServerResponseService) { - this.responseService.setInternalServerError(); - } -} diff --git a/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts b/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts deleted file mode 100644 index e8792c4789..0000000000 --- a/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component } from '@angular/core'; -import { ThemedComponent } from '../shared/theme-support/themed.component'; -import { PageInternalServerErrorComponent } from './page-internal-server-error.component'; - -/** - * Themed wrapper for PageInternalServerErrorComponent - */ -@Component({ - selector: 'ds-themed-search-page', - styleUrls: [], - templateUrl: '../shared/theme-support/themed.component.html', -}) -export class ThemedPageInternalServerErrorComponent extends ThemedComponent { - - protected getComponentName(): string { - return 'PageInternalServerErrorComponent'; - } - - protected importThemedComponent(themeName: string): Promise { - return import(`../../themes/${themeName}/app/page-internal-server-error/page-internal-server-error.component`); - } - - protected importUnthemedComponent(): Promise { - return import(`./page-internal-server-error.component`); - } -} diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index dc44095573..6ba859ef23 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -1,5 +1,5 @@ import { map } from 'rxjs/operators'; -import { Component, Inject, Input, OnInit } from '@angular/core'; +import { Component, Inject, OnInit, Input } from '@angular/core'; import { Router } from '@angular/router'; import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs'; @@ -19,7 +19,6 @@ import { ThemeConfig } from '../../config/theme.model'; import { Angulartics2DSpace } from '../statistics/angulartics/dspace-provider'; import { environment } from '../../environments/environment'; import { slideSidebarPadding } from '../shared/animations/slide'; -import { getPageInternalServerErrorRoute } from '../app-routing-paths'; @Component({ selector: 'ds-root', @@ -69,13 +68,9 @@ export class RootComponent implements OnInit { this.totalSidebarWidth = this.cssService.getVariable('totalSidebarWidth'); const sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN); - this.slideSidebarOver = combineLatestObservable([sidebarCollapsed, this.windowService.isXsOrSm()]) + this.slideSidebarOver = combineLatestObservable(sidebarCollapsed, this.windowService.isXsOrSm()) .pipe( map(([collapsed, mobile]) => collapsed || mobile) ); - - if (this.router.url === getPageInternalServerErrorRoute()) { - this.shouldShowRouteLoader = false; - } } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index f82835401d..6b47238f5b 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -14,11 +14,6 @@ "403.forbidden": "forbidden", - "500.page-internal-server-error": "Service Unavailable", - - "500.help": "The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.", - - "500.link.home-page": "Take me to the home page", "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", From c34f75b4430126e0c2f97f4fe2f335db95661843 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Mon, 24 Jan 2022 09:27:19 +0100 Subject: [PATCH 73/77] replace href="#" with href="javascript:void(0);" everywhere --- .../org-unit-input-suggestions.component.html | 2 +- .../person-input-suggestions.component.html | 2 +- src/app/footer/footer.component.html | 2 +- .../field-components/collections/collections.component.html | 2 +- .../expandable-navbar-section.component.html | 2 +- src/app/shared/auth-nav-menu/auth-nav-menu.component.html | 4 ++-- src/app/shared/chips/chips.component.html | 2 +- .../filter-input-suggestions.component.html | 2 +- .../shared/input-suggestions/input-suggestions.component.html | 4 ++-- .../validation-suggestions.component.html | 2 +- src/app/shared/lang-switch/lang-switch.component.html | 2 +- .../sections/container/section-container.component.html | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html index 87a422e7db..c4e31d3d81 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html @@ -15,7 +15,7 @@