From ae6b183faec9cda0d2932143a52e14ef94bd945c Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 14 Jun 2023 18:51:42 +0200 Subject: [PATCH 01/71] 103236: fix issue where setStaleByHrefSubtring wouldn't emit after all requests were stale --- src/app/core/data/request.service.ts | 36 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index 2d5acb2cb3d..3b7ee80ffb0 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; import { HttpHeaders } from '@angular/common/http'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { filter, map, take, tap } from 'rxjs/operators'; +import { Observable, from as observableFrom } from 'rxjs'; +import { filter, find, map, mergeMap, switchMap, take, tap, toArray } from 'rxjs/operators'; import { cloneDeep } from 'lodash'; import { hasValue, isEmpty, isNotEmpty, hasNoValue } from '../../shared/empty.util'; import { ObjectCacheEntry } from '../cache/object-cache.reducer'; @@ -292,22 +292,42 @@ export class RequestService { * Set all requests that match (part of) the href to stale * * @param href A substring of the request(s) href - * @return Returns an observable emitting whether or not the cache is removed + * @return Returns an observable emitting when those requests are all stale */ setStaleByHrefSubstring(href: string): Observable { - this.store.pipe( + const requestUUIDs$ = this.store.pipe( select(uuidsFromHrefSubstringSelector(requestIndexSelector, href)), take(1) - ).subscribe((uuids: string[]) => { + ); + requestUUIDs$.subscribe((uuids: string[]) => { for (const uuid of uuids) { this.store.dispatch(new RequestStaleAction(uuid)); } }); this.requestsOnTheirWayToTheStore = this.requestsOnTheirWayToTheStore.filter((reqHref: string) => reqHref.indexOf(href) < 0); - return this.store.pipe( - select(uuidsFromHrefSubstringSelector(requestIndexSelector, href)), - map((uuids) => isEmpty(uuids)) + // emit true after all requests are stale + return requestUUIDs$.pipe( + switchMap((uuids: string[]) => { + if (isEmpty(uuids)) { + // if there were no matching requests, emit true immediately + return [true]; + } else { + // otherwise emit all request uuids in order + return observableFrom(uuids).pipe( + // retrieve the RequestEntry for each uuid + mergeMap((uuid: string) => this.getByUUID(uuid)), + // check whether it is undefined or stale + map((request: RequestEntry) => hasNoValue(request) || isStale(request.state)), + // if it is, complete + find((stale: boolean) => stale === true), + // after all observables above are completed, emit them as a single array + toArray(), + // when the array comes in, emit true + map(() => true) + ); + } + }) ); } From 02a20c8862ca4d93919ca07e900d70a722ebbb5d Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 30 Jun 2023 16:56:37 +0200 Subject: [PATCH 02/71] 103236: Added tests for setStaleByHrefSubstring --- src/app/core/data/request.service.spec.ts | 46 ++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index fe35d840d7d..4493c61a69c 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -1,6 +1,6 @@ import { Store, StoreModule } from '@ngrx/store'; import { cold, getTestScheduler } from 'jasmine-marbles'; -import { EMPTY, of as observableOf } from 'rxjs'; +import { EMPTY, Observable, of as observableOf } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { getMockObjectCacheService } from '../../shared/mocks/object-cache.service.mock'; @@ -625,4 +625,48 @@ describe('RequestService', () => { expect(done$).toBeObservable(cold('-----(t|)', { t: true })); })); }); + + describe('setStaleByHrefSubstring', () => { + let dispatchSpy: jasmine.Spy; + let getByUUIDSpy: jasmine.Spy; + + beforeEach(() => { + dispatchSpy = spyOn(store, 'dispatch'); + getByUUIDSpy = spyOn(service, 'getByUUID').and.callThrough(); + }); + + describe('with an empty/no matching requests in the state', () => { + it('should return true', () => { + const done$: Observable = service.setStaleByHrefSubstring('https://rest.api/endpoint/selfLink'); + expect(done$).toBeObservable(cold('(a|)', { a: true })); + }); + }); + + describe('with a matching request in the state', () => { + beforeEach(() => { + const state = Object.assign({}, initialState, { + core: Object.assign({}, initialState.core, { + 'index': { + 'get-request/href-to-uuid': { + 'https://rest.api/endpoint/selfLink': '5f2a0d2a-effa-4d54-bd54-5663b960f9eb' + } + } + }) + }); + mockStore.setState(state); + }); + + it('should return an Observable that emits true as soon as the request is stale', () => { + dispatchSpy.and.callFake(() => { /* empty */ }); // don't actually set as stale + getByUUIDSpy.and.returnValue(cold('a-b--c--d-', { // but fake the state in the cache + a: { state: RequestEntryState.ResponsePending }, + b: { state: RequestEntryState.Success }, + c: { state: RequestEntryState.SuccessStale }, + d: { state: RequestEntryState.Error }, + })); + const done$: Observable = service.setStaleByHrefSubstring('https://rest.api/endpoint/selfLink'); + expect(done$).toBeObservable(cold('-----(a|)', { a: true })); + }); + }); + }); }); From b5a70e8f95d1046bed0e33d5b0bdc8109d645676 Mon Sep 17 00:00:00 2001 From: Nona Luypaert Date: Sat, 8 Jul 2023 00:20:30 +0200 Subject: [PATCH 03/71] Fix VocabularyTreeview not updating + i18n for nsi --- .../vocabulary-treeview/vocabulary-treeview.component.ts | 9 +++++++-- src/assets/i18n/en.json5 | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts index 017416e8c25..13d4495e614 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts @@ -1,5 +1,5 @@ import { FlatTreeControl } from '@angular/cdk/tree'; -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, OnChanges, SimpleChanges } from '@angular/core'; import { map } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; @@ -28,7 +28,7 @@ import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operato templateUrl: './vocabulary-treeview.component.html', styleUrls: ['./vocabulary-treeview.component.scss'] }) -export class VocabularyTreeviewComponent implements OnDestroy, OnInit { +export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges { /** * The {@link VocabularyOptions} object @@ -322,4 +322,9 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit { private getEntryId(entry: VocabularyEntry): string { return entry.authority || entry.otherInformation.id || undefined; } + + ngOnChanges(changes: SimpleChanges): void { + this.reset(); + this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.selectedItems, null); + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..ee594a9cb29 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -782,6 +782,8 @@ "browse.comcol.by.srsc": "By Subject Category", + "browse.comcol.by.nsi": "By Norwegian Science Index", + "browse.comcol.by.title": "By Title", "browse.comcol.head": "Browse", @@ -804,6 +806,8 @@ "browse.metadata.srsc.breadcrumbs": "Browse by Subject Category", + "browse.metadata.nsi.breadcrumbs": "Browse by Norwegian Science Index", + "browse.metadata.title.breadcrumbs": "Browse by Title", "pagination.next.button": "Next", @@ -2826,6 +2830,8 @@ "menu.section.browse_global_by_srsc": "By Subject Category", + "menu.section.browse_global_by_nsi": "By Norwegian Science Index", + "menu.section.browse_global_by_title": "By Title", "menu.section.browse_global_communities_and_collections": "Communities & Collections", From 23aefb7385a987c5cb3f3eb169b37037f032a126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:29:14 +0200 Subject: [PATCH 04/71] Added themed-user-menu component. --- .../user-menu/themed-user-menu.component.ts | 33 +++++++++++++++++++ src/app/shared/shared.module.ts | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts diff --git a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts new file mode 100644 index 00000000000..09f02eb761c --- /dev/null +++ b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts @@ -0,0 +1,33 @@ +import {Component, Input} from '@angular/core' +import {ThemedComponent} from '../../theme-support/themed.component'; +import {UserMenuComponent} from './user-menu.component'; + +/** + * This component represents the user nav menu. + */ +@Component({ + selector: 'ds-themed-user-menu', + templateUrl: './../../theme-support/themed.component.html', + styleUrls: [] +}) +export class ThemedUserMenuComponent extends ThemedComponent{ + + /** + * The input flag to show user details in navbar expandable menu + */ + @Input() inExpandableNavbar = false; + + protected inAndOutputNames: (keyof UserMenuComponent & keyof this)[] = ['inExpandableNavbar']; + + protected getComponentName(): string { + return 'UserMenuComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import((`../../../../themes/${themeName}/app/shared/auth-nav-menu/user-menu/user-menu.component`)); + } + + protected importUnthemedComponent(): Promise { + return import('./user-menu.component'); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9b..91175736baf 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -284,6 +284,7 @@ import { } from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component'; import { NgxPaginationModule } from 'ngx-pagination'; +import {ThemedUserMenuComponent} from './auth-nav-menu/user-menu/themed-user-menu.component'; const MODULES = [ CommonModule, @@ -332,6 +333,7 @@ const COMPONENTS = [ AuthNavMenuComponent, ThemedAuthNavMenuComponent, UserMenuComponent, + ThemedUserMenuComponent, DsSelectComponent, ErrorComponent, LangSwitchComponent, From 63582cfa0d40497b73f39088aaf949f41571e5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:34:25 +0200 Subject: [PATCH 05/71] Corrected missing semicolon. --- .../auth-nav-menu/user-menu/themed-user-menu.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts index 09f02eb761c..cecafc9d5cd 100644 --- a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts +++ b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core' +import {Component, Input} from '@angular/core'; import {ThemedComponent} from '../../theme-support/themed.component'; import {UserMenuComponent} from './user-menu.component'; From ed84f4513225d3fdef45edcafd2d434271b5f4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:38:32 +0200 Subject: [PATCH 06/71] Replaced tags for ds-user-menu. --- src/app/navbar/navbar.component.html | 2 +- src/app/shared/auth-nav-menu/auth-nav-menu.component.html | 2 +- src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index bc1e04f5130..8608ee7b02d 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -6,7 +6,7 @@
diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts index 58a1edfabde..0b9ea6ef4b4 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts @@ -248,7 +248,7 @@ describe('AuthNavMenuComponent', () => { component = null; }); it('should render UserMenuComponent component', () => { - const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-user-menu')); + const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-themed-user-menu')); expect(logoutDropdownMenu.nativeElement).toBeDefined(); }); }); From e3f57dae44de6f58e1ba2bf91d0de092b9416f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:54:09 +0200 Subject: [PATCH 07/71] Included user-menu component in custom theme. --- .../user-menu/user-menu.component.html | 0 .../user-menu/user-menu.component.scss | 0 .../user-menu/user-menu.component.ts | 15 +++++++++++++++ src/themes/custom/lazy-theme.module.ts | 2 ++ 4 files changed, 17 insertions(+) create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts new file mode 100644 index 00000000000..f9f1db65ee6 --- /dev/null +++ b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { UserMenuComponent as BaseComponent } from '../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component'; + +/** + * Component representing the {@link UserMenuComponent} of a page + */ +@Component({ + selector: 'ds-user-menu', + // templateUrl: 'user-menu.component.html', + templateUrl: '../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component.html', + // styleUrls: ['user-menu.component.scss'], + styleUrls: ['../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component.scss'], +}) +export class UserMenuComponent extends BaseComponent { +} diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index edb3f5478c9..937e174b7f8 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -156,6 +156,7 @@ import { ItemStatusComponent } from './app/item-page/edit-item-page/item-status/ import { EditBitstreamPageComponent } from './app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component'; import { FormModule } from '../../app/shared/form/form.module'; import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; +import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; const DECLARATIONS = [ FileSectionComponent, @@ -239,6 +240,7 @@ const DECLARATIONS = [ SubmissionSectionUploadFileComponent, ItemStatusComponent, EditBitstreamPageComponent, + UserMenuComponent, ]; @NgModule({ From cac1407f08290adbc1a827fb1769011d3ecba803 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 12 Jul 2023 15:11:38 +0200 Subject: [PATCH 08/71] 104189: Allow CSV export on related entity search --- .../related-entities-search.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 2a08efeb2ca..36340bebfa0 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 @@ -2,5 +2,6 @@ [fixedFilterQuery]="fixedFilter" [configuration]="configuration" [searchEnabled]="searchEnabled" - [sideBarWidth]="sideBarWidth"> + [sideBarWidth]="sideBarWidth" + [showCsvExport]="true"> From 45ad5f73168ccdf3d4f7ab617d44a0e28c94545a Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 12 Jul 2023 16:32:56 +0200 Subject: [PATCH 09/71] 104189: CSV export add fixedFilter --- .../search-export-csv.component.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app/shared/search/search-export-csv/search-export-csv.component.ts b/src/app/shared/search/search-export-csv/search-export-csv.component.ts index 6ad105342f6..1997a663a13 100644 --- a/src/app/shared/search/search-export-csv/search-export-csv.component.ts +++ b/src/app/shared/search/search-export-csv/search-export-csv.component.ts @@ -94,6 +94,19 @@ export class SearchExportCsvComponent implements OnInit { } }); } + if (isNotEmpty(this.searchConfig.fixedFilter)) { + const fixedFilter = this.searchConfig.fixedFilter.substring(2); + const keyAndValue = fixedFilter.split('='); + if (keyAndValue.length > 1) { + const key = keyAndValue[0]; + const valueAndOperator = keyAndValue[1].split(','); + if (valueAndOperator.length > 1) { + const value = valueAndOperator[0]; + const operator = valueAndOperator[1]; + parameters.push({name: '-f', value: `${key},${operator}=${value}`}); + } + } + } } this.scriptDataService.invoke('metadata-export-search', parameters, []).pipe( From 648925f3e1c0a51fc3eb61b7257e7a44ea57fee6 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 19 Jul 2023 14:01:41 +0200 Subject: [PATCH 10/71] 104312: DsDynamicLookupRelationExternalSourceTabComponent should have the form value already filled in the search input --- .../dynamic-lookup-relation-modal.component.html | 1 + ...ookup-relation-external-source-tab.component.ts | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html index f95cd98c656..4c635b931f0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html @@ -42,6 +42,7 @@