From 2b17bb8f1e5ebdb1c1bcb49beffcab7ff265133f Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 7 Apr 2022 11:29:22 +0200 Subject: [PATCH 001/103] 89676: Themeable browse-by-page decorator & search-results component --- .../browse-by-switcher/browse-by-decorator.ts | 27 ++++++-- .../browse-by-switcher.component.ts | 6 +- .../themed-search-results.component.ts | 64 +++++++++++++++++++ src/app/shared/search/search.component.html | 4 +- src/app/shared/search/search.module.ts | 4 +- 5 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 src/app/shared/search/search-results/themed-search-results.component.ts diff --git a/src/app/browse-by/browse-by-switcher/browse-by-decorator.ts b/src/app/browse-by/browse-by-switcher/browse-by-decorator.ts index 1ebaa7face..ceb4c6a6c6 100644 --- a/src/app/browse-by/browse-by-switcher/browse-by-decorator.ts +++ b/src/app/browse-by/browse-by-switcher/browse-by-decorator.ts @@ -1,6 +1,10 @@ import { hasNoValue } from '../../shared/empty.util'; import { InjectionToken } from '@angular/core'; import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { + DEFAULT_THEME, + resolveTheme +} from '../../shared/object-collection/shared/listable-object/listable-object.decorator'; export enum BrowseByDataType { Title = 'title', @@ -10,7 +14,7 @@ export enum BrowseByDataType { export const DEFAULT_BROWSE_BY_TYPE = BrowseByDataType.Metadata; -export const BROWSE_BY_COMPONENT_FACTORY = new InjectionToken<(browseByType) => GenericConstructor>('getComponentByBrowseByType', { +export const BROWSE_BY_COMPONENT_FACTORY = new InjectionToken<(browseByType, theme) => GenericConstructor>('getComponentByBrowseByType', { providedIn: 'root', factory: () => getComponentByBrowseByType }); @@ -20,13 +24,17 @@ const map = new Map(); /** * Decorator used for rendering Browse-By pages by type * @param browseByType The type of page + * @param theme The optional theme for the component */ -export function rendersBrowseBy(browseByType: BrowseByDataType) { +export function rendersBrowseBy(browseByType: BrowseByDataType, theme = DEFAULT_THEME) { return function decorator(component: any) { if (hasNoValue(map.get(browseByType))) { - map.set(browseByType, component); + map.set(browseByType, new Map()); + } + if (hasNoValue(map.get(browseByType).get(theme))) { + map.get(browseByType).set(theme, component); } else { - throw new Error(`There can't be more than one component to render Browse-By of type "${browseByType}"`); + throw new Error(`There can't be more than one component to render Browse-By of type "${browseByType}" and theme "${theme}"`); } }; } @@ -34,11 +42,16 @@ export function rendersBrowseBy(browseByType: BrowseByDataType) { /** * Get the component used for rendering a Browse-By page by type * @param browseByType The type of page + * @param theme the theme to match */ -export function getComponentByBrowseByType(browseByType) { - const comp = map.get(browseByType); +export function getComponentByBrowseByType(browseByType, theme) { + let themeMap = map.get(browseByType); + if (hasNoValue(themeMap)) { + themeMap = map.get(DEFAULT_BROWSE_BY_TYPE); + } + const comp = resolveTheme(themeMap, theme); if (hasNoValue(comp)) { - map.get(DEFAULT_BROWSE_BY_TYPE); + return themeMap.get(DEFAULT_THEME); } return comp; } diff --git a/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.ts b/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.ts index cf4c1d9856..0d3a35bebf 100644 --- a/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.ts +++ b/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.ts @@ -5,6 +5,7 @@ import { map } from 'rxjs/operators'; import { BROWSE_BY_COMPONENT_FACTORY } from './browse-by-decorator'; import { GenericConstructor } from '../../core/shared/generic-constructor'; import { BrowseDefinition } from '../../core/shared/browse-definition.model'; +import { ThemeService } from '../../shared/theme-support/theme.service'; @Component({ selector: 'ds-browse-by-switcher', @@ -21,7 +22,8 @@ export class BrowseBySwitcherComponent implements OnInit { browseByComponent: Observable; public constructor(protected route: ActivatedRoute, - @Inject(BROWSE_BY_COMPONENT_FACTORY) private getComponentByBrowseByType: (browseByType) => GenericConstructor) { + protected themeService: ThemeService, + @Inject(BROWSE_BY_COMPONENT_FACTORY) private getComponentByBrowseByType: (browseByType, theme) => GenericConstructor) { } /** @@ -29,7 +31,7 @@ export class BrowseBySwitcherComponent implements OnInit { */ ngOnInit(): void { this.browseByComponent = this.route.data.pipe( - map((data: { browseDefinition: BrowseDefinition }) => this.getComponentByBrowseByType(data.browseDefinition.dataType)) + map((data: { browseDefinition: BrowseDefinition }) => this.getComponentByBrowseByType(data.browseDefinition.dataType, this.themeService.getThemeName())) ); } diff --git a/src/app/shared/search/search-results/themed-search-results.component.ts b/src/app/shared/search/search-results/themed-search-results.component.ts new file mode 100644 index 0000000000..19a8fc55e8 --- /dev/null +++ b/src/app/shared/search/search-results/themed-search-results.component.ts @@ -0,0 +1,64 @@ +import { ThemedComponent } from '../../theme-support/themed.component'; +import { SearchResultsComponent, SelectionConfig } from './search-results.component'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { CollectionElementLinkType } from '../../object-collection/collection-element-link.type'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { SearchResult } from '../models/search-result.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +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'; +import { Context } from '../../../core/shared/context.model'; +import { ListableObject } from '../../object-collection/shared/listable-object.model'; + +/** + * Themed wrapper for SearchResultsComponent + */ +@Component({ + selector: 'ds-themed-search-results', + styleUrls: [], + templateUrl: '../../theme-support/themed.component.html', +}) +export class ThemedSearchResultsComponent extends ThemedComponent { + protected inAndOutputNames: (keyof SearchResultsComponent & keyof this)[] = ['linkType', 'searchResults', 'searchConfig', 'sortConfig', 'viewMode', 'configuration', 'disableHeader', 'selectable', 'context', 'hidePaginationDetail', 'selectionConfig', 'deselectObject', 'selectObject']; + + @Input() linkType: CollectionElementLinkType; + + @Input() searchResults: RemoteData>>; + + @Input() searchConfig: PaginatedSearchOptions; + + @Input() sortConfig: SortOptions; + + @Input() viewMode: ViewMode; + + @Input() configuration: string; + + @Input() disableHeader = false; + + @Input() selectable = false; + + @Input() context: Context; + + @Input() hidePaginationDetail = false; + + @Input() selectionConfig: SelectionConfig = null; + + @Output() deselectObject: EventEmitter = new EventEmitter(); + + @Output() selectObject: EventEmitter = new EventEmitter(); + + protected getComponentName(): string { + return 'SearchResultsComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../../../themes/${themeName}/app/shared/search/search-results/search-results.component`); + } + + protected importUnthemedComponent(): Promise { + return import('./search-results.component'); + } + +} diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index 5ca3e925a5..aac77b3570 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -29,7 +29,7 @@ | translate}} - + (selectObject)="selectObject.emit($event)"> diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts index 668d260c23..991fad409b 100644 --- a/src/app/shared/search/search.module.ts +++ b/src/app/shared/search/search.module.ts @@ -28,6 +28,7 @@ import { MissingTranslationHelper } from '../translate/missing-translation.helpe import { SharedModule } from '../shared.module'; import { SearchResultsComponent } from './search-results/search-results.component'; import { SearchComponent } from './search.component'; +import { ThemedSearchResultsComponent } from './search-results/themed-search-results.component'; const COMPONENTS = [ SearchComponent, @@ -50,7 +51,8 @@ const COMPONENTS = [ SearchAuthorityFilterComponent, SearchSwitchConfigurationComponent, ConfigurationSearchPageComponent, - ThemedConfigurationSearchPageComponent + ThemedConfigurationSearchPageComponent, + ThemedSearchResultsComponent, ]; const ENTRY_COMPONENTS = [ From 0ed7f2e0aa0d1b43f9ed82f5cadf8cc74c5b7cb6 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 8 Apr 2022 11:12:26 +0200 Subject: [PATCH 002/103] 89676: Test fixes --- .../browse-by-switcher.component.spec.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.spec.ts b/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.spec.ts index cb82ddb7c4..c2e1c9cb68 100644 --- a/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.spec.ts +++ b/src/app/browse-by/browse-by-switcher/browse-by-switcher.component.spec.ts @@ -4,7 +4,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { BROWSE_BY_COMPONENT_FACTORY, BrowseByDataType } from './browse-by-decorator'; import { BrowseDefinition } from '../../core/shared/browse-definition.model'; -import { BehaviorSubject, of as observableOf } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; +import { ThemeService } from '../../shared/theme-support/theme.service'; describe('BrowseBySwitcherComponent', () => { let comp: BrowseBySwitcherComponent; @@ -44,11 +45,20 @@ describe('BrowseBySwitcherComponent', () => { data }; + let themeService: ThemeService; + let themeName: string; + beforeEach(waitForAsync(() => { + themeName = 'dspace'; + themeService = jasmine.createSpyObj('themeService', { + getThemeName: themeName, + }); + TestBed.configureTestingModule({ declarations: [BrowseBySwitcherComponent], providers: [ { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: ThemeService, useValue: themeService }, { provide: BROWSE_BY_COMPONENT_FACTORY, useValue: jasmine.createSpy('getComponentByBrowseByType').and.returnValue(null) } ], schemas: [NO_ERRORS_SCHEMA] @@ -68,7 +78,7 @@ describe('BrowseBySwitcherComponent', () => { }); it(`should call getComponentByBrowseByType with type "${type.dataType}"`, () => { - expect((comp as any).getComponentByBrowseByType).toHaveBeenCalledWith(type.dataType); + expect((comp as any).getComponentByBrowseByType).toHaveBeenCalledWith(type.dataType, themeName); }); }); }); From 155db64c63363d7e69fd342a0aabf686697a4291 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 12 Apr 2022 09:36:18 +0200 Subject: [PATCH 003/103] 86526: Added themable AuthNavMenuComponent --- src/app/header/header.component.html | 2 +- .../themed-auth-nav-menu.component.ts | 25 +++++++++++++++++++ src/app/shared/shared.module.ts | 2 ++ .../dspace/app/header/header.component.html | 2 +- .../dspace/app/navbar/navbar.component.html | 2 +- 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/app/shared/auth-nav-menu/themed-auth-nav-menu.component.ts diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index c7b979d266..e5d5f38971 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -8,7 +8,7 @@ From a9162eb9205c920f1d64857851117514a8c2beca Mon Sep 17 00:00:00 2001 From: Pratik Rajkotiya Date: Wed, 13 Apr 2022 18:20:16 +0530 Subject: [PATCH 004/103] [CST-5339] ORCID queue added. --- src/app/core/core.module.ts | 12 +- .../core/orcid/model/orcid-history.model.ts | 89 +++++++ .../model/orcid-history.resource-type.ts | 9 + src/app/core/orcid/model/orcid-queue.model.ts | 68 +++++ .../orcid/model/orcid-queue.resource-type.ts | 9 + src/app/core/orcid/orcid-history.service.ts | 95 +++++++ src/app/core/orcid/orcid-queue.service.ts | 124 +++++++++ src/app/item-page/item-page.module.ts | 4 +- .../orcid-page/orcid-page.component.html | 1 + .../orcid-queue/orcid-queue.component.html | 59 +++++ .../orcid-queue/orcid-queue.component.scss | 0 .../orcid-queue/orcid-queue.component.ts | 250 ++++++++++++++++++ 12 files changed, 717 insertions(+), 3 deletions(-) create mode 100644 src/app/core/orcid/model/orcid-history.model.ts create mode 100644 src/app/core/orcid/model/orcid-history.resource-type.ts create mode 100644 src/app/core/orcid/model/orcid-queue.model.ts create mode 100644 src/app/core/orcid/model/orcid-queue.resource-type.ts create mode 100644 src/app/core/orcid/orcid-history.service.ts create mode 100644 src/app/core/orcid/orcid-queue.service.ts create mode 100644 src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html create mode 100644 src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.scss create mode 100644 src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 7e97c78b3b..3f2737f30d 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -165,6 +165,10 @@ import { SubmissionAccessesModel } from './config/models/config-submission-acces import { ResearcherProfileService } from './profile/researcher-profile.service'; import { ProfileClaimService } from '../profile-page/profile-claim/profile-claim.service'; import { ResearcherProfile } from './profile/model/researcher-profile.model'; +import { OrcidQueueService } from './orcid/orcid-queue.service'; +import { OrcidHistoryService } from './orcid/orcid-history.service'; +import { OrcidQueue } from './orcid/model/orcid-queue.model'; +import { OrcidHistory } from './orcid/model/orcid-history.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -290,7 +294,9 @@ const PROVIDERS = [ GroupDataService, FeedbackDataService, ResearcherProfileService, - ProfileClaimService + ProfileClaimService, + OrcidQueueService, + OrcidHistoryService, ]; /** @@ -351,7 +357,9 @@ export const models = Root, SearchConfig, SubmissionAccessesModel, - ResearcherProfile + ResearcherProfile, + OrcidQueue, + OrcidHistory, ]; @NgModule({ diff --git a/src/app/core/orcid/model/orcid-history.model.ts b/src/app/core/orcid/model/orcid-history.model.ts new file mode 100644 index 0000000000..207a0c4df9 --- /dev/null +++ b/src/app/core/orcid/model/orcid-history.model.ts @@ -0,0 +1,89 @@ +import { autoserialize, deserialize } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { CacheableObject } from '../../cache/object-cache.reducer'; +import { HALLink } from '../../shared/hal-link.model'; +import { ResourceType } from '../../shared/resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { ORCID_HISTORY } from './orcid-history.resource-type'; + +/** + * Class the represents a Orcid History. + */ +@typedObject +export class OrcidHistory extends CacheableObject { + + static type = ORCID_HISTORY; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + /** + * The identifier of this Orcid History record + */ + @autoserialize + id: number; + + /** + * The name of the related entity + */ + @autoserialize + entityName: string; + + /** + * The identifier of the owner of this Orcid History record. + */ + @autoserialize + ownerId: string; + + /** + * The identifier of the entity related to this Orcid History record. + */ + @autoserialize + entityId: string; + + /** + * The type of the entity related to this Orcid History record. + */ + @autoserialize + entityType: string; + + /** + * The response status coming from ORCID api. + */ + @autoserialize + status: number; + + /** + * The putCode assigned by ORCID to the entity. + */ + @autoserialize + putCode: string; + + /** + * The last send attempt timestamp. + */ + lastAttempt: string; + + /** + * The success send attempt timestamp. + */ + successAttempt: string; + + /** + * The response coming from ORCID. + */ + responseMessage: string; + + /** + * The {@link HALLink}s for this Orcid History record + */ + @deserialize + _links: { + self: HALLink, + }; + +} diff --git a/src/app/core/orcid/model/orcid-history.resource-type.ts b/src/app/core/orcid/model/orcid-history.resource-type.ts new file mode 100644 index 0000000000..45da8cbf68 --- /dev/null +++ b/src/app/core/orcid/model/orcid-history.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for OrcidHistory + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const ORCID_HISTORY = new ResourceType('orcidhistory'); diff --git a/src/app/core/orcid/model/orcid-queue.model.ts b/src/app/core/orcid/model/orcid-queue.model.ts new file mode 100644 index 0000000000..52ab8676ad --- /dev/null +++ b/src/app/core/orcid/model/orcid-queue.model.ts @@ -0,0 +1,68 @@ +import { autoserialize, deserialize } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { CacheableObject } from '../../cache/object-cache.reducer'; +import { HALLink } from '../../shared/hal-link.model'; +import { ResourceType } from '../../shared/resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { ORCID_QUEUE } from './orcid-queue.resource-type'; + +/** + * Class the represents a Orcid Queue. + */ +@typedObject +export class OrcidQueue extends CacheableObject { + + static type = ORCID_QUEUE; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + /** + * The identifier of this Orcid Queue record + */ + @autoserialize + id: number; + + /** + * The record description. + */ + @autoserialize + description: string; + + /** + * The identifier of the owner of this Orcid Queue record. + */ + @autoserialize + ownerId: string; + + /** + * The identifier of the entity related to this Orcid Queue record. + */ + @autoserialize + entityId: string; + + /** + * The type of this Orcid Queue record. + */ + @autoserialize + recordType: string; + + /** + * The operation related to this Orcid Queue record. + */ + @autoserialize + operation: string; + + /** + * The {@link HALLink}s for this Orcid Queue record + */ + @deserialize + _links: { + self: HALLink, + }; + +} diff --git a/src/app/core/orcid/model/orcid-queue.resource-type.ts b/src/app/core/orcid/model/orcid-queue.resource-type.ts new file mode 100644 index 0000000000..a7f40d70ec --- /dev/null +++ b/src/app/core/orcid/model/orcid-queue.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for OrcidQueue + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const ORCID_QUEUE = new ResourceType('orcidqueue'); diff --git a/src/app/core/orcid/orcid-history.service.ts b/src/app/core/orcid/orcid-history.service.ts new file mode 100644 index 0000000000..03eb497956 --- /dev/null +++ b/src/app/core/orcid/orcid-history.service.ts @@ -0,0 +1,95 @@ +/* tslint:disable:max-classes-per-file */ + +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { catchError, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'; +import { isNotEmpty } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { createFailedRemoteDataObject$ } from '../../shared/remote-data.utils'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { DataService } from '../data/data.service'; +import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; +import { ItemDataService } from '../data/item-data.service'; +import { RemoteData } from '../data/remote-data'; +import { PostRequest, RestRequest } from '../data/request.models'; +import { RequestService } from '../data/request.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { getFinishedRemoteData, getResponseFromEntry, sendRequest } from '../shared/operators'; +import { OrcidHistory } from './model/orcid-history.model'; +import { ORCID_HISTORY } from './model/orcid-history.resource-type'; +import { OrcidQueue } from './model/orcid-queue.model'; +import { HttpOptions } from '../dspace-rest/dspace-rest.service'; + +/** + * A private DataService implementation to delegate specific methods to. + */ +class OrcidHistoryServiceImpl extends DataService { + public linkPath = 'orcidhistories'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } + +} + +/** + * A service that provides methods to make REST requests with Orcid History endpoint. + */ +@Injectable() +@dataService(ORCID_HISTORY) +export class OrcidHistoryService { + + dataService: OrcidHistoryServiceImpl; + + responseMsToLive: number = 10 * 1000; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer, + protected itemService: ItemDataService ) { + + this.dataService = new OrcidHistoryServiceImpl(requestService, rdbService, store, objectCache, halService, + notificationsService, http, comparator); + + } + + sendToORCID(orcidQueue: OrcidQueue): Observable> { + const requestId = this.requestService.generateRequestId(); + return this.getEndpoint().pipe( + map((endpointURL: string) => { + const options: HttpOptions = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Content-Type', 'text/uri-list'); + options.headers = headers; + return new PostRequest(requestId, endpointURL, orcidQueue._links.self.href, options); + }), + sendRequest(this.requestService), + switchMap((request: RestRequest) => this.rdbService.buildFromRequestUUID(request.uuid) as Observable>) + ); + } + + getEndpoint(): Observable { + return this.halService.getEndpoint(this.dataService.linkPath); + } + +} diff --git a/src/app/core/orcid/orcid-queue.service.ts b/src/app/core/orcid/orcid-queue.service.ts new file mode 100644 index 0000000000..7cf43a9aa0 --- /dev/null +++ b/src/app/core/orcid/orcid-queue.service.ts @@ -0,0 +1,124 @@ +/* tslint:disable:max-classes-per-file */ + +import { DataService } from '../data/data.service'; +import { OrcidQueue } from './model/orcid-queue.model'; +import { RequestService } from '../data/request.service'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { HttpClient } from '@angular/common/http'; +import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; +import { Injectable } from '@angular/core'; +import { dataService } from '../cache/builders/build-decorators'; +import { ORCID_QUEUE } from './model/orcid-queue.resource-type'; +import { ItemDataService } from '../data/item-data.service'; +import { combineLatest, Observable } from 'rxjs'; +import { RemoteData } from '../data/remote-data'; +import { PaginatedList } from '../data/paginated-list.model'; +import { RequestParam } from '../cache/models/request-param.model'; +import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; +import { NoContent } from '../shared/NoContent.model'; +import { ConfigurationDataService } from '../data/configuration-data.service'; +import { map } from 'rxjs/operators'; +import { getFirstSucceededRemoteDataPayload } from '../shared/operators'; +import { environment } from '../../../environments/environment'; +import { Router } from '@angular/router'; + +/** + * A private DataService implementation to delegate specific methods to. + */ +class OrcidQueueServiceImpl extends DataService { + public linkPath = 'orcidqueues'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } + +} + +/** + * A service that provides methods to make REST requests with Orcid Queue endpoint. + */ +@Injectable() +@dataService(ORCID_QUEUE) +export class OrcidQueueService { + + dataService: OrcidQueueServiceImpl; + + responseMsToLive: number = 10 * 1000; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer, + protected configurationService: ConfigurationDataService, + protected router: Router, + protected itemService: ItemDataService ) { + + this.dataService = new OrcidQueueServiceImpl(requestService, rdbService, store, objectCache, halService, + notificationsService, http, comparator); + + } + + /** + * @param itemId It represent a Id of owner + * @param paginationOptions + * @returns { OrcidQueue } + */ + searchByOwnerId(itemId: string, paginationOptions: PaginationComponentOptions): Observable>> { + return this.dataService.searchBy('findByOwner', { + searchParams: [new RequestParam('ownerId', itemId)], + elementsPerPage: paginationOptions.pageSize, + currentPage: paginationOptions.currentPage + },false, + true); + } + + /** + * @param orcidQueueId represents a id of orcid queue + * @returns { NoContent } + */ + deleteById(orcidQueueId: number): Observable> { + return this.dataService.delete(orcidQueueId + ''); + } + + /** + * This method will set linkPath to stale + */ + clearFindByOwnerRequests() { + this.requestService.setStaleByHrefSubstring(this.dataService.linkPath + '/search/findByOwner'); + } + + /** + * @param profileId represent a uuid of that user + * @returns orcid authorized url of that user + */ + getOrcidAuthorizeUrl(profileId: string): Observable { + return combineLatest([ + this.configurationService.findByPropertyName('orcid.authorize-url').pipe(getFirstSucceededRemoteDataPayload()), + this.configurationService.findByPropertyName('orcid.application-client-id').pipe(getFirstSucceededRemoteDataPayload()), + this.configurationService.findByPropertyName('orcid.scope').pipe(getFirstSucceededRemoteDataPayload())] + ).pipe( + map(([authorizeUrl, clientId, scopes]) => { + const redirectUri = environment.rest.baseUrl + '/api/cris/orcid/' + profileId + '/?url=' + encodeURIComponent(this.router.url); + return authorizeUrl.values[0] + '?client_id=' + clientId.values[0] + '&redirect_uri=' + redirectUri + '&response_type=code&scope=' + + scopes.values.join(' '); + })); + } +} diff --git a/src/app/item-page/item-page.module.ts b/src/app/item-page/item-page.module.ts index 2c4b57b249..9c471a5aa7 100644 --- a/src/app/item-page/item-page.module.ts +++ b/src/app/item-page/item-page.module.ts @@ -38,6 +38,7 @@ import { OrcidAuthComponent } from './orcid-page/orcid-auth/orcid-auth.component import { OrcidPageComponent } from './orcid-page/orcid-page.component'; import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'; import { OrcidSettingComponent } from './orcid-page/orcid-sync/orcid-setting.component'; +import { OrcidQueueComponent } from './orcid-page/orcid-queue/orcid-queue.component'; const ENTRY_COMPONENTS = [ @@ -73,7 +74,8 @@ const DECLARATIONS = [ VersionPageComponent, OrcidPageComponent, OrcidAuthComponent, - OrcidSettingComponent + OrcidSettingComponent, + OrcidQueueComponent ]; @NgModule({ diff --git a/src/app/item-page/orcid-page/orcid-page.component.html b/src/app/item-page/orcid-page/orcid-page.component.html index 4e62a8d51c..33c1dd158d 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.html +++ b/src/app/item-page/orcid-page/orcid-page.component.html @@ -1,2 +1,3 @@ + diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html new file mode 100644 index 0000000000..81e30bc013 --- /dev/null +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -0,0 +1,59 @@ +
+ + + +
+ + +
+ {{ 'person.page.orcid.sync-queue.empty-message' | translate}} +
+ + +
+ + + + + + + + + + + + + +
{{'person.page.orcid.sync-queue.description' | translate}}
+ {{ entry.description }} + +
+ + + + +
+
+
+
+
+
+
+
+
diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.scss b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts new file mode 100644 index 0000000000..01639a427c --- /dev/null +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -0,0 +1,250 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; +import { switchMap, tap } from 'rxjs/operators'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { RemoteData } from '../../../core/data/remote-data'; +import { OrcidHistory } from '../../../core/orcid/model/orcid-history.model'; +import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; +import { OrcidHistoryService } from '../../../core/orcid/orcid-history.service'; +import { OrcidQueueService } from '../../../core/orcid/orcid-queue.service'; +import { PaginationService } from '../../../core/pagination/pagination.service'; +import { getFinishedRemoteData, getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { hasValue } from '../../../shared/empty.util'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; + +@Component({ + selector: 'ds-orcid-queue', + templateUrl: './orcid-queue.component.html', + styleUrls: ['./orcid-queue.component.scss'] +}) +export class OrcidQueueComponent implements OnInit { + /** + * Pagination config used to display the list + */ + public paginationOptions: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + id: 'oqp', + pageSize: 5 + }); + + /** + * A boolean representing if results are loading + */ + public processing$ = new BehaviorSubject(false); + + /** + * A list of orcid queue records + */ + private list$: BehaviorSubject>> = new BehaviorSubject>>({} as any); + + /** + * Array to track all subscriptions and unsubscribe them onDestroy + * @type {Array} + */ + private subs: Subscription[] = []; + constructor(private orcidQueueService: OrcidQueueService, + protected translateService: TranslateService, + private paginationService: PaginationService, + private route: ActivatedRoute, + private notificationsService: NotificationsService, + private orcidHistoryService: OrcidHistoryService, + ) { } + + ngOnInit(): void { + this.updateList(); + } + + updateList() { + this.subs.push( + this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions).pipe( + tap(() => this.processing$.next(true)), + switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByOwnerId(this.route.snapshot.paramMap.get('id'), config)), + getFirstCompletedRemoteData() + ).subscribe((result: RemoteData>) => { + this.processing$.next(false); + this.list$.next(result); + this.orcidQueueService.clearFindByOwnerRequests(); + }) + ); + } + + + /** + * Return the list of orcid queue records + */ + getList(): Observable>> { + return this.list$.asObservable(); + } + + getIconClass(orcidQueue: OrcidQueue): string { + if (!orcidQueue.recordType) { + return 'fa fa-user'; + } + switch (orcidQueue.recordType.toLowerCase()) { + case 'publication': + return 'fa fa-book'; + case 'funding': + return 'fa fa-wallet'; + case 'education': + return 'fa fa-school'; + case 'affiliation': + return 'fa fa-university'; + case 'country': + return 'fas fa-globe-europe'; + case 'external_ids': + case 'researcher_urls': + return 'fas fa-external-link-alt'; + default: + return 'fa fa-user'; + } + } + + getIconTooltip(orcidQueue: OrcidQueue): string { + if (!orcidQueue.recordType) { + return ''; + } + + return 'person.page.orcid.sync-queue.tooltip.' + orcidQueue.recordType.toLowerCase(); + } + + getOperationBadgeClass(orcidQueue: OrcidQueue): string { + + if (!orcidQueue.operation) { + return ''; + } + + switch (orcidQueue.operation.toLowerCase()) { + case 'insert': + return 'badge badge-pill badge-success'; + case 'update': + return 'badge badge-pill badge-primary'; + case 'delete': + return 'badge badge-pill badge-danger'; + default: + return ''; + } + } + + getOperationTooltip(orcidQueue: OrcidQueue): string { + if (!orcidQueue.operation) { + return ''; + } + + return 'person.page.orcid.sync-queue.tooltip.' + orcidQueue.operation.toLowerCase(); + } + + getOperationClass(orcidQueue: OrcidQueue): string { + + if (!orcidQueue.operation) { + return ''; + } + + switch (orcidQueue.operation.toLowerCase()) { + case 'insert': + return 'fas fa-plus'; + case 'update': + return 'fas fa-edit'; + case 'delete': + return 'fas fa-trash-alt'; + default: + return ''; + } + } + + discardEntry(orcidQueue: OrcidQueue) { + this.processing$.next(true); + this.subs.push(this.orcidQueueService.deleteById(orcidQueue.id).pipe( + getFinishedRemoteData() + ).subscribe((remoteData) => { + this.processing$.next(false); + if (remoteData.isSuccess) { + this.notificationsService.success(this.translateService.get('person.page.orcid.sync-queue.discard.success')); + this.updateList(); + } else { + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.discard.error')); + } + })); + } + + send( orcidQueue: OrcidQueue ) { + this.processing$.next(true); + this.subs.push(this.orcidHistoryService.sendToORCID(orcidQueue).pipe( + getFinishedRemoteData() + ).subscribe((remoteData) => { + this.processing$.next(false); + if (remoteData.isSuccess) { + this.handleOrcidHistoryRecordCreation(remoteData.payload); + } else if (remoteData.statusCode === 422) { + this.handleValidationErrors(remoteData); + } else { + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.error')); + } + })); + } + + handleOrcidHistoryRecordCreation(orcidHistory: OrcidHistory) { + switch (orcidHistory.status) { + case 200: + case 201: + case 204: + this.notificationsService.success(this.translateService.get('person.page.orcid.sync-queue.send.success')); + this.updateList(); + break; + case 400: + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.bad-request-error'), null, { timeOut: -1 }); + break; + case 401: + combineLatest([ + this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.title'), + this.getUnauthorizedErrorContent()], + ).subscribe(([title, content]) => { + this.notificationsService.error(title, content, { timeOut: -1}, true); + }); + break; + case 404: + this.notificationsService.warning(this.translateService.get('person.page.orcid.sync-queue.send.not-found-warning')); + break; + case 409: + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.conflict-error'), null, { timeOut: -1 }); + break; + default: + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.error'), null, { timeOut: -1 }); + } + } + + handleValidationErrors(remoteData: RemoteData) { + const translations = [this.translateService.get('person.page.orcid.sync-queue.send.validation-error')]; + const errorMessage = remoteData.errorMessage; + if (errorMessage && errorMessage.indexOf('Error codes:') > 0) { + errorMessage.substring(errorMessage.indexOf(':') + 1).trim().split(',') + .forEach((error) => translations.push(this.translateService.get('person.page.orcid.sync-queue.send.validation-error.' + error))); + } + combineLatest(translations).subscribe((messages) => { + const title = messages.shift(); + const content = '
    ' + messages.map((message) => '
  • ' + message + '
  • ').join('') + '
'; + this.notificationsService.error(title, content, { timeOut: -1 }, true); + }); + } + + private getUnauthorizedErrorContent(): Observable { + return this.orcidQueueService.getOrcidAuthorizeUrl(this.route.snapshot.paramMap.get('id')).pipe( + switchMap((authorizeUrl) => this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.content', { orcid : authorizeUrl})) + ); + } + + /** + * Unsubscribe from all subscriptions + */ + ngOnDestroy(): void { + this.list$ = null; + this.subs.filter((subscription) => hasValue(subscription)) + .forEach((subscription) => subscription.unsubscribe()); + } + + isProfileRecord(orcidQueue: OrcidQueue): boolean { + return orcidQueue.recordType !== 'Publication' && orcidQueue.recordType !== 'Project'; + } + +} From 7480a19a656fa954da162ff665b955bc86acecff Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 28 Apr 2022 12:18:14 +0200 Subject: [PATCH 005/103] 89720: Added ThemedItemMetadataComponent --- .../edit-item-template-page.component.html | 2 +- .../edit-item-page/edit-item-page.module.ts | 5 ++- .../themed-item-metadata.component.ts | 34 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/app/item-page/edit-item-page/item-metadata/themed-item-metadata.component.ts diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html index f8c5c92e96..aa6b71f588 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html @@ -3,7 +3,7 @@

{{ 'collection.edit.template.head' | translate:{ collection: collection?.name } }}

- +
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 97901bd7c8..67cf31c6ed 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 @@ -15,6 +15,7 @@ import { ItemPrivateComponent } from './item-private/item-private.component'; import { ItemPublicComponent } from './item-public/item-public.component'; import { ItemDeleteComponent } from './item-delete/item-delete.component'; import { ItemMetadataComponent } from './item-metadata/item-metadata.component'; +import { ThemedItemMetadataComponent } from './item-metadata/themed-item-metadata.component'; import { EditInPlaceFieldComponent } from './item-metadata/edit-in-place-field/edit-in-place-field.component'; import { ItemBitstreamsComponent } from './item-bitstreams/item-bitstreams.component'; import { ItemEditBitstreamComponent } from './item-bitstreams/item-edit-bitstream/item-edit-bitstream.component'; @@ -62,6 +63,7 @@ import { ResourcePoliciesModule } from '../../shared/resource-policies/resource- ItemDeleteComponent, ItemStatusComponent, ItemMetadataComponent, + ThemedItemMetadataComponent, ItemRelationshipsComponent, ItemBitstreamsComponent, ItemVersionHistoryComponent, @@ -83,7 +85,8 @@ import { ResourcePoliciesModule } from '../../shared/resource-policies/resource- ObjectValuesPipe ], exports: [ - ItemMetadataComponent + EditInPlaceFieldComponent, + ThemedItemMetadataComponent, ] }) export class EditItemPageModule { diff --git a/src/app/item-page/edit-item-page/item-metadata/themed-item-metadata.component.ts b/src/app/item-page/edit-item-page/item-metadata/themed-item-metadata.component.ts new file mode 100644 index 0000000000..53f0120015 --- /dev/null +++ b/src/app/item-page/edit-item-page/item-metadata/themed-item-metadata.component.ts @@ -0,0 +1,34 @@ +import { Component, Input } from '@angular/core'; +import { Item } from '../../../core/shared/item.model'; +import { UpdateDataService } from '../../../core/data/update-data.service'; +import { ItemMetadataComponent } from './item-metadata.component'; +import { ThemedComponent } from '../../../shared/theme-support/themed.component'; + +@Component({ + selector: 'ds-themed-item-metadata', + styleUrls: [], + templateUrl: './../../../shared/theme-support/themed.component.html', +}) +/** + * Component for displaying an item's metadata edit page + */ +export class ThemedItemMetadataComponent extends ThemedComponent { + + @Input() item: Item; + + @Input() updateService: UpdateDataService; + + protected inAndOutputNames: (keyof ItemMetadataComponent & keyof this)[] = ['item', 'updateService']; + + protected getComponentName(): string { + return 'ItemMetadataComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../../../themes/${themeName}/app/item-page/edit-item-page/item-metadata/item-metadata.component`); + } + + protected importUnthemedComponent(): Promise { + return import(`./item-metadata.component`); + } +} From 2f84d0294be4582fdc5c6db8c0fe059b42eeddfa Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 29 Apr 2022 10:27:26 +0200 Subject: [PATCH 006/103] 89720: Added ThemedEditItemTemplatePageComponent --- .../collection-page-routing.module.ts | 4 +-- .../collection-page/collection-page.module.ts | 2 ++ ...hemed-edit-item-template-page.component.ts | 25 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts diff --git a/src/app/collection-page/collection-page-routing.module.ts b/src/app/collection-page/collection-page-routing.module.ts index 5879e523af..0574958037 100644 --- a/src/app/collection-page/collection-page-routing.module.ts +++ b/src/app/collection-page/collection-page-routing.module.ts @@ -6,7 +6,7 @@ import { CreateCollectionPageComponent } from './create-collection-page/create-c import { AuthenticatedGuard } from '../core/auth/authenticated.guard'; import { CreateCollectionPageGuard } from './create-collection-page/create-collection-page.guard'; import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component'; -import { EditItemTemplatePageComponent } from './edit-item-template-page/edit-item-template-page.component'; +import { ThemedEditItemTemplatePageComponent } from './edit-item-template-page/themed-edit-item-template-page.component'; import { ItemTemplatePageResolver } from './edit-item-template-page/item-template-page.resolver'; import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-breadcrumb.resolver'; import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service'; @@ -52,7 +52,7 @@ import { ThemedCollectionPageComponent } from './themed-collection-page.componen }, { path: ITEMTEMPLATE_PATH, - component: EditItemTemplatePageComponent, + component: ThemedEditItemTemplatePageComponent, canActivate: [AuthenticatedGuard], resolve: { item: ItemTemplatePageResolver, diff --git a/src/app/collection-page/collection-page.module.ts b/src/app/collection-page/collection-page.module.ts index 3652823200..c35ebf9021 100644 --- a/src/app/collection-page/collection-page.module.ts +++ b/src/app/collection-page/collection-page.module.ts @@ -8,6 +8,7 @@ import { CollectionPageRoutingModule } from './collection-page-routing.module'; import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component'; import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component'; import { EditItemTemplatePageComponent } from './edit-item-template-page/edit-item-template-page.component'; +import { ThemedEditItemTemplatePageComponent } from './edit-item-template-page/themed-edit-item-template-page.component'; import { EditItemPageModule } from '../item-page/edit-item-page/edit-item-page.module'; import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component'; import { SearchService } from '../core/shared/search/search.service'; @@ -32,6 +33,7 @@ import { ComcolModule } from '../shared/comcol/comcol.module'; CreateCollectionPageComponent, DeleteCollectionPageComponent, EditItemTemplatePageComponent, + ThemedEditItemTemplatePageComponent, CollectionItemMapperComponent ], providers: [ diff --git a/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts b/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts new file mode 100644 index 0000000000..b53f4e6c45 --- /dev/null +++ b/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { ThemedComponent } from '../../shared/theme-support/themed.component'; +import { EditItemTemplatePageComponent } from './edit-item-template-page.component'; + +@Component({ + selector: 'ds-themed-edit-item-template-page', + styleUrls: [], + templateUrl: '../../shared/theme-support/themed.component.html', +}) +/** + * Component for editing the item template of a collection + */ +export class ThemedEditItemTemplatePageComponent extends ThemedComponent { + protected getComponentName(): string { + return 'EditItemTemplatePageComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../../themes/${themeName}/app/collection-page/edit-item-template-page/edit-item-template-page.component`); + } + + protected importUnthemedComponent(): Promise { + return import('./edit-item-template-page.component'); + } +} From b9b5b50999a3e3173a97709e403c4773839116a5 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 3 May 2022 08:56:37 +0200 Subject: [PATCH 007/103] 89741: Added ThemedExpandableNavbarSectionComponent --- ...med-expandable-navbar-section.component.ts | 29 +++++++++++++++++++ src/app/navbar/navbar.module.ts | 11 +++---- 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts diff --git a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts new file mode 100644 index 0000000000..744eeb5a02 --- /dev/null +++ b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts @@ -0,0 +1,29 @@ +import { Component } from '@angular/core'; +import { ThemedComponent } from '../../shared/theme-support/themed.component'; +import { ExpandableNavbarSectionComponent } from './expandable-navbar-section.component'; +import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator'; +import { MenuID } from '../../shared/menu/initial-menus-state'; + +/** + * Themed wrapper for ExpandableNavbarSectionComponent + */ +@Component({ + /* tslint:disable:component-selector */ + selector: 'li[ds-themed-expandable-navbar-section]', + styleUrls: [], + templateUrl: '../../shared/theme-support/themed.component.html', +}) +@rendersSectionForMenu(MenuID.PUBLIC, true) +export class ThemedExpandableNavbarSectionComponent extends ThemedComponent { + protected getComponentName(): string { + return 'ExpandableNavbarSectionComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import(`../../../themes/${themeName}/app/navbar/expandable-navbar-section/expandable-navbar-section.component`); + } + + protected importUnthemedComponent(): Promise { + return import(`./expandable-navbar-section.component`); + } +} diff --git a/src/app/navbar/navbar.module.ts b/src/app/navbar/navbar.module.ts index c84e732fd5..95641de41b 100644 --- a/src/app/navbar/navbar.module.ts +++ b/src/app/navbar/navbar.module.ts @@ -7,6 +7,7 @@ import { CoreModule } from '../core/core.module'; import { NavbarEffects } from './navbar.effects'; import { NavbarSectionComponent } from './navbar-section/navbar-section.component'; import { ExpandableNavbarSectionComponent } from './expandable-navbar-section/expandable-navbar-section.component'; +import { ThemedExpandableNavbarSectionComponent } from './expandable-navbar-section/themed-expandable-navbar-section.component'; import { NavbarComponent } from './navbar.component'; import { MenuModule } from '../shared/menu/menu.module'; import { SharedModule } from '../shared/shared.module'; @@ -20,7 +21,7 @@ const effects = [ const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator NavbarSectionComponent, - ExpandableNavbarSectionComponent, + ThemedExpandableNavbarSectionComponent, ]; @NgModule({ @@ -36,19 +37,19 @@ const ENTRY_COMPONENTS = [ NavbarComponent, ThemedNavbarComponent, NavbarSectionComponent, - ExpandableNavbarSectionComponent + ExpandableNavbarSectionComponent, + ThemedExpandableNavbarSectionComponent, ], providers: [ ], entryComponents: [ - NavbarSectionComponent, - ExpandableNavbarSectionComponent + ...ENTRY_COMPONENTS, ], exports: [ ThemedNavbarComponent, NavbarSectionComponent, - ExpandableNavbarSectionComponent + ThemedExpandableNavbarSectionComponent, ] }) From 870a36180c4836108c23f790e5e49c04460a99b4 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Mon, 25 Apr 2022 17:26:12 +0200 Subject: [PATCH 008/103] 89984: Add ThemedLoadingComponent --- .../epeople-registry.component.html | 2 +- .../eperson-form/eperson-form.component.html | 4 +-- .../groups-registry.component.html | 2 +- .../edit-bitstream-page.component.html | 4 +-- .../browse-by-metadata-page.component.html | 2 +- .../collection-page.component.html | 8 ++--- .../collection-source.component.html | 2 +- .../edit-item-template-page.component.html | 2 +- .../community-list.component.html | 6 ++-- .../community-page.component.html | 2 +- ...ty-page-sub-collection-list.component.html | 2 +- ...ity-page-sub-community-list.component.html | 2 +- .../top-level-community-list.component.html | 2 +- .../item-bitstreams.component.html | 2 +- ...rag-and-drop-bitstream-list.component.html | 2 +- .../edit-relationship-list.component.html | 2 +- .../item-relationships.component.html | 2 +- .../full/full-item-page.component.html | 2 +- .../media-viewer/media-viewer.component.html | 4 +-- .../media-viewer.component.spec.ts | 2 +- .../file-section/file-section.component.html | 2 +- .../file-section.component.spec.ts | 2 +- .../item-page/simple/item-page.component.html | 2 +- .../simple/item-page.component.spec.ts | 2 +- ...etadata-representation-list.component.html | 2 +- .../related-items.component.html | 2 +- .../detail/process-detail.component.html | 2 +- .../deny-request-copy.component.html | 2 +- .../grant-deny-request-copy.component.html | 2 +- .../grant-request-copy.component.html | 2 +- src/app/root/root.component.html | 4 +-- .../user-menu/user-menu.component.html | 2 +- .../shared/browse-by/browse-by.component.html | 2 +- .../browse-by/browse-by.component.spec.ts | 2 +- .../collection-dropdown.component.html | 4 +-- .../comcol-role/comcol-role.component.html | 2 +- .../dso-selector/dso-selector.component.html | 2 +- .../entity-dropdown.component.html | 4 +-- ...sting-metadata-list-element.component.html | 2 +- ...sting-relation-list-element.component.html | 2 +- .../dynamic-relation-group.component.html | 2 +- ...namic-lookup-relation-modal.component.html | 2 +- ...elation-external-source-tab.component.html | 4 +-- ...tion-external-source-tab.component.spec.ts | 4 +-- .../loading/themed-loading.component.ts | 31 +++++++++++++++++++ src/app/shared/log-in/log-in.component.html | 2 +- .../object-detail.component.html | 2 +- .../object-grid/object-grid.component.html | 2 +- ...-search-result-list-element.component.html | 4 +-- ...-search-result-list-element.component.html | 4 +-- .../collection-select.component.html | 2 +- .../item-select/item-select.component.html | 2 +- .../search-results.component.html | 2 +- src/app/shared/shared.module.ts | 2 ++ .../vocabulary-treeview.component.html | 2 +- .../statistics-page.component.html | 2 +- .../form/submission-form.component.html | 2 +- ...-import-external-collection.component.html | 2 +- .../submission-import-external.component.html | 4 +-- ...mission-section-cc-licenses.component.html | 4 +-- .../sections/form/section-form.component.html | 2 +- src/app/thumbnail/thumbnail.component.html | 4 +-- src/app/thumbnail/thumbnail.component.spec.ts | 2 +- 63 files changed, 112 insertions(+), 79 deletions(-) create mode 100644 src/app/shared/loading/themed-loading.component.ts diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.html b/src/app/access-control/epeople-registry/epeople-registry.component.html index 7ef02a76cf..2d87f21d26 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -45,7 +45,7 @@
- + - +
{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
- + - +
- + diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html index 2321da0204..c0741891eb 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html @@ -35,7 +35,7 @@ (prev)="goPrev()" (next)="goNext()"> - + diff --git a/src/app/collection-page/collection-page.component.html b/src/app/collection-page/collection-page.component.html index 9d598a3b69..4f5422e300 100644 --- a/src/app/collection-page/collection-page.component.html +++ b/src/app/collection-page/collection-page.component.html @@ -57,8 +57,8 @@ - + @@ -75,7 +75,7 @@ - + diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html index b67ee9a1bd..847ccefdda 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -25,7 +25,7 @@ - +

{{ 'collection.edit.tabs.source.form.head' | translate }}

diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html index f8c5c92e96..37258cd057 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html @@ -6,7 +6,7 @@ - +
diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index f441dfa36e..5d53633c4e 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -1,4 +1,4 @@ - + {{ 'communityList.showMore' | translate }} - +
@@ -57,7 +57,7 @@ - +
diff --git a/src/app/community-page/community-page.component.html b/src/app/community-page/community-page.component.html index cf7282eb4b..95755fdaf1 100644 --- a/src/app/community-page/community-page.component.html +++ b/src/app/community-page/community-page.component.html @@ -41,5 +41,5 @@ - + diff --git a/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.html b/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.html index 9928ebd18a..69f16ee3ac 100644 --- a/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.html +++ b/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.html @@ -9,5 +9,5 @@ - +
diff --git a/src/app/community-page/sub-community-list/community-page-sub-community-list.component.html b/src/app/community-page/sub-community-list/community-page-sub-community-list.component.html index 2d14dce60a..be2788a9f4 100644 --- a/src/app/community-page/sub-community-list/community-page-sub-community-list.component.html +++ b/src/app/community-page/sub-community-list/community-page-sub-community-list.component.html @@ -9,5 +9,5 @@ - + diff --git a/src/app/home-page/top-level-community-list/top-level-community-list.component.html b/src/app/home-page/top-level-community-list/top-level-community-list.component.html index dbea87a175..788db6ea4f 100644 --- a/src/app/home-page/top-level-community-list/top-level-community-list.component.html +++ b/src/app/home-page/top-level-community-list/top-level-community-list.component.html @@ -10,4 +10,4 @@ - + diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 315498378a..0d6a609e74 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -44,7 +44,7 @@ class="alert alert-info w-100 d-inline-block mt-4" role="alert"> {{'item.edit.bitstreams.empty' | translate}} - +
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.html 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.html index f7904f6cc8..f54aa73597 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.html +++ 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.html @@ -29,5 +29,5 @@
- + diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html index 86ab93662e..7cdc903f24 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html @@ -31,5 +31,5 @@
{{"item.edit.relationships.no-relationships" | translate}}
- + diff --git a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html index 4a53445a6d..f19ab21871 100644 --- a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html @@ -32,7 +32,7 @@ >
- +
diff --git a/src/app/item-page/full/full-item-page.component.html b/src/app/item-page/full/full-item-page.component.html index d2655c4ad0..ea97a3957c 100644 --- a/src/app/item-page/full/full-item-page.component.html +++ b/src/app/item-page/full/full-item-page.component.html @@ -37,5 +37,5 @@
- + diff --git a/src/app/item-page/media-viewer/media-viewer.component.html b/src/app/item-page/media-viewer/media-viewer.component.html index b79b91629f..4259af5250 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.html +++ b/src/app/item-page/media-viewer/media-viewer.component.html @@ -1,9 +1,9 @@ - + >
diff --git a/src/app/item-page/media-viewer/media-viewer.component.spec.ts b/src/app/item-page/media-viewer/media-viewer.component.spec.ts index cfd72bf416..39a35ebe61 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.spec.ts +++ b/src/app/item-page/media-viewer/media-viewer.component.spec.ts @@ -110,7 +110,7 @@ describe('MediaViewerComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-loading')); + const loading = fixture.debugElement.query(By.css('ds-themed-loading')); expect(loading.nativeElement).toBeDefined(); }); }); diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.html b/src/app/item-page/simple/field-components/file-section/file-section.component.html index 3d093f83c9..5fa5e5096f 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.html +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.html @@ -6,7 +6,7 @@ ({{(file?.sizeBytes) | dsFileSize }}) - + diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts index fdd6d14e7d..2d185aef9c 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts @@ -86,7 +86,7 @@ describe('FileSectionComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-loading')); + const loading = fixture.debugElement.query(By.css('ds-themed-loading')); expect(loading.nativeElement).toBeDefined(); }); }); diff --git a/src/app/item-page/simple/item-page.component.html b/src/app/item-page/simple/item-page.component.html index 74b61fd976..d91f4b501d 100644 --- a/src/app/item-page/simple/item-page.component.html +++ b/src/app/item-page/simple/item-page.component.html @@ -9,5 +9,5 @@
- + diff --git a/src/app/item-page/simple/item-page.component.spec.ts b/src/app/item-page/simple/item-page.component.spec.ts index ff5a1e38d5..0b0f1e1724 100644 --- a/src/app/item-page/simple/item-page.component.spec.ts +++ b/src/app/item-page/simple/item-page.component.spec.ts @@ -85,7 +85,7 @@ describe('ItemPageComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-loading')); + const loading = fixture.debugElement.query(By.css('ds-themed-loading')); expect(loading.nativeElement).toBeDefined(); }); }); diff --git a/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html b/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html index d1281f450a..e1559cb129 100644 --- a/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html +++ b/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html @@ -4,7 +4,7 @@ - + - + diff --git a/src/app/request-copy/grant-request-copy/grant-request-copy.component.html b/src/app/request-copy/grant-request-copy/grant-request-copy.component.html index d2c2cfc3c8..5cb4dbac36 100644 --- a/src/app/request-copy/grant-request-copy/grant-request-copy.component.html +++ b/src/app/request-copy/grant-request-copy/grant-request-copy.component.html @@ -13,5 +13,5 @@ - + diff --git a/src/app/root/root.component.html b/src/app/root/root.component.html index 898074352c..d0465af69f 100644 --- a/src/app/root/root.component.html +++ b/src/app/root/root.component.html @@ -13,7 +13,7 @@
- +
@@ -25,6 +25,6 @@
- +
diff --git a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html index ac55a211e9..736d39d318 100644 --- a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html +++ b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html @@ -1,4 +1,4 @@ - +
{{(user$ | async)?.name}} ({{(user$ | async)?.email}}) {{'nav.profile' | translate}} diff --git a/src/app/shared/browse-by/browse-by.component.html b/src/app/shared/browse-by/browse-by.component.html index 6d1422293d..645a987abe 100644 --- a/src/app/shared/browse-by/browse-by.component.html +++ b/src/app/shared/browse-by/browse-by.component.html @@ -34,7 +34,7 @@
- + diff --git a/src/app/shared/comcol/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 index b0a319b4ff..440785b89b 100644 --- a/src/app/shared/comcol/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 @@ -13,7 +13,7 @@
- +
{{'comcol-role.edit.no-group' | translate}}
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html index 4b46d3bc3f..d4283246d8 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html @@ -31,7 +31,7 @@
diff --git a/src/app/shared/entity-dropdown/entity-dropdown.component.html b/src/app/shared/entity-dropdown/entity-dropdown.component.html index 59c242ef97..a4d539625f 100644 --- a/src/app/shared/entity-dropdown/entity-dropdown.component.html +++ b/src/app/shared/entity-dropdown/entity-dropdown.component.html @@ -21,8 +21,8 @@ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html index 07ea131a00..62d34a8625 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html @@ -1,7 +1,7 @@
- + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html index 15087d2553..ff91b18e1c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html @@ -1,7 +1,7 @@
- + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html index 84bc0f4ffe..05f443aad5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html @@ -57,7 +57,7 @@
- +
- + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html index 74fc5fd06d..f26de733b2 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html @@ -6,6 +6,6 @@ - + [showMessage]="false"> diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html index 41d95b87af..2f0b04ef12 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html @@ -6,6 +6,6 @@ - + [showMessage]="false"> diff --git a/src/app/shared/object-select/collection-select/collection-select.component.html b/src/app/shared/object-select/collection-select/collection-select.component.html index 27ebcd9643..8ed41c5226 100644 --- a/src/app/shared/object-select/collection-select/collection-select.component.html +++ b/src/app/shared/object-select/collection-select/collection-select.component.html @@ -28,7 +28,7 @@ {{'collection.select.empty' | translate}}
- +
- + diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 715ee66a99..f9391afdb4 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -177,6 +177,7 @@ import { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/ import { BitstreamRequestACopyPageComponent } from './bitstream-request-a-copy-page/bitstream-request-a-copy-page.component'; import { DsSelectComponent } from './ds-select/ds-select.component'; import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component'; +import { ThemedLoadingComponent } from './loading/themed-loading.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -234,6 +235,7 @@ const COMPONENTS = [ FileSectionComponent, LangSwitchComponent, LoadingComponent, + ThemedLoadingComponent, LogInComponent, LogOutComponent, NumberPickerComponent, diff --git a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html index 3f57e6a4c3..39c62d6e53 100644 --- a/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/vocabulary-treeview/vocabulary-treeview.component.html @@ -23,7 +23,7 @@
- +

{{'vocabulary-treeview.search.no-result' | translate}}

diff --git a/src/app/statistics-page/statistics-page/statistics-page.component.html b/src/app/statistics-page/statistics-page/statistics-page.component.html index 5cf1e9c8b5..c6938c7582 100644 --- a/src/app/statistics-page/statistics-page/statistics-page.component.html +++ b/src/app/statistics-page/statistics-page/statistics-page.component.html @@ -11,7 +11,7 @@ - + diff --git a/src/app/submission/form/submission-form.component.html b/src/app/submission/form/submission-form.component.html index c86d4e0195..a80fe35f4e 100644 --- a/src/app/submission/form/submission-form.component.html +++ b/src/app/submission/form/submission-form.component.html @@ -22,7 +22,7 @@
- +
- \ No newline at end of file + diff --git a/src/app/shared/menu/menu-section.decorator.ts b/src/app/shared/menu/menu-section.decorator.ts index 9374ab3c0d..18eedd1cf4 100644 --- a/src/app/shared/menu/menu-section.decorator.ts +++ b/src/app/shared/menu/menu-section.decorator.ts @@ -1,6 +1,6 @@ import { DEFAULT_THEME } from '../object-collection/shared/listable-object/listable-object.decorator'; import { MenuID } from './initial-menus-state'; -import { hasNoValue, hasValue } from '../empty.util'; +import { hasValue } from '../empty.util'; const menuComponentMap = new Map(); diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 2ff0713f46..79ed914c5d 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -70,6 +70,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges this.lazyLoadSub = this.resolveThemedComponent(this.themeService.getThemeName()).pipe( switchMap((themedFile: any) => { + console.log(themedFile); if (hasValue(themedFile) && hasValue(themedFile[this.getComponentName()])) { // if the file is not null, and exports a component with the specified name, // return that component diff --git a/src/themes/custom/app/shared/loading/loading.component.html b/src/themes/custom/app/shared/loading/loading.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/shared/loading/loading.component.scss b/src/themes/custom/app/shared/loading/loading.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/shared/loading/loading.component.ts b/src/themes/custom/app/shared/loading/loading.component.ts new file mode 100644 index 0000000000..43249a4624 --- /dev/null +++ b/src/themes/custom/app/shared/loading/loading.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; +import { LoadingComponent as BaseComponent } from '../../../../../app/shared/loading/loading.component'; + +@Component({ + selector: 'ds-loading', + styleUrls: ['../../../../../app/shared/loading/loading.component.scss'], + // styleUrls: ['./loading.component.scss'], + templateUrl: '../../../../app/shared/loading/loading.component.html' + // templateUrl: './loading.component.html' +}) +export class LoadingComponent extends BaseComponent { + +} diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index e2e97b9087..67ad6028ce 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -84,6 +84,7 @@ 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'; import { FeedbackComponent } from './app/info/feedback/feedback.component'; +import { LoadingComponent } from './app/shared/loading/loading.component'; const DECLARATIONS = [ FileSectionComponent, @@ -126,7 +127,8 @@ const DECLARATIONS = [ NavbarComponent, HeaderNavbarWrapperComponent, BreadcrumbsComponent, - FeedbackComponent + FeedbackComponent, + LoadingComponent ]; @NgModule({ From 166a163c24fd0e6b05aa6a49fc8474c10c9a1600 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Wed, 11 May 2022 12:34:44 +0200 Subject: [PATCH 017/103] Fix custom loading components template url --- src/themes/custom/app/shared/loading/loading.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/custom/app/shared/loading/loading.component.ts b/src/themes/custom/app/shared/loading/loading.component.ts index 43249a4624..fb1a291dc0 100644 --- a/src/themes/custom/app/shared/loading/loading.component.ts +++ b/src/themes/custom/app/shared/loading/loading.component.ts @@ -5,7 +5,7 @@ import { LoadingComponent as BaseComponent } from '../../../../../app/shared/loa selector: 'ds-loading', styleUrls: ['../../../../../app/shared/loading/loading.component.scss'], // styleUrls: ['./loading.component.scss'], - templateUrl: '../../../../app/shared/loading/loading.component.html' + templateUrl: '../../../../../app/shared/loading/loading.component.html' // templateUrl: './loading.component.html' }) export class LoadingComponent extends BaseComponent { From 67ffa89c472bc7f86283fd8e0bcd735f481d4bc6 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Wed, 11 May 2022 13:30:11 +0200 Subject: [PATCH 018/103] Remove console.log --- src/app/shared/theme-support/themed.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 79ed914c5d..2ff0713f46 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -70,7 +70,6 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges this.lazyLoadSub = this.resolveThemedComponent(this.themeService.getThemeName()).pipe( switchMap((themedFile: any) => { - console.log(themedFile); if (hasValue(themedFile) && hasValue(themedFile[this.getComponentName()])) { // if the file is not null, and exports a component with the specified name, // return that component From 5b4ecb9fc23633aad3224a9002cb56d85fc028c8 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 11 May 2022 13:46:03 +0200 Subject: [PATCH 019/103] 89720: Themed ItemMetadataComponent --- .../item-metadata/item-metadata.component.html | 0 .../item-metadata/item-metadata.component.scss | 0 .../item-metadata/item-metadata.component.ts | 17 +++++++++++++++++ src/themes/custom/theme.module.ts | 4 +++- 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.html create mode 100644 src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.scss create mode 100644 src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.ts diff --git a/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.html b/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.scss b/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.ts b/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.ts new file mode 100644 index 0000000000..d6d7c4b8fb --- /dev/null +++ b/src/themes/custom/app/item-page/edit-item-page/item-metadata/item-metadata.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { + ItemMetadataComponent as BaseComponent +} from '../../../../../../app/item-page/edit-item-page/item-metadata/item-metadata.component'; + +@Component({ + selector: 'ds-item-metadata', + // styleUrls: ['./item-metadata.component.scss'], + styleUrls: ['../../../../../../app/item-page/edit-item-page/item-metadata/item-metadata.component.scss'], + // templateUrl: './item-metadata.component.html', + templateUrl: '../../../../../../app/item-page/edit-item-page/item-metadata/item-metadata.component.html', +}) +/** + * Component for displaying an item's metadata edit page + */ +export class ItemMetadataComponent extends BaseComponent { +} diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index e2e97b9087..ce259b5841 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -84,6 +84,7 @@ 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'; import { FeedbackComponent } from './app/info/feedback/feedback.component'; +import { ItemMetadataComponent } from './app/item-page/edit-item-page/item-metadata/item-metadata.component'; const DECLARATIONS = [ FileSectionComponent, @@ -126,7 +127,8 @@ const DECLARATIONS = [ NavbarComponent, HeaderNavbarWrapperComponent, BreadcrumbsComponent, - FeedbackComponent + FeedbackComponent, + ItemMetadataComponent, ]; @NgModule({ From a89375f67babaad5db95d9e661c8a89210940806 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 11 May 2022 14:28:16 +0200 Subject: [PATCH 020/103] 89720: Themed EditItemTemplatePageComponent --- .../edit-item-template-page.component.html | 0 .../edit-item-template-page.component.scss | 0 .../edit-item-template-page.component.ts | 16 ++++++++++++++++ src/themes/custom/theme.module.ts | 4 ++++ 4 files changed, 20 insertions(+) create mode 100644 src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.html create mode 100644 src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.scss create mode 100644 src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts diff --git a/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.html b/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.scss b/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts b/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts new file mode 100644 index 0000000000..ad9f515dcf --- /dev/null +++ b/src/themes/custom/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { + EditItemTemplatePageComponent as BaseComponent +} from '../../../../../app/collection-page/edit-item-template-page/edit-item-template-page.component'; + +@Component({ + selector: 'ds-edit-item-template-page', + styleUrls: ['./edit-item-template-page.component.scss'], + // templateUrl: './edit-item-template-page.component.html', + templateUrl: '../../../../../app/collection-page/edit-item-template-page/edit-item-template-page.component.html', +}) +/** + * Component for editing the item template of a collection + */ +export class EditItemTemplatePageComponent extends BaseComponent { +} diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index ce259b5841..af3dee50c0 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -85,6 +85,9 @@ import { ResourcePoliciesModule } from '../../app/shared/resource-policies/resou import { ComcolModule } from '../../app/shared/comcol/comcol.module'; import { FeedbackComponent } from './app/info/feedback/feedback.component'; import { ItemMetadataComponent } from './app/item-page/edit-item-page/item-metadata/item-metadata.component'; +import { + EditItemTemplatePageComponent +} from './app/collection-page/edit-item-template-page/edit-item-template-page.component'; const DECLARATIONS = [ FileSectionComponent, @@ -129,6 +132,7 @@ const DECLARATIONS = [ BreadcrumbsComponent, FeedbackComponent, ItemMetadataComponent, + EditItemTemplatePageComponent, ]; @NgModule({ From db375b8f4702acc19c14480d3f27a26ae023957c Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 12 May 2022 12:05:17 +0200 Subject: [PATCH 021/103] 91131: Added parent constructor to ThemedLoadingComponent --- src/app/shared/loading/themed-loading.component.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/shared/loading/themed-loading.component.ts b/src/app/shared/loading/themed-loading.component.ts index 2b6aa6212c..0f887a025f 100644 --- a/src/app/shared/loading/themed-loading.component.ts +++ b/src/app/shared/loading/themed-loading.component.ts @@ -1,6 +1,7 @@ -import { Component, Input } from '@angular/core'; -import { ThemedComponent } from '../../shared/theme-support/themed.component'; +import { Component, Input, ComponentFactoryResolver, ChangeDetectorRef } from '@angular/core'; +import { ThemedComponent } from '../theme-support/themed.component'; import { LoadingComponent } from './loading.component'; +import { ThemeService } from '../theme-support/theme.service'; /** * Themed wrapper for LoadingComponent @@ -17,6 +18,14 @@ export class ThemedLoadingComponent extends ThemedComponent { protected inAndOutputNames: (keyof LoadingComponent & keyof this)[] = ['message', 'showMessage']; + constructor( + protected resolver: ComponentFactoryResolver, + protected cdr: ChangeDetectorRef, + protected themeService: ThemeService + ) { + super(resolver, cdr, themeService); + } + protected getComponentName(): string { return 'LoadingComponent'; } From 5682c81217c5da5090ad6cbb4cb561cbca5cd84c Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 13 May 2022 13:45:49 +0200 Subject: [PATCH 022/103] 91272: Fixed import statements and position of expandable navbar button --- .../themed-expandable-navbar-section.component.ts | 4 ++-- src/app/navbar/navbar.component.html | 4 ++-- .../expandable-navbar-section.component.ts | 4 ++-- src/themes/dspace/app/navbar/navbar.component.html | 4 ++-- src/themes/dspace/styles/_global-styles.scss | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts index 744eeb5a02..e33dca4104 100644 --- a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts @@ -2,13 +2,13 @@ import { Component } from '@angular/core'; import { ThemedComponent } from '../../shared/theme-support/themed.component'; import { ExpandableNavbarSectionComponent } from './expandable-navbar-section.component'; import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator'; -import { MenuID } from '../../shared/menu/initial-menus-state'; +import { MenuID } from '../../shared/menu/menu-id.model'; /** * Themed wrapper for ExpandableNavbarSectionComponent */ @Component({ - /* tslint:disable:component-selector */ + /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-themed-expandable-navbar-section]', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 63f308fb32..b41f2ea706 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -4,7 +4,7 @@
-
- \ No newline at end of file + diff --git a/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index 283b9ca6f6..f7efd1fdca 100644 --- a/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -4,13 +4,13 @@ import { } from '../../../../../app/navbar/expandable-navbar-section/expandable-navbar-section.component'; import { slide } from '../../../../../app/shared/animations/slide'; import { rendersSectionForMenu } from '../../../../../app/shared/menu/menu-section.decorator'; -import { MenuID } from '../../../../../app/shared/menu/initial-menus-state'; +import { MenuID } from '../../../../../app/shared/menu/menu-id.model'; /** * Represents an expandable section in the navbar */ @Component({ - /* tslint:disable:component-selector */ + /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-expandable-navbar-section]', // templateUrl: './expandable-navbar-section.component.html', templateUrl: '../../../../../app/navbar/expandable-navbar-section/expandable-navbar-section.component.html', diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index 218fc368ba..6b71728494 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -6,7 +6,7 @@
-
- \ No newline at end of file + diff --git a/src/themes/dspace/styles/_global-styles.scss b/src/themes/dspace/styles/_global-styles.scss index 8682e3dcdf..3271f15bf2 100644 --- a/src/themes/dspace/styles/_global-styles.scss +++ b/src/themes/dspace/styles/_global-styles.scss @@ -23,8 +23,7 @@ } header { - li > .navbar-section, - li > .expandable-navbar-section { + .navbar-navigation > li { display: flex; flex-direction: column; justify-content: center; From e197e496b51aad5d05e4e6684a84cf435a1e15d4 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 13 May 2022 17:19:42 +0200 Subject: [PATCH 023/103] 91272: Fixed accessibility violation --- .../admin-sidebar-section/admin-sidebar-section.component.ts | 2 ++ .../expandable-admin-sidebar-section.component.ts | 2 ++ .../expandable-navbar-section.component.ts | 3 +-- src/app/navbar/navbar-section/navbar-section.component.ts | 2 ++ .../expandable-navbar-section.component.ts | 3 +-- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts index 47f693cb99..422431d2c5 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts @@ -14,6 +14,8 @@ import { Router } from '@angular/router'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-admin-sidebar-section]', + // To theme this element remove the surrounding li[] in this component but leave it in the new + // ThemedAdminSidebarSectionComponent templateUrl: './admin-sidebar-section.component.html', styleUrls: ['./admin-sidebar-section.component.scss'], diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts index 7cd20b15d2..28cadcac5f 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts @@ -17,6 +17,8 @@ import { Router } from '@angular/router'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-expandable-admin-sidebar-section]', + // To theme this element remove the surrounding li[] in this component but leave it in the new + // ThemedExpandableAdminSidebarSectionComponent templateUrl: './expandable-admin-sidebar-section.component.html', styleUrls: ['./expandable-admin-sidebar-section.component.scss'], animations: [rotate, slide, bgColor] diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index a6d3a52cd2..5bc69bcbb4 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -11,8 +11,7 @@ import { MenuID } from '../../shared/menu/menu-id.model'; * Represents an expandable section in the navbar */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-expandable-navbar-section]', + selector: 'ds-expandable-navbar-section', templateUrl: './expandable-navbar-section.component.html', styleUrls: ['./expandable-navbar-section.component.scss'], animations: [slide] diff --git a/src/app/navbar/navbar-section/navbar-section.component.ts b/src/app/navbar/navbar-section/navbar-section.component.ts index 9f75a96f6e..20d5299584 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.ts +++ b/src/app/navbar/navbar-section/navbar-section.component.ts @@ -10,6 +10,8 @@ import { MenuID } from '../../shared/menu/menu-id.model'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-navbar-section]', + // To theme this element remove the surrounding li[] in this component but leave it in the new + // ThemedNavbarSectionComponent templateUrl: './navbar-section.component.html', styleUrls: ['./navbar-section.component.scss'] }) diff --git a/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index f7efd1fdca..3e11271bf0 100644 --- a/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/themes/custom/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -10,8 +10,7 @@ import { MenuID } from '../../../../../app/shared/menu/menu-id.model'; * Represents an expandable section in the navbar */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-expandable-navbar-section]', + selector: 'ds-expandable-navbar-section', // templateUrl: './expandable-navbar-section.component.html', templateUrl: '../../../../../app/navbar/expandable-navbar-section/expandable-navbar-section.component.html', // styleUrls: ['./expandable-navbar-section.component.scss'], From 460efa42c732dc80979e8733793c439282141c1e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 13 May 2022 19:33:40 +0200 Subject: [PATCH 024/103] 91272: Fix merge request --- src/app/admin/admin-sidebar/admin-sidebar.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index 5febf93deb..d4071b91ed 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -41,7 +41,6 @@ import { FeatureID } from '../../core/data/feature-authorization/feature-id'; import { MenuID } from '../../shared/menu/menu-id.model'; import { MenuItemType } from '../../shared/menu/menu-item-type.model'; import { ActivatedRoute } from '@angular/router'; -import { Router, ActivatedRoute } from '@angular/router'; import { ThemeService } from '../../shared/theme-support/theme.service'; /** From 743513cf848a7db3c5ec1fc97817a07fd6cdc134 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 13 May 2022 20:35:08 +0200 Subject: [PATCH 025/103] 89676: Added empty SearchResultsComponent files --- .../shared/search/search-results/search-results.component.html | 0 .../shared/search/search-results/search-results.component.scss | 0 .../app/shared/search/search-results/search-results.component.ts | 1 + 3 files changed, 1 insertion(+) create mode 100644 src/themes/custom/app/shared/search/search-results/search-results.component.html create mode 100644 src/themes/custom/app/shared/search/search-results/search-results.component.scss diff --git a/src/themes/custom/app/shared/search/search-results/search-results.component.html b/src/themes/custom/app/shared/search/search-results/search-results.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/shared/search/search-results/search-results.component.scss b/src/themes/custom/app/shared/search/search-results/search-results.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/shared/search/search-results/search-results.component.ts b/src/themes/custom/app/shared/search/search-results/search-results.component.ts index bdfeea15a5..5084d4d405 100644 --- a/src/themes/custom/app/shared/search/search-results/search-results.component.ts +++ b/src/themes/custom/app/shared/search/search-results/search-results.component.ts @@ -6,6 +6,7 @@ import { fadeIn, fadeInOut } from '../../../../../../app/shared/animations/fade' selector: 'ds-search-results', // templateUrl: './search-results.component.html', templateUrl: '../../../../../../app/shared/search/search-results/search-results.component.html', + // styleUrls: ['./search-results.component.scss'], animations: [ fadeIn, fadeInOut From 3a483c393ddeeb94c90113bbd36320bf8abb3800 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 27 May 2022 16:32:23 +0200 Subject: [PATCH 026/103] 89721: Themed UntypedItemComponent --- .../untyped-item/untyped-item.component.html | 0 .../untyped-item/untyped-item.component.scss | 0 .../untyped-item/untyped-item.component.ts | 25 +++++++++++++++++++ src/themes/custom/entry-components.ts | 4 ++- src/themes/custom/theme.module.ts | 22 ++++++++++++---- 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.html create mode 100644 src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.scss create mode 100644 src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.ts diff --git a/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.html b/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.scss b/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.ts b/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.ts new file mode 100644 index 0000000000..1d1676e92f --- /dev/null +++ b/src/themes/custom/app/item-page/simple/item-types/untyped-item/untyped-item.component.ts @@ -0,0 +1,25 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { Item } from '../../../../../../../app/core/shared/item.model'; +import { ViewMode } from '../../../../../../../app/core/shared/view-mode.model'; +import { + listableObjectComponent +} from '../../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../../../../app/core/shared/context.model'; +import { + UntypedItemComponent as BaseComponent +} from '../../../../../../../app/item-page/simple/item-types/untyped-item/untyped-item.component'; + +/** + * Component that represents an untyped Item page + */ +@listableObjectComponent(Item, ViewMode.StandalonePage, Context.Any, 'custom') +@Component({ + selector: 'ds-untyped-item', + // styleUrls: ['./untyped-item.component.scss'], + styleUrls: ['../../../../../../../app/item-page/simple/item-types/untyped-item/untyped-item.component.scss'], + // templateUrl: './untyped-item.component.html', + templateUrl: '../../../../../../../app/item-page/simple/item-types/untyped-item/untyped-item.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class UntypedItemComponent extends BaseComponent { +} diff --git a/src/themes/custom/entry-components.ts b/src/themes/custom/entry-components.ts index b518e4cc45..9a9c0624a4 100644 --- a/src/themes/custom/entry-components.ts +++ b/src/themes/custom/entry-components.ts @@ -1,5 +1,7 @@ import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; +import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component'; export const ENTRY_COMPONENTS = [ - PublicationComponent + PublicationComponent, + UntypedItemComponent, ]; diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index e2e97b9087..c5d5e5a1c4 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -34,6 +34,7 @@ import { HomePageModule } from '../../app/home-page/home-page.module'; import { RootComponent } from './app/root/root.component'; import { AppModule } from '../../app/app.module'; import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; +import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component'; import { ItemPageModule } from '../../app/item-page/item-page.module'; import { RouterModule } from '@angular/router'; import { AccessControlModule } from '../../app/access-control/access-control.module'; @@ -47,8 +48,12 @@ import { PageNotFoundComponent } from './app/pagenotfound/pagenotfound.component import { ObjectNotFoundComponent } from './app/lookup-by-id/objectnotfound/objectnotfound.component'; import { ForbiddenComponent } from './app/forbidden/forbidden.component'; import { PrivacyComponent } from './app/info/privacy/privacy.component'; -import { CollectionStatisticsPageComponent } from './app/statistics-page/collection-statistics-page/collection-statistics-page.component'; -import { CommunityStatisticsPageComponent } from './app/statistics-page/community-statistics-page/community-statistics-page.component'; +import { + CollectionStatisticsPageComponent +} from './app/statistics-page/collection-statistics-page/collection-statistics-page.component'; +import { + CommunityStatisticsPageComponent +} from './app/statistics-page/community-statistics-page/community-statistics-page.component'; import { StatisticsPageModule } from '../../app/statistics-page/statistics-page.module'; import { ItemStatisticsPageComponent } from './app/statistics-page/item-statistics-page/item-statistics-page.component'; import { SiteStatisticsPageComponent } from './app/statistics-page/site-statistics-page/site-statistics-page.component'; @@ -67,11 +72,17 @@ import { ForgotPasswordFormComponent } from './app/forgot-password/forgot-passwo import { ProfilePageComponent } from './app/profile-page/profile-page.component'; import { RegisterEmailComponent } from './app/register-page/register-email/register-email.component'; import { SubmissionEditComponent } from './app/submission/edit/submission-edit.component'; -import { SubmissionImportExternalComponent } from './app/submission/import-external/submission-import-external.component'; +import { + SubmissionImportExternalComponent +} from './app/submission/import-external/submission-import-external.component'; import { SubmissionSubmitComponent } from './app/submission/submit/submission-submit.component'; import { MyDSpacePageComponent } from './app/my-dspace-page/my-dspace-page.component'; -import { WorkflowItemSendBackComponent } from './app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component'; -import { WorkflowItemDeleteComponent } from './app/workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component'; +import { + WorkflowItemSendBackComponent +} from './app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component'; +import { + WorkflowItemDeleteComponent +} from './app/workflowitems-edit-page/workflow-item-delete/workflow-item-delete.component'; import { SubmissionModule } from '../../app/submission/submission.module'; import { MyDSpacePageModule } from '../../app/my-dspace-page/my-dspace-page.module'; import { NavbarComponent } from './app/navbar/navbar.component'; @@ -91,6 +102,7 @@ const DECLARATIONS = [ HomeNewsComponent, RootComponent, PublicationComponent, + UntypedItemComponent, BrowseBySwitcherComponent, CommunityListPageComponent, SearchPageComponent, From 533e4c982f43f2859951479c1302b3343226941d Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 2 Jun 2022 10:22:46 +0200 Subject: [PATCH 027/103] 91272: Small fixes --- .../listable-object-component-loader.component.ts | 2 ++ .../app/info/end-user-agreement/end-user-agreement.component.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts index 8adbcbeec3..9c7ad5f659 100644 --- a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts @@ -128,6 +128,8 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges 'context', 'viewMode', 'value', + 'hideBadges', + 'contentChange', ]; constructor( diff --git a/src/themes/custom/app/info/end-user-agreement/end-user-agreement.component.ts b/src/themes/custom/app/info/end-user-agreement/end-user-agreement.component.ts index e3e5ac8d19..50e196bfaf 100644 --- a/src/themes/custom/app/info/end-user-agreement/end-user-agreement.component.ts +++ b/src/themes/custom/app/info/end-user-agreement/end-user-agreement.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { EndUserAgreementComponent as BaseComponent } from '../../../../../app/info/end-user-agreement/end-user-agreement.component'; @Component({ - selector: 'ds-home-news', + selector: 'ds-end-user-agreement', // styleUrls: ['./end-user-agreement.component.scss'], styleUrls: ['../../../../../app/info/end-user-agreement/end-user-agreement.component.scss'], // templateUrl: './end-user-agreement.component.html' From 2441db16e93a500f8ed4849537be918d86696086 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 27 May 2022 18:53:56 +0200 Subject: [PATCH 028/103] 89721: Themed JournalIssueComponent --- .../journal-issue.component.html | 0 .../journal-issue.component.scss | 0 .../journal-issue/journal-issue.component.ts | 23 +++++++++++++++++++ src/themes/custom/entry-components.ts | 4 ++++ src/themes/custom/theme.module.ts | 6 ++++- 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.scss create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.scss b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts new file mode 100644 index 0000000000..a9f23c25f6 --- /dev/null +++ b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../../../app/core/shared/view-mode.model'; +import { + listableObjectComponent +} from '../../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { + JournalIssueComponent as BaseComponent +} from '../../../../../../../app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; +import { Context } from '../../../../../../../app/core/shared/context.model'; + +@listableObjectComponent('JournalIssue', ViewMode.StandalonePage, Context.Any, 'custom') +@Component({ + selector: 'ds-journal-issue', + // styleUrls: ['./journal-issue.component.scss'], + styleUrls: ['../../../../../../../app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.scss'], + // templateUrl: './journal-issue.component.html', + templateUrl: '../../../../../../../app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html', +}) +/** + * The component for displaying metadata and relations of an item of the type Journal Issue + */ +export class JournalIssueComponent extends BaseComponent { +} diff --git a/src/themes/custom/entry-components.ts b/src/themes/custom/entry-components.ts index 9a9c0624a4..b5c4469718 100644 --- a/src/themes/custom/entry-components.ts +++ b/src/themes/custom/entry-components.ts @@ -1,7 +1,11 @@ +import { + JournalIssueComponent +} from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component'; export const ENTRY_COMPONENTS = [ + JournalIssueComponent, PublicationComponent, UntypedItemComponent, ]; diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index c5d5e5a1c4..5fb1ce580b 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -95,6 +95,9 @@ 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'; import { FeedbackComponent } from './app/info/feedback/feedback.component'; +import { + JournalIssueComponent +} from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; const DECLARATIONS = [ FileSectionComponent, @@ -138,7 +141,8 @@ const DECLARATIONS = [ NavbarComponent, HeaderNavbarWrapperComponent, BreadcrumbsComponent, - FeedbackComponent + FeedbackComponent, + JournalIssueComponent, ]; @NgModule({ From 2264067240e3d7302878e59fae02e27fc65d096e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 27 May 2022 19:12:03 +0200 Subject: [PATCH 029/103] 89721: Themed JournalVolumeComponent --- .../journal-volume.component.html | 0 .../journal-volume.component.scss | 0 .../journal-volume.component.ts | 23 +++++++++++++++++++ src/themes/custom/entry-components.ts | 4 ++++ src/themes/custom/theme.module.ts | 4 ++++ 5 files changed, 31 insertions(+) create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.scss create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.scss b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts new file mode 100644 index 0000000000..1a190dc2e8 --- /dev/null +++ b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../../../app/core/shared/view-mode.model'; +import { + listableObjectComponent +} from '../../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { + JournalVolumeComponent as BaseComponent +} from '../../../../../../../app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component'; +import { Context } from '../../../../../../../app/core/shared/context.model'; + +@listableObjectComponent('JournalVolume', ViewMode.StandalonePage, Context.Any, 'custom') +@Component({ + selector: 'ds-journal-volume', + // styleUrls: ['./journal-volume.component.scss'], + styleUrls: ['../../../../../../../app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.scss'], + // templateUrl: './journal-volume.component.html', + templateUrl: '../../../../../../../app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html', +}) +/** + * The component for displaying metadata and relations of an item of the type Journal Volume + */ +export class JournalVolumeComponent extends BaseComponent { +} diff --git a/src/themes/custom/entry-components.ts b/src/themes/custom/entry-components.ts index b5c4469718..8f24a3b7e6 100644 --- a/src/themes/custom/entry-components.ts +++ b/src/themes/custom/entry-components.ts @@ -1,11 +1,15 @@ import { JournalIssueComponent } from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; +import { + JournalVolumeComponent +} from './app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component'; import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component'; export const ENTRY_COMPONENTS = [ JournalIssueComponent, + JournalVolumeComponent, PublicationComponent, UntypedItemComponent, ]; diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index 5fb1ce580b..3193b200af 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -98,6 +98,9 @@ import { FeedbackComponent } from './app/info/feedback/feedback.component'; import { JournalIssueComponent } from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; +import { + JournalVolumeComponent +} from './app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component'; const DECLARATIONS = [ FileSectionComponent, @@ -143,6 +146,7 @@ const DECLARATIONS = [ BreadcrumbsComponent, FeedbackComponent, JournalIssueComponent, + JournalVolumeComponent, ]; @NgModule({ From bca332a23aed34b5e96ea6cfae8cfccd92173fc3 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Mon, 30 May 2022 10:12:04 +0200 Subject: [PATCH 030/103] 89721: Themed JournalComponent --- .../item-pages/journal/journal.component.html | 0 .../item-pages/journal/journal.component.scss | 0 .../item-pages/journal/journal.component.ts | 23 +++++++++++++++++++ src/themes/custom/entry-components.ts | 2 ++ src/themes/custom/theme.module.ts | 6 ++++- 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.html create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.scss create mode 100644 src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.html b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.scss b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts new file mode 100644 index 0000000000..7b64c1a35d --- /dev/null +++ b/src/themes/custom/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../../../app/core/shared/view-mode.model'; +import { + listableObjectComponent +} from '../../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { + JournalComponent as BaseComponent +} from '../../../../../../../app/entity-groups/journal-entities/item-pages/journal/journal.component'; +import { Context } from '../../../../../../../app/core/shared/context.model'; + +@listableObjectComponent('Journal', ViewMode.StandalonePage, Context.Any, 'custom') +@Component({ + selector: 'ds-journal', + // styleUrls: ['./journal.component.scss'], + styleUrls: ['../../../../../../../app/entity-groups/journal-entities/item-pages/journal/journal.component.scss'], + // templateUrl: './journal.component.html', + templateUrl: '../../../../../../../app/entity-groups/journal-entities/item-pages/journal/journal.component.html', +}) +/** + * The component for displaying metadata and relations of an item of the type Journal + */ +export class JournalComponent extends BaseComponent { +} diff --git a/src/themes/custom/entry-components.ts b/src/themes/custom/entry-components.ts index 8f24a3b7e6..ca4c40f523 100644 --- a/src/themes/custom/entry-components.ts +++ b/src/themes/custom/entry-components.ts @@ -1,3 +1,4 @@ +import { JournalComponent } from './app/entity-groups/journal-entities/item-pages/journal/journal.component'; import { JournalIssueComponent } from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; @@ -8,6 +9,7 @@ import { PublicationComponent } from './app/item-page/simple/item-types/publicat import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component'; export const ENTRY_COMPONENTS = [ + JournalComponent, JournalIssueComponent, JournalVolumeComponent, PublicationComponent, diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index 3193b200af..b42dfa80ac 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -95,12 +95,14 @@ 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'; import { FeedbackComponent } from './app/info/feedback/feedback.component'; +import { JournalComponent } from './app/entity-groups/journal-entities/item-pages/journal/journal.component'; import { JournalIssueComponent } from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component'; import { JournalVolumeComponent } from './app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component'; +import { ItemSharedModule } from '../../app/item-page/item-shared.module'; const DECLARATIONS = [ FileSectionComponent, @@ -145,6 +147,7 @@ const DECLARATIONS = [ HeaderNavbarWrapperComponent, BreadcrumbsComponent, FeedbackComponent, + JournalComponent, JournalIssueComponent, JournalVolumeComponent, ]; @@ -196,7 +199,8 @@ const DECLARATIONS = [ SearchModule, FormsModule, ResourcePoliciesModule, - ComcolModule + ComcolModule, + ItemSharedModule, ], declarations: DECLARATIONS }) From dc5d46993e33f31d5c35b52777fc544c1d372d84 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 27 May 2022 11:14:28 +0200 Subject: [PATCH 031/103] 89721: Themed AdminSidebarComponent --- .../admin-sidebar/admin-sidebar.component.html | 0 .../admin-sidebar/admin-sidebar.component.scss | 0 .../admin-sidebar/admin-sidebar.component.ts | 15 +++++++++++++++ src/themes/custom/theme.module.ts | 2 ++ 4 files changed, 17 insertions(+) create mode 100644 src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.html create mode 100644 src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.scss create mode 100644 src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.ts diff --git a/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.html b/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.scss b/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.ts new file mode 100644 index 0000000000..6485ad98e6 --- /dev/null +++ b/src/themes/custom/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { AdminSidebarComponent as BaseComponent } from '../../../../../app/admin/admin-sidebar/admin-sidebar.component'; + +/** + * Component representing the admin sidebar + */ +@Component({ + selector: 'ds-admin-sidebar', + // templateUrl: './admin-sidebar.component.html', + templateUrl: '../../../../../app/admin/admin-sidebar/admin-sidebar.component.html', + // styleUrls: ['./admin-sidebar.component.scss'] + styleUrls: ['../../../../../app/admin/admin-sidebar/admin-sidebar.component.scss'] +}) +export class AdminSidebarComponent extends BaseComponent { +} diff --git a/src/themes/custom/theme.module.ts b/src/themes/custom/theme.module.ts index b42dfa80ac..95203336dd 100644 --- a/src/themes/custom/theme.module.ts +++ b/src/themes/custom/theme.module.ts @@ -103,6 +103,7 @@ import { JournalVolumeComponent } from './app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component'; import { ItemSharedModule } from '../../app/item-page/item-shared.module'; +import { AdminSidebarComponent } from './app/admin/admin-sidebar/admin-sidebar.component'; const DECLARATIONS = [ FileSectionComponent, @@ -150,6 +151,7 @@ const DECLARATIONS = [ JournalComponent, JournalIssueComponent, JournalVolumeComponent, + AdminSidebarComponent, ]; @NgModule({ From fc1e6b6b852da9fc635144caf84da08ddaaa5f8e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 3 Jun 2022 11:47:46 +0200 Subject: [PATCH 032/103] Removed comments for how to theme li[Component] --- .../admin-sidebar-section/admin-sidebar-section.component.ts | 2 -- .../expandable-admin-sidebar-section.component.ts | 2 -- src/app/navbar/navbar-section/navbar-section.component.ts | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts index 422431d2c5..47f693cb99 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts @@ -14,8 +14,6 @@ import { Router } from '@angular/router'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-admin-sidebar-section]', - // To theme this element remove the surrounding li[] in this component but leave it in the new - // ThemedAdminSidebarSectionComponent templateUrl: './admin-sidebar-section.component.html', styleUrls: ['./admin-sidebar-section.component.scss'], diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts index 28cadcac5f..7cd20b15d2 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts @@ -17,8 +17,6 @@ import { Router } from '@angular/router'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-expandable-admin-sidebar-section]', - // To theme this element remove the surrounding li[] in this component but leave it in the new - // ThemedExpandableAdminSidebarSectionComponent templateUrl: './expandable-admin-sidebar-section.component.html', styleUrls: ['./expandable-admin-sidebar-section.component.scss'], animations: [rotate, slide, bgColor] diff --git a/src/app/navbar/navbar-section/navbar-section.component.ts b/src/app/navbar/navbar-section/navbar-section.component.ts index 20d5299584..9f75a96f6e 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.ts +++ b/src/app/navbar/navbar-section/navbar-section.component.ts @@ -10,8 +10,6 @@ import { MenuID } from '../../shared/menu/menu-id.model'; @Component({ /* eslint-disable @angular-eslint/component-selector */ selector: 'li[ds-navbar-section]', - // To theme this element remove the surrounding li[] in this component but leave it in the new - // ThemedNavbarSectionComponent templateUrl: './navbar-section.component.html', styleUrls: ['./navbar-section.component.scss'] }) From 5bf34b868cabce3d87d2bf64a704a1617b6b3e7b Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 10 Jun 2022 13:08:36 +0200 Subject: [PATCH 033/103] added missing keys workspace.search.results.head and workflow.search.results.head --- src/assets/i18n/de.json5 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 23ab3a29e5..526da437b0 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -5358,10 +5358,14 @@ "virtual-metadata.delete-relationship.modal-head": "Wählen Sie die Items aus, deren virtuelle Metadaten Sie als echte Metadaten speichern möchten.", - + // "workspace.search.results.head": "Your submissions", + "workspace.search.results.head": "Deine Einreichungen", + // "workflowAdmin.search.results.head": "Administer Workflow", "workflowAdmin.search.results.head": "Workflow verwalten", - + + // "workflow.search.results.head": "Workflow tasks", + "workflow.search.results.head": "Workflow-Aufgaben", // "workflow-item.delete.notification.success.title": "Deleted", From afe798942bf39f39ef055bd4246d6e4be6692b7f Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 10 Jun 2022 13:15:53 +0200 Subject: [PATCH 034/103] =?UTF-8?q?harmonized=20german=20translations=20("?= =?UTF-8?q?Ihre=20Ver=C3=B6ffentlichungen")?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/i18n/de.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 526da437b0..42e0d083e7 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -5359,7 +5359,7 @@ // "workspace.search.results.head": "Your submissions", - "workspace.search.results.head": "Deine Einreichungen", + "workspace.search.results.head": "Ihre Veröffentlichungen", // "workflowAdmin.search.results.head": "Administer Workflow", "workflowAdmin.search.results.head": "Workflow verwalten", From 68d162432b114425d3d96da1b238a986e3414d6d Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Fri, 10 Jun 2022 14:22:52 +0200 Subject: [PATCH 035/103] added two missing keys --- src/assets/i18n/de.json5 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 42e0d083e7..effe6932fd 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -5279,6 +5279,13 @@ // "submission.workflow.tasks.pool.show-detail": "Show detail", "submission.workflow.tasks.pool.show-detail": "Details anzeigen", + // "submission.workspace.generic.view": "View", + "submission.workspace.generic.view": "Anzeige", + + // "submission.workspace.generic.view-help": "Select this option to view the item's metadata.", + "submission.workspace.generic.view-help": "Wählen Sie diese Option, um die Metadaten des Items anzuzeigen.", + + // "thumbnail.default.alt": "Thumbnail Image", "thumbnail.default.alt": "Vorschaubild", From 02b124f7dd0f0dcf222e86c8c335d357f556b3d8 Mon Sep 17 00:00:00 2001 From: nikunj59 Date: Mon, 13 Jun 2022 17:38:07 +0530 Subject: [PATCH 036/103] CST-6056 changes for filter result not working while lookup from text input --- .../search-facet-option.component.html | 4 +-- .../search-facet-filter.component.ts | 29 +++++++++---------- .../search-hierarchy-filter.component.html | 2 +- .../search-hierarchy-filter.component.ts | 5 +++- .../search-text-filter.component.html | 2 +- .../search-text-filter.component.ts | 5 +++- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html index e2e57e7370..3c15eff127 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html @@ -9,6 +9,6 @@ - {{filterValue.count}} - + {{filterValue.count}} + 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 4f226add54..edcd88cd21 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 @@ -236,22 +236,21 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { onSubmit(data: any) { if (data.match(new RegExp(`^.+,(equals|query|authority)$`))) { this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { - if (isNotEmpty(data)) { - this.router.navigate(this.getSearchLinkParts(), { - queryParams: - { - [this.filterConfig.paramName]: [ - ...selectedValues.map((facet) => this.getFacetValue(facet)), - data - ] - }, - queryParamsHandling: 'merge' - }); - this.filter = ''; - } - this.filterSearchResults = observableOf([]); + if (isNotEmpty(data)) { + this.router.navigate(this.getSearchLinkParts(), { + queryParams: + { + [this.filterConfig.paramName]: [ + ...selectedValues.map((facet) => this.getFacetValue(facet)), + data + ] + }, + queryParamsHandling: 'merge' + }); + this.filter = ''; } - ); + this.filterSearchResults = observableOf([]); + }); } } diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html index 49ca6fe3fd..02f2bc6336 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html @@ -24,7 +24,7 @@ [name]="filterConfig.paramName" [(ngModel)]="filter" (submitSuggestion)="onSubmit($event)" - (clickSuggestion)="onClick($event)" + (clickSuggestion)="onSubmit($event)" (findSuggestions)="findSuggestions($event)" ngDefaultControl > 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 b3349a5dd9..a6e9fb4a00 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 @@ -3,6 +3,7 @@ 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 { addOperatorToFilterValue } from '../../../search.utils'; +import { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; @Component({ selector: 'ds-search-hierarchy-filter', @@ -22,6 +23,8 @@ export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent i * @param data The string from the input field */ onSubmit(data: any) { - super.onSubmit(addOperatorToFilterValue(data, 'query')); + this.filterSearchResults.subscribe((filterSearchResults: InputSuggestion[]) => { + super.onSubmit(addOperatorToFilterValue(data, filterSearchResults.length ? 'equals' : 'query')); + }); } } diff --git a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html index fdf154bc04..44aed494e3 100644 --- a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html @@ -24,7 +24,7 @@ [name]="filterConfig.paramName" [(ngModel)]="filter" (submitSuggestion)="onSubmit($event)" - (clickSuggestion)="onClick($event)" + (clickSuggestion)="onSubmit($event)" (findSuggestions)="findSuggestions($event)" ngDefaultControl> 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 cfd81c3750..62c10e4c61 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 @@ -3,6 +3,7 @@ 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 { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; /** * This component renders a simple item page. @@ -28,6 +29,8 @@ export class SearchTextFilterComponent extends SearchFacetFilterComponent implem * @param data The string from the input field */ onSubmit(data: any) { - super.onSubmit(addOperatorToFilterValue(data, 'query')); + this.filterSearchResults.subscribe((filterSearchResults: InputSuggestion[]) => { + super.onSubmit(addOperatorToFilterValue(data, filterSearchResults.length ? 'equals' : 'query')); + }); } } From e04404bdd6d9ec197c2c5c406b999ddc1ded5b46 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 13 Jun 2022 17:05:41 +0200 Subject: [PATCH 037/103] [CST-5339] use ds-alert for info box --- .../orcid-page/orcid-queue/orcid-queue.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index 81e30bc013..854bac3669 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -5,10 +5,10 @@
-
+ {{ 'person.page.orcid.sync-queue.empty-message' | translate}} -
+ @@ -55,5 +55,5 @@
- + From f39283cae587c5b5de78053b56f4d58c1237dd9d Mon Sep 17 00:00:00 2001 From: nikunj59 Date: Tue, 14 Jun 2022 14:56:41 +0530 Subject: [PATCH 038/103] CST-6051 changes description tool tip and truncate text --- .../item-bitstreams/item-bitstreams.component.scss | 4 ++++ .../item-edit-bitstream/item-edit-bitstream.component.html | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss index 46d172dadc..7de575b785 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss @@ -50,3 +50,7 @@ cursor: grabbing; } } + +:host ::ng-deep .larger-tooltip .tooltip-inner { + max-width: 500px; +} diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html index 5d1edb847f..0f0fad2199 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html @@ -9,9 +9,10 @@
- - {{ bitstream?.firstMetadataValue('dc.description') }} - +
+ {{ bitstream?.firstMetadataValue('dc.description') }} +
From 9850174fa2ed3a55620fd22777a217d296af3990 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 12:13:07 +0200 Subject: [PATCH 039/103] [CST-5339] ORCID registry queue table reformatted --- angular.json | 3 +- .../orcid-queue/orcid-queue.component.html | 107 +++++++++--------- .../orcid-queue/orcid-queue.component.ts | 19 +++- src/assets/i18n/en.json5 | 8 +- 4 files changed, 74 insertions(+), 63 deletions(-) diff --git a/angular.json b/angular.json index 56e06bd86c..2ece0c5e7d 100644 --- a/angular.json +++ b/angular.json @@ -63,7 +63,8 @@ "bundleName": "dspace-theme" } ], - "scripts": [] + "scripts": [], + "baseHref": "/" }, "configurations": { "development": { diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index 854bac3669..d21575e31c 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -1,59 +1,60 @@
- - - -
- + + + +
+ - - {{ 'person.page.orcid.sync-queue.empty-message' | translate}} - - + + {{ 'person.page.orcid.sync-queue.empty-message' | translate}} + + -
- - - - - - - - - - - - - -
{{'person.page.orcid.sync-queue.description' | translate}}
- {{ entry.description }} - -
- - - - -
-
+
+ + + + + + + + + + + + + + + +
{{'person.page.orcid.sync-queue.table.header.type' | translate}}{{'person.page.orcid.sync-queue.table.header.description' | translate}}{{'person.page.orcid.sync-queue.table.header.action' | translate}}
+ + + {{ entry.description }} + +
+ + +
- +
- - - + +
+ + +
diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 01639a427c..a80ff851fb 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; @@ -14,13 +14,14 @@ import { getFinishedRemoteData, getFirstCompletedRemoteData } from '../../../cor import { hasValue } from '../../../shared/empty.util'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { AlertType } from '../../../shared/alert/aletr-type'; @Component({ selector: 'ds-orcid-queue', templateUrl: './orcid-queue.component.html', styleUrls: ['./orcid-queue.component.scss'] }) -export class OrcidQueueComponent implements OnInit { +export class OrcidQueueComponent implements OnInit, OnDestroy { /** * Pagination config used to display the list */ @@ -39,6 +40,12 @@ export class OrcidQueueComponent implements OnInit { */ private list$: BehaviorSubject>> = new BehaviorSubject>>({} as any); + /** + * The AlertType enumeration + * @type {AlertType} + */ + AlertTypeEnum = AlertType; + /** * Array to track all subscriptions and unsubscribe them onDestroy * @type {Array} @@ -84,13 +91,13 @@ export class OrcidQueueComponent implements OnInit { } switch (orcidQueue.recordType.toLowerCase()) { case 'publication': - return 'fa fa-book'; + return 'fas fa-book'; case 'funding': - return 'fa fa-wallet'; + return 'fas fa-wallet'; case 'education': - return 'fa fa-school'; + return 'fas fa-school'; case 'affiliation': - return 'fa fa-university'; + return 'fas fa-university'; case 'country': return 'fas fa-globe-europe'; case 'external_ids': diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index bddc705cb8..d29c31aef8 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4481,8 +4481,6 @@ "researcherprofile.success.claim.title" : "Success", - "person.page.orcid": "ORCID", - "person.page.orcid.create": "Create an ORCID ID", "person.page.orcid.granted-authorizations": "Granted authorizations", @@ -4547,7 +4545,11 @@ "person.page.orcid.sync-queue.empty-message": "The ORCID queue registry is empty", - "person.page.orcid.sync-queue.description" : "Description", + "person.page.orcid.sync-queue.table.header.type" : "Type", + + "person.page.orcid.sync-queue.table.header.description" : "Description", + + "person.page.orcid.sync-queue.table.header.action" : "Action", "person.page.orcid.sync-queue.description.affiliation": "Affiliations", From 383703a4d6c2ab102b391018b9c4faeaf5d30723 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 12:29:38 +0200 Subject: [PATCH 040/103] [CST-5339] Lint errors --- src/app/core/orcid/model/orcid-history.model.ts | 2 +- src/app/core/orcid/model/orcid-queue.model.ts | 2 +- src/app/core/orcid/orcid-history.service.ts | 14 +++++--------- .../orcid-queue/orcid-queue.component.ts | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/app/core/orcid/model/orcid-history.model.ts b/src/app/core/orcid/model/orcid-history.model.ts index 01b5d027e9..fd7f73b9fa 100644 --- a/src/app/core/orcid/model/orcid-history.model.ts +++ b/src/app/core/orcid/model/orcid-history.model.ts @@ -4,7 +4,7 @@ import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; import { excludeFromEquals } from '../../utilities/equals.decorators'; import { ORCID_HISTORY } from './orcid-history.resource-type'; -import {CacheableObject} from "../../cache/cacheable-object.model"; +import { CacheableObject } from '../../cache/cacheable-object.model'; /** * Class the represents a Orcid History. diff --git a/src/app/core/orcid/model/orcid-queue.model.ts b/src/app/core/orcid/model/orcid-queue.model.ts index 7294a6b736..f967772208 100644 --- a/src/app/core/orcid/model/orcid-queue.model.ts +++ b/src/app/core/orcid/model/orcid-queue.model.ts @@ -4,7 +4,7 @@ import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; import { excludeFromEquals } from '../../utilities/equals.decorators'; import { ORCID_QUEUE } from './orcid-queue.resource-type'; -import {CacheableObject} from "../../cache/cacheable-object.model"; +import { CacheableObject } from '../../cache/cacheable-object.model'; /** * Class the represents a Orcid Queue. diff --git a/src/app/core/orcid/orcid-history.service.ts b/src/app/core/orcid/orcid-history.service.ts index 9d86763466..6658c63c9f 100644 --- a/src/app/core/orcid/orcid-history.service.ts +++ b/src/app/core/orcid/orcid-history.service.ts @@ -1,17 +1,13 @@ -/* tslint:disable:max-classes-per-file */ - +// eslint-disable-next-line max-classes-per-file import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; -import { catchError, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'; -import { isNotEmpty } from '../../shared/empty.util'; +import { map, switchMap } from 'rxjs/operators'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { createFailedRemoteDataObject$ } from '../../shared/remote-data.utils'; import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { RestResponse } from '../cache/response.models'; import { DataService } from '../data/data.service'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; import { ItemDataService } from '../data/item-data.service'; @@ -23,9 +19,9 @@ import { OrcidHistory } from './model/orcid-history.model'; import { ORCID_HISTORY } from './model/orcid-history.resource-type'; import { OrcidQueue } from './model/orcid-queue.model'; import { HttpOptions } from '../dspace-rest/dspace-rest.service'; -import {CoreState} from "../core-state.model"; -import {RestRequest} from "../data/rest-request.model"; -import {sendRequest} from "../shared/request.operators"; +import { CoreState } from '../core-state.model'; +import { RestRequest } from '../data/rest-request.model'; +import { sendRequest } from '../shared/request.operators'; /** * A private DataService implementation to delegate specific methods to. diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index a80ff851fb..7a742471b7 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -230,7 +230,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { } combineLatest(translations).subscribe((messages) => { const title = messages.shift(); - const content = '
    ' + messages.map((message) => '
  • ' + message + '
  • ').join('') + '
'; + const content = '
    ' + messages.map((message) => `
  • ${message}
  • `).join('') + '
'; this.notificationsService.error(title, content, { timeOut: -1 }, true); }); } From d779521dc95caab1e79700c0f43bb23b8d96fe9c Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 12:31:20 +0200 Subject: [PATCH 041/103] [CST-5339] Lint errors --- src/app/core/orcid/orcid-queue.service.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/core/orcid/orcid-queue.service.ts b/src/app/core/orcid/orcid-queue.service.ts index 4803c78560..0da9ac227c 100644 --- a/src/app/core/orcid/orcid-queue.service.ts +++ b/src/app/core/orcid/orcid-queue.service.ts @@ -1,5 +1,4 @@ -/* tslint:disable:max-classes-per-file */ - +// eslint-disable-next-line max-classes-per-file import { DataService } from '../data/data.service'; import { OrcidQueue } from './model/orcid-queue.model'; import { RequestService } from '../data/request.service'; @@ -25,7 +24,7 @@ import { map } from 'rxjs/operators'; import { getFirstSucceededRemoteDataPayload } from '../shared/operators'; import { environment } from '../../../environments/environment'; import { Router } from '@angular/router'; -import {CoreState} from "../core-state.model"; +import { CoreState } from '../core-state.model'; /** * A private DataService implementation to delegate specific methods to. @@ -95,7 +94,7 @@ export class OrcidQueueService { * @returns { NoContent } */ deleteById(orcidQueueId: number): Observable> { - return this.dataService.delete(orcidQueueId + ''); + return this.dataService.delete(orcidQueueId.toString()); } /** From 851855fc2a4d20744dad87aa6bded644488f7af8 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 17:44:57 +0200 Subject: [PATCH 042/103] [CST-5339] Tests (WIP) --- .../orcid-queue/orcid-queue.component.spec.ts | 89 +++++++++++++++++++ .../orcid-queue/orcid-queue.component.ts | 6 +- src/app/shared/testing/active-router.stub.ts | 1 + 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts new file mode 100644 index 0000000000..0c6895b74c --- /dev/null +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -0,0 +1,89 @@ +import { OrcidQueueComponent } from './orcid-queue.component'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { OrcidQueueService } from '../../../core/orcid/orcid-queue.service'; +import { PaginationService } from '../../../core/pagination/pagination.service'; +import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; +import { OrcidHistoryService } from '../../../core/orcid/orcid-history.service'; +import { ActivatedRoute, Params } from '@angular/router'; +import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; +import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; +import { createPaginatedList } from '../../../shared/testing/utils.test'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; + +fdescribe('OrcidQueueComponent test suite', () => { + let comp: OrcidQueueComponent; + let fixture: ComponentFixture; + let orcidQueueService: OrcidQueueService; + + const testOwnerId = 'test-owner-id'; + + const routeParams: Params = {'id': testOwnerId}; + + const activatedRouteStub = new ActivatedRouteStub(routeParams); + + function orcidQueueElement(id: number) { + return Object.assign(new OrcidQueue(), { + 'id': id, + 'ownerId': testOwnerId, + 'entityId': `test-entity-${id}`, + 'description': `test description ${id}`, + 'recordType': 'Publication', + 'operation': 'INSERT', + 'type': 'orcidqueue', + }); + } + + const orcidQueueElements = [orcidQueueElement(1), orcidQueueElement(2)]; + + const orcidQueueServiceMock = { + searchByOwnerId(id) { + return createSuccessfulRemoteDataObject$>(createPaginatedList(orcidQueueElements)); + }, + clearFindByOwnerRequests() { + return null; + } + }; + + beforeEach(waitForAsync(() => { + void TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + RouterTestingModule.withRoutes([]) + ], + declarations: [OrcidQueueComponent], + providers: [ + { provide: OrcidQueueService, useValue: orcidQueueServiceMock }, + { provide: OrcidHistoryService, useValue: {} }, + { provide: PaginationService, useValue: new PaginationServiceStub() }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + + orcidQueueService = TestBed.inject(OrcidQueueService); + })); + + beforeEach(waitForAsync(() => { + fixture = TestBed.createComponent(OrcidQueueComponent); + comp = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(comp).toBeTruthy(); + }); + +}); diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 7a742471b7..0dd2f8517c 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -25,7 +25,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { /** * Pagination config used to display the list */ - public paginationOptions: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + public paginationOptions: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { id: 'oqp', pageSize: 5 }); @@ -57,7 +57,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { private route: ActivatedRoute, private notificationsService: NotificationsService, private orcidHistoryService: OrcidHistoryService, - ) { } + ) { } ngOnInit(): void { this.updateList(); @@ -81,7 +81,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { /** * Return the list of orcid queue records */ - getList(): Observable>> { + getList(): Observable>> { return this.list$.asObservable(); } diff --git a/src/app/shared/testing/active-router.stub.ts b/src/app/shared/testing/active-router.stub.ts index aa4bfce438..13cb81b42e 100644 --- a/src/app/shared/testing/active-router.stub.ts +++ b/src/app/shared/testing/active-router.stub.ts @@ -54,6 +54,7 @@ export class ActivatedRouteStub { get snapshot() { return { params: this.testParams, + paramMap: convertToParamMap(this.params), queryParamMap: convertToParamMap(this.testParams) }; } From adcef89c29e3b9becda7ae2167a894ba46d02794 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 18:21:06 +0200 Subject: [PATCH 043/103] [CST-5339] Tests (WIP) --- .../orcid-queue/orcid-queue.component.spec.ts | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index 0c6895b74c..f85feb853d 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock'; import { RouterTestingModule } from '@angular/router/testing'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { OrcidQueueService } from '../../../core/orcid/orcid-queue.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; @@ -16,10 +16,13 @@ import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { createPaginatedList } from '../../../shared/testing/utils.test'; import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { By } from '@angular/platform-browser'; + fdescribe('OrcidQueueComponent test suite', () => { - let comp: OrcidQueueComponent; + let component: OrcidQueueComponent; let fixture: ComponentFixture; + let debugElement: DebugElement; let orcidQueueService: OrcidQueueService; const testOwnerId = 'test-owner-id'; @@ -76,14 +79,20 @@ fdescribe('OrcidQueueComponent test suite', () => { orcidQueueService = TestBed.inject(OrcidQueueService); })); - beforeEach(waitForAsync(() => { + beforeEach(() => { fixture = TestBed.createComponent(OrcidQueueComponent); - comp = fixture.componentInstance; + component = fixture.componentInstance; + debugElement = fixture.debugElement; fixture.detectChanges(); - })); + }); it('should create', () => { - expect(comp).toBeTruthy(); + expect(component).toBeTruthy(); + }); + + it('should ...', () => { + const table = debugElement.queryAll(By.css('table')); + expect(table.length).toBe(1); }); }); From 3adf846786f094acf8fee8caa3d11394b3701f07 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 18:56:18 +0200 Subject: [PATCH 044/103] [CST-5339] Pass item as input - Tests --- .../orcid-page/orcid-page.component.html | 2 +- .../orcid-queue/orcid-queue.component.html | 109 +++++++++--------- .../orcid-queue/orcid-queue.component.spec.ts | 83 ++++++++++--- .../orcid-queue/orcid-queue.component.ts | 15 ++- 4 files changed, 128 insertions(+), 81 deletions(-) diff --git a/src/app/item-page/orcid-page/orcid-page.component.html b/src/app/item-page/orcid-page/orcid-page.component.html index 3bb4a0737c..7fb1ae3a71 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.html +++ b/src/app/item-page/orcid-page/orcid-page.component.html @@ -10,4 +10,4 @@ - + diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index d21575e31c..23e59b6f5d 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -1,60 +1,55 @@ -
- - - -
- +
+ +
+

{{ 'person.orcid.registry.queue' | translate }}

- - {{ 'person.page.orcid.sync-queue.empty-message' | translate}} - - + + {{ 'person.page.orcid.sync-queue.empty-message' | translate}} + + -
- - - - - - - - - - - - - - - -
{{'person.page.orcid.sync-queue.table.header.type' | translate}}{{'person.page.orcid.sync-queue.table.header.description' | translate}}{{'person.page.orcid.sync-queue.table.header.action' | translate}}
- - - {{ entry.description }} - -
- - - -
-
-
-
-
- - - +
+ + + + + + + + + + + + + + + +
{{'person.page.orcid.sync-queue.table.header.type' | translate}}{{'person.page.orcid.sync-queue.table.header.description' | translate}}{{'person.page.orcid.sync-queue.table.header.action' | translate}}
+ + + {{ entry.description }} + +
+ + + +
+
+
+ +
diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index f85feb853d..2c4dcf46c3 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -10,13 +10,12 @@ import { PaginationServiceStub } from '../../../shared/testing/pagination-servic import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { OrcidHistoryService } from '../../../core/orcid/orcid-history.service'; -import { ActivatedRoute, Params } from '@angular/router'; -import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { createPaginatedList } from '../../../shared/testing/utils.test'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { By } from '@angular/platform-browser'; +import { Item } from '../../../core/shared/item.model'; fdescribe('OrcidQueueComponent test suite', () => { @@ -27,9 +26,63 @@ fdescribe('OrcidQueueComponent test suite', () => { const testOwnerId = 'test-owner-id'; - const routeParams: Params = {'id': testOwnerId}; - - const activatedRouteStub = new ActivatedRouteStub(routeParams); + const mockItemLinkedToOrcid: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: { + 'dc.title': [{ + value: 'test person' + }], + 'dspace.entity.type': [{ + 'value': 'Person' + }], + 'dspace.object.owner': [{ + 'value': 'test person', + 'language': null, + 'authority': 'deced3e7-68e2-495d-bf98-7c44fc33b8ff', + 'confidence': 600, + 'place': 0 + }], + 'dspace.orcid.authenticated': [{ + 'value': '2022-06-10T15:15:12.952872', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }], + 'dspace.orcid.scope': [{ + 'value': '/authenticate', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }, { + 'value': '/read-limited', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 1 + }, { + 'value': '/activities/update', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 2 + }, { + 'value': '/person/update', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 3 + }], + 'person.identifier.orcid': [{ + 'value': 'orcid-id', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }] + } + }); function orcidQueueElement(id: number) { return Object.assign(new OrcidQueue(), { @@ -45,14 +98,8 @@ fdescribe('OrcidQueueComponent test suite', () => { const orcidQueueElements = [orcidQueueElement(1), orcidQueueElement(2)]; - const orcidQueueServiceMock = { - searchByOwnerId(id) { - return createSuccessfulRemoteDataObject$>(createPaginatedList(orcidQueueElements)); - }, - clearFindByOwnerRequests() { - return null; - } - }; + const orcidQueueServiceSpy = jasmine.createSpyObj('orcidQueueService', ['searchByOwnerId', 'clearFindByOwnerRequests']); + orcidQueueServiceSpy.searchByOwnerId.and.returnValue(createSuccessfulRemoteDataObject$>(createPaginatedList(orcidQueueElements))); beforeEach(waitForAsync(() => { void TestBed.configureTestingModule({ @@ -67,11 +114,10 @@ fdescribe('OrcidQueueComponent test suite', () => { ], declarations: [OrcidQueueComponent], providers: [ - { provide: OrcidQueueService, useValue: orcidQueueServiceMock }, + { provide: OrcidQueueService, useValue: orcidQueueServiceSpy }, { provide: OrcidHistoryService, useValue: {} }, { provide: PaginationService, useValue: new PaginationServiceStub() }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -82,6 +128,7 @@ fdescribe('OrcidQueueComponent test suite', () => { beforeEach(() => { fixture = TestBed.createComponent(OrcidQueueComponent); component = fixture.componentInstance; + component.item = mockItemLinkedToOrcid; debugElement = fixture.debugElement; fixture.detectChanges(); }); @@ -90,9 +137,9 @@ fdescribe('OrcidQueueComponent test suite', () => { expect(component).toBeTruthy(); }); - it('should ...', () => { - const table = debugElement.queryAll(By.css('table')); - expect(table.length).toBe(1); + it('should show the ORCID queue elements', () => { + const table = debugElement.queryAll(By.css('[data-test="orcidQueueElementRow"]')); + expect(table.length).toBe(2); }); }); diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 0dd2f8517c..7faa4f54cb 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -1,5 +1,4 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; @@ -15,6 +14,7 @@ import { hasValue } from '../../../shared/empty.util'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { AlertType } from '../../../shared/alert/aletr-type'; +import { Item } from '../../../core/shared/item.model'; @Component({ selector: 'ds-orcid-queue', @@ -22,6 +22,12 @@ import { AlertType } from '../../../shared/alert/aletr-type'; styleUrls: ['./orcid-queue.component.scss'] }) export class OrcidQueueComponent implements OnInit, OnDestroy { + + /** + * The item for which showing the orcid settings + */ + @Input() item: Item; + /** * Pagination config used to display the list */ @@ -54,7 +60,6 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { constructor(private orcidQueueService: OrcidQueueService, protected translateService: TranslateService, private paginationService: PaginationService, - private route: ActivatedRoute, private notificationsService: NotificationsService, private orcidHistoryService: OrcidHistoryService, ) { } @@ -67,7 +72,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { this.subs.push( this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions).pipe( tap(() => this.processing$.next(true)), - switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByOwnerId(this.route.snapshot.paramMap.get('id'), config)), + switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByOwnerId(this.item.id, config)), getFirstCompletedRemoteData() ).subscribe((result: RemoteData>) => { this.processing$.next(false); @@ -236,7 +241,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { } private getUnauthorizedErrorContent(): Observable { - return this.orcidQueueService.getOrcidAuthorizeUrl(this.route.snapshot.paramMap.get('id')).pipe( + return this.orcidQueueService.getOrcidAuthorizeUrl(this.item.id).pipe( switchMap((authorizeUrl) => this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.content', { orcid : authorizeUrl})) ); } From 8eca0d93e45e970ded0773ae80cc92089dc4c5a1 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Tue, 14 Jun 2022 23:14:10 +0200 Subject: [PATCH 045/103] [CST-5339] fdescribe removed --- .../orcid-page/orcid-queue/orcid-queue.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index 2c4dcf46c3..d460e541e6 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -18,7 +18,7 @@ import { By } from '@angular/platform-browser'; import { Item } from '../../../core/shared/item.model'; -fdescribe('OrcidQueueComponent test suite', () => { +describe('OrcidQueueComponent test suite', () => { let component: OrcidQueueComponent; let fixture: ComponentFixture; let debugElement: DebugElement; From 3979c51e610b750f1ebbed070ccb7cc5e029eb49 Mon Sep 17 00:00:00 2001 From: Pierre Lasou Date: Tue, 14 Jun 2022 17:43:56 -0400 Subject: [PATCH 046/103] New french translations for some parameters. Proposition for new translations of the following terms: Workspace, Workflow, Workflow task and MyDSpace. --- src/assets/i18n/fr.json5 | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/assets/i18n/fr.json5 b/src/assets/i18n/fr.json5 index 3b9d7498be..dac20bc90f 100644 --- a/src/assets/i18n/fr.json5 +++ b/src/assets/i18n/fr.json5 @@ -751,13 +751,13 @@ "administrativeView.search.results.head": "Recherche Administrateur", // "admin.workflow.breadcrumbs": "Administer Workflow", - "admin.workflow.breadcrumbs": "Gestion des soumissions en Workflow", + "admin.workflow.breadcrumbs": "Gestion des soumissions en traitement", // "admin.workflow.title": "Administer Workflow", - "admin.workflow.title": "Gestion des soumissions en Workflow", + "admin.workflow.title": "Gestion des soumissions en traitement", // "admin.workflow.item.workflow": "Workflow", - "admin.workflow.item.workflow": "Workflow", + "admin.workflow.item.workflow": "En traitement", // "admin.workflow.item.delete": "Delete", "admin.workflow.item.delete": "Supprimer", @@ -3622,7 +3622,7 @@ "menu.section.workflow": "Workflow Administrateur", // "mydspace.breadcrumbs": "MyDSpace", - "mydspace.breadcrumbs": "Mon compte DSpace", + "mydspace.breadcrumbs": "Mes dépôts", // "mydspace.description": "", "mydspace.description": "", @@ -3709,7 +3709,7 @@ "mydspace.search-form.placeholder": "Rechercher dans mon compte DSpace...", // "mydspace.show.workflow": "Workflow tasks", - "mydspace.show.workflow": "Tâches du Workflow", + "mydspace.show.workflow": "Tableau de suivi", // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Vos dépôts", @@ -3724,13 +3724,13 @@ "mydspace.status.waiting-for-controller": "En attente d'assignation", // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Workflow", + "mydspace.status.workflow": "En traitement", // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Espace de travail", + "mydspace.status.workspace": "Dépôts en cours", // "mydspace.title": "MyDSpace", - "mydspace.title": "Mon compte DSpace", + "mydspace.title": "Mes dépôts", // "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", "mydspace.upload.upload-failed": "Erreur à la création de l'espace de travail. Veuillez vérifier le contenu téléchargé avant de réessayer.", @@ -3769,7 +3769,7 @@ "nav.main.description": "Barre de navigation principale", // "nav.mydspace": "MyDSpace", - "nav.mydspace": "Mon compte DSpace", + "nav.mydspace": "Mes dépôts", // "nav.profile": "Profile", "nav.profile": "Profil", @@ -4984,7 +4984,7 @@ "submission.import-external.page.hint": "Entrer votre recherche ci-dessus pour rechercher des éléments du web à importer dans DSpace", // "submission.import-external.back-to-my-dspace": "Back to MyDSpace", - "submission.import-external.back-to-my-dspace": "Retour à mon compte DSpace", + "submission.import-external.back-to-my-dspace": "Retour à Mes dépôts", // "submission.import-external.search.placeholder": "Search the external source", "submission.import-external.search.placeholder": "Recherche de la source externe", @@ -5824,7 +5824,7 @@ "workflowAdmin.search.results.head": "Workflow Administrateur", // "workflow.search.results.head": "Workflow tasks", - "workflow.search.results.head": "tâches du Workflow", + "workflow.search.results.head": "Tableau de suivi", // "workflow-item.edit.breadcrumbs": "Edit workflowitem", "workflow-item.edit.breadcrumbs": "Éditer l'Item du Workflow", From d3ba1d2926abc022c41839c778b05e2a4fb9b93f Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 15 Jun 2022 12:42:02 +0200 Subject: [PATCH 047/103] [CST-5339] Rename ORCID service; add findById and findAllByHref --- src/app/core/core.module.ts | 4 +-- ...rvice.ts => orcid-history-data.service.ts} | 36 ++++++++++++++++++- .../orcid-queue/orcid-queue.component.spec.ts | 4 +-- .../orcid-queue/orcid-queue.component.ts | 4 +-- 4 files changed, 41 insertions(+), 7 deletions(-) rename src/app/core/orcid/{orcid-history.service.ts => orcid-history-data.service.ts} (58%) diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 4ec4ca8592..90e326a4df 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -174,7 +174,7 @@ import { ResearcherProfileService } from './profile/researcher-profile.service'; import { ProfileClaimService } from '../profile-page/profile-claim/profile-claim.service'; import { ResearcherProfile } from './profile/model/researcher-profile.model'; import { OrcidQueueService } from './orcid/orcid-queue.service'; -import { OrcidHistoryService } from './orcid/orcid-history.service'; +import { OrcidHistoryDataService } from './orcid/orcid-history-data.service'; import { OrcidQueue } from './orcid/model/orcid-queue.model'; import { OrcidHistory } from './orcid/model/orcid-history.model'; @@ -306,7 +306,7 @@ const PROVIDERS = [ ResearcherProfileService, ProfileClaimService, OrcidQueueService, - OrcidHistoryService, + OrcidHistoryDataService, ]; /** diff --git a/src/app/core/orcid/orcid-history.service.ts b/src/app/core/orcid/orcid-history-data.service.ts similarity index 58% rename from src/app/core/orcid/orcid-history.service.ts rename to src/app/core/orcid/orcid-history-data.service.ts index 6658c63c9f..cef3efbe78 100644 --- a/src/app/core/orcid/orcid-history.service.ts +++ b/src/app/core/orcid/orcid-history-data.service.ts @@ -22,6 +22,9 @@ import { HttpOptions } from '../dspace-rest/dspace-rest.service'; import { CoreState } from '../core-state.model'; import { RestRequest } from '../data/rest-request.model'; import { sendRequest } from '../shared/request.operators'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { FindListOptions } from '../data/find-list-options.model'; +import { PaginatedList } from '../data/paginated-list.model'; /** * A private DataService implementation to delegate specific methods to. @@ -48,7 +51,7 @@ class OrcidHistoryServiceImpl extends DataService { */ @Injectable() @dataService(ORCID_HISTORY) -export class OrcidHistoryService { +export class OrcidHistoryDataService { dataService: OrcidHistoryServiceImpl; @@ -89,4 +92,35 @@ export class OrcidHistoryService { return this.halService.getEndpoint(this.dataService.linkPath); } + /** + * Returns an observable of {@link RemoteData} of an object, based on its ID, with a list of + * {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object + * @param id ID of object we want to retrieve + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which + * {@link HALLink}s should be automatically resolved + */ + findById(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { + return this.dataService.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } + + /** + * Returns a list of observables of {@link RemoteData} of {@link OrcidHistory}s, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link OrcidHistory} + * @param href The url of object we want to retrieve + * @param findListOptions Find list options object + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which + * {@link HALLink}s should be automatically resolved + */ + findAllByHref(href: string, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { + return this.dataService.findAllByHref(href, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } + } diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index d460e541e6..accd5e57a5 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -9,7 +9,7 @@ import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; -import { OrcidHistoryService } from '../../../core/orcid/orcid-history.service'; +import { OrcidHistoryDataService } from '../../../core/orcid/orcid-history-data.service'; import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { createPaginatedList } from '../../../shared/testing/utils.test'; @@ -115,7 +115,7 @@ describe('OrcidQueueComponent test suite', () => { declarations: [OrcidQueueComponent], providers: [ { provide: OrcidQueueService, useValue: orcidQueueServiceSpy }, - { provide: OrcidHistoryService, useValue: {} }, + { provide: OrcidHistoryDataService, useValue: {} }, { provide: PaginationService, useValue: new PaginationServiceStub() }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, ], diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 7faa4f54cb..217e02bc1f 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -6,7 +6,7 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { OrcidHistory } from '../../../core/orcid/model/orcid-history.model'; import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; -import { OrcidHistoryService } from '../../../core/orcid/orcid-history.service'; +import { OrcidHistoryDataService } from '../../../core/orcid/orcid-history-data.service'; import { OrcidQueueService } from '../../../core/orcid/orcid-queue.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { getFinishedRemoteData, getFirstCompletedRemoteData } from '../../../core/shared/operators'; @@ -61,7 +61,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { protected translateService: TranslateService, private paginationService: PaginationService, private notificationsService: NotificationsService, - private orcidHistoryService: OrcidHistoryService, + private orcidHistoryService: OrcidHistoryDataService, ) { } ngOnInit(): void { From 9bcd92efae532ac1724a7ace99873e720dd227f4 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 15 Jun 2022 15:08:16 +0200 Subject: [PATCH 048/103] [CST-6056] optimize fix to issue with filter suggestion --- .../search-facet-filter.component.ts | 53 +++++++++++-------- .../search-hierarchy-filter.component.html | 2 +- .../search-hierarchy-filter.component.ts | 5 +- .../search-text-filter.component.html | 2 +- .../search-text-filter.component.ts | 5 +- src/app/shared/search/search.utils.spec.ts | 4 +- src/app/shared/search/search.utils.ts | 2 +- 7 files changed, 38 insertions(+), 35 deletions(-) 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 edcd88cd21..c754d80a79 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 @@ -29,7 +29,7 @@ import { InputSuggestion } from '../../../../input-suggestions/input-suggestions 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'; +import { addOperatorToFilterValue, getFacetValueForType, stripOperatorFromFilterValue } from '../../../search.utils'; import { createPendingRemoteDataObject } from '../../../../remote-data.utils'; @Component({ @@ -234,32 +234,16 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * @param data The string from the input field */ onSubmit(data: any) { - if (data.match(new RegExp(`^.+,(equals|query|authority)$`))) { - this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { - if (isNotEmpty(data)) { - this.router.navigate(this.getSearchLinkParts(), { - queryParams: - { - [this.filterConfig.paramName]: [ - ...selectedValues.map((facet) => this.getFacetValue(facet)), - data - ] - }, - queryParamsHandling: 'merge' - }); - this.filter = ''; - } - this.filterSearchResults = observableOf([]); - }); - } + this.applyFilterValue(data); } /** - * On click, set the input's value to the clicked data - * @param data The value of the option that was clicked + * Submits a selected filter value to the filter + * Adds the "equals" operator to the received data before passing it on + * @param data The string selected from input suggestions */ onClick(data: any) { - this.filter = data; + this.applyFilterValue(addOperatorToFilterValue(data, 'equals')); } /** @@ -307,6 +291,31 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { } } + /** + * Build the filter query using the value given and apply to the search. + * @param data The string from the input field + */ + protected applyFilterValue(data) { + if (data.match(new RegExp(`^.+,(equals|query|authority)$`))) { + this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { + if (isNotEmpty(data)) { + this.router.navigate(this.getSearchLinkParts(), { + queryParams: + { + [this.filterConfig.paramName]: [ + ...selectedValues.map((facet) => this.getFacetValue(facet)), + data + ] + }, + queryParamsHandling: 'merge' + }); + this.filter = ''; + } + this.filterSearchResults = observableOf([]); + }); + } + } + /** * Retrieve facet value */ diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html index 02f2bc6336..49ca6fe3fd 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html @@ -24,7 +24,7 @@ [name]="filterConfig.paramName" [(ngModel)]="filter" (submitSuggestion)="onSubmit($event)" - (clickSuggestion)="onSubmit($event)" + (clickSuggestion)="onClick($event)" (findSuggestions)="findSuggestions($event)" ngDefaultControl > 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 a6e9fb4a00..b3349a5dd9 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 @@ -3,7 +3,6 @@ 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 { addOperatorToFilterValue } from '../../../search.utils'; -import { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; @Component({ selector: 'ds-search-hierarchy-filter', @@ -23,8 +22,6 @@ export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent i * @param data The string from the input field */ onSubmit(data: any) { - this.filterSearchResults.subscribe((filterSearchResults: InputSuggestion[]) => { - super.onSubmit(addOperatorToFilterValue(data, filterSearchResults.length ? 'equals' : 'query')); - }); + super.onSubmit(addOperatorToFilterValue(data, 'query')); } } diff --git a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html index 44aed494e3..fdf154bc04 100644 --- a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.html @@ -24,7 +24,7 @@ [name]="filterConfig.paramName" [(ngModel)]="filter" (submitSuggestion)="onSubmit($event)" - (clickSuggestion)="onSubmit($event)" + (clickSuggestion)="onClick($event)" (findSuggestions)="findSuggestions($event)" ngDefaultControl>
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 62c10e4c61..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 @@ -3,7 +3,6 @@ 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 { InputSuggestion } from '../../../../input-suggestions/input-suggestions.model'; /** * This component renders a simple item page. @@ -29,8 +28,6 @@ export class SearchTextFilterComponent extends SearchFacetFilterComponent implem * @param data The string from the input field */ onSubmit(data: any) { - this.filterSearchResults.subscribe((filterSearchResults: InputSuggestion[]) => { - super.onSubmit(addOperatorToFilterValue(data, filterSearchResults.length ? 'equals' : 'query')); - }); + super.onSubmit(addOperatorToFilterValue(data, 'query')); } } diff --git a/src/app/shared/search/search.utils.spec.ts b/src/app/shared/search/search.utils.spec.ts index 75735093e8..70bf9a43a0 100644 --- a/src/app/shared/search/search.utils.spec.ts +++ b/src/app/shared/search/search.utils.spec.ts @@ -66,11 +66,11 @@ describe('Search Utils', () => { describe('addOperatorToFilterValue', () => { it('should add the operator to the value', () => { - expect(addOperatorToFilterValue('value', 'operator')).toEqual('value,operator'); + expect(addOperatorToFilterValue('value', 'equals')).toEqual('value,equals'); }); it('shouldn\'t add the operator to the value if it already contains the operator', () => { - expect(addOperatorToFilterValue('value,operator', 'operator')).toEqual('value,operator'); + expect(addOperatorToFilterValue('value,equals', 'equals')).toEqual('value,equals'); }); }); diff --git a/src/app/shared/search/search.utils.ts b/src/app/shared/search/search.utils.ts index 4d688d48eb..cfb96a5285 100644 --- a/src/app/shared/search/search.utils.ts +++ b/src/app/shared/search/search.utils.ts @@ -49,7 +49,7 @@ export function stripOperatorFromFilterValue(value: string) { * @param operator */ export function addOperatorToFilterValue(value: string, operator: string) { - if (!value.endsWith(`,${operator}`)) { + if (!value.match(new RegExp(`^.+,(equals|query|authority)$`))) { return `${value},${operator}`; } return value; From 793169dd312121c06aab9f7d20b3de9d49447e86 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 15 Jun 2022 18:54:30 +0200 Subject: [PATCH 049/103] [CST-5339] Fix queue refresh after preferences are changed --- src/app/core/orcid/orcid-queue.service.ts | 22 ++-- .../orcid-page/orcid-page.component.ts | 16 ++- .../orcid-queue/orcid-queue.component.html | 8 +- .../orcid-queue/orcid-queue.component.ts | 114 ++++++++++++------ 4 files changed, 103 insertions(+), 57 deletions(-) diff --git a/src/app/core/orcid/orcid-queue.service.ts b/src/app/core/orcid/orcid-queue.service.ts index 0da9ac227c..1d50c560ed 100644 --- a/src/app/core/orcid/orcid-queue.service.ts +++ b/src/app/core/orcid/orcid-queue.service.ts @@ -76,17 +76,23 @@ export class OrcidQueueService { } /** - * @param itemId It represent a Id of owner - * @param paginationOptions + * @param itemId It represent an Id of owner + * @param paginationOptions The pagination options object + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale * @returns { OrcidQueue } */ - searchByOwnerId(itemId: string, paginationOptions: PaginationComponentOptions): Observable>> { + searchByOwnerId(itemId: string, paginationOptions: PaginationComponentOptions, useCachedVersionIfAvailable = true, reRequestOnStale = true): Observable>> { return this.dataService.searchBy('findByOwner', { - searchParams: [new RequestParam('ownerId', itemId)], - elementsPerPage: paginationOptions.pageSize, - currentPage: paginationOptions.currentPage - },false, - true); + searchParams: [new RequestParam('ownerId', itemId)], + elementsPerPage: paginationOptions.pageSize, + currentPage: paginationOptions.currentPage + }, + useCachedVersionIfAvailable, + reRequestOnStale + ); } /** diff --git a/src/app/item-page/orcid-page/orcid-page.component.ts b/src/app/item-page/orcid-page/orcid-page.component.ts index 6c1de3d100..a4628eed93 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.ts +++ b/src/app/item-page/orcid-page/orcid-page.component.ts @@ -109,6 +109,7 @@ export class OrcidPageComponent implements OnInit { * Retrieve the updated profile item */ updateItem(): void { + this.clearRouteParams(); this.itemService.findById(this.itemId, false).pipe( getFirstCompletedRemoteData() ).subscribe((itemRD: RemoteData) => { @@ -135,11 +136,18 @@ export class OrcidPageComponent implements OnInit { } else { this.item.next(person); this.connectionStatus.next(false); + this.clearRouteParams(); } - - // update route removing the code from query params - const redirectUrl = this.router.url.split('?')[0]; - this.router.navigate([redirectUrl]); }); } + + /** + * Update route removing the code from query params + * @private + */ + private clearRouteParams(): void { + // update route removing the code from query params + const redirectUrl = this.router.url.split('?')[0]; + this.router.navigate([redirectUrl]); + } } diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index 23e59b6f5d..fc8eb3c4cf 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -23,7 +23,7 @@ - + @@ -32,11 +32,7 @@
- - diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 217e02bc1f..27f98598a7 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -1,7 +1,9 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; + import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; -import { switchMap, tap } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs/operators'; + import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { OrcidHistory } from '../../../core/orcid/model/orcid-history.model'; @@ -9,7 +11,7 @@ import { OrcidQueue } from '../../../core/orcid/model/orcid-queue.model'; import { OrcidHistoryDataService } from '../../../core/orcid/orcid-history-data.service'; import { OrcidQueueService } from '../../../core/orcid/orcid-queue.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; -import { getFinishedRemoteData, getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { hasValue } from '../../../shared/empty.util'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; @@ -57,22 +59,35 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { * @type {Array} */ private subs: Subscription[] = []; + constructor(private orcidQueueService: OrcidQueueService, protected translateService: TranslateService, private paginationService: PaginationService, private notificationsService: NotificationsService, private orcidHistoryService: OrcidHistoryDataService, - ) { } + ) { + } ngOnInit(): void { this.updateList(); } + ngOnChanges(changes: SimpleChanges): void { + if (!changes.item.isFirstChange() && changes.item.currentValue !== changes.item.previousValue) { + this.updateList(); + } + } + + /** + * Retrieve queue list + */ updateList() { this.subs.push( this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions).pipe( + debounceTime(100), + distinctUntilChanged(), tap(() => this.processing$.next(true)), - switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByOwnerId(this.item.id, config)), + switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByOwnerId(this.item.id, config, false)), getFirstCompletedRemoteData() ).subscribe((result: RemoteData>) => { this.processing$.next(false); @@ -82,7 +97,6 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { ); } - /** * Return the list of orcid queue records */ @@ -90,6 +104,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { return this.list$.asObservable(); } + /** + * Return the icon class for the queue object type + * + * @param orcidQueue The OrcidQueue object + */ getIconClass(orcidQueue: OrcidQueue): string { if (!orcidQueue.recordType) { return 'fa fa-user'; @@ -113,6 +132,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { } } + /** + * Return the icon tooltip message for the queue object type + * + * @param orcidQueue The OrcidQueue object + */ getIconTooltip(orcidQueue: OrcidQueue): string { if (!orcidQueue.recordType) { return ''; @@ -121,24 +145,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { return 'person.page.orcid.sync-queue.tooltip.' + orcidQueue.recordType.toLowerCase(); } - getOperationBadgeClass(orcidQueue: OrcidQueue): string { - - if (!orcidQueue.operation) { - return ''; - } - - switch (orcidQueue.operation.toLowerCase()) { - case 'insert': - return 'badge badge-pill badge-success'; - case 'update': - return 'badge badge-pill badge-primary'; - case 'delete': - return 'badge badge-pill badge-danger'; - default: - return ''; - } - } - + /** + * Return the icon tooltip message for the queue object operation + * + * @param orcidQueue The OrcidQueue object + */ getOperationTooltip(orcidQueue: OrcidQueue): string { if (!orcidQueue.operation) { return ''; @@ -147,6 +158,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { return 'person.page.orcid.sync-queue.tooltip.' + orcidQueue.operation.toLowerCase(); } + /** + * Return the icon class for the queue object operation + * + * @param orcidQueue The OrcidQueue object + */ getOperationClass(orcidQueue: OrcidQueue): string { if (!orcidQueue.operation) { @@ -165,10 +181,15 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { } } + /** + * Discard a queue entry from the synchronization + * + * @param orcidQueue The OrcidQueue object to discard + */ discardEntry(orcidQueue: OrcidQueue) { this.processing$.next(true); this.subs.push(this.orcidQueueService.deleteById(orcidQueue.id).pipe( - getFinishedRemoteData() + getFirstCompletedRemoteData() ).subscribe((remoteData) => { this.processing$.next(false); if (remoteData.isSuccess) { @@ -180,10 +201,15 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { })); } - send( orcidQueue: OrcidQueue ) { + /** + * Send a queue entry to orcid for the synchronization + * + * @param orcidQueue The OrcidQueue object to synchronize + */ + send(orcidQueue: OrcidQueue) { this.processing$.next(true); this.subs.push(this.orcidHistoryService.sendToORCID(orcidQueue).pipe( - getFinishedRemoteData() + getFirstCompletedRemoteData() ).subscribe((remoteData) => { this.processing$.next(false); if (remoteData.isSuccess) { @@ -196,7 +222,22 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { })); } - handleOrcidHistoryRecordCreation(orcidHistory: OrcidHistory) { + + /** + * Return the error message for Unauthorized response + * @private + */ + private getUnauthorizedErrorContent(): Observable { + return this.orcidQueueService.getOrcidAuthorizeUrl(this.item.id).pipe( + switchMap((authorizeUrl) => this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.content', { orcid: authorizeUrl })) + ); + } + + /** + * Manage notification by response + * @private + */ + private handleOrcidHistoryRecordCreation(orcidHistory: OrcidHistory) { switch (orcidHistory.status) { case 200: case 201: @@ -212,7 +253,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.title'), this.getUnauthorizedErrorContent()], ).subscribe(([title, content]) => { - this.notificationsService.error(title, content, { timeOut: -1}, true); + this.notificationsService.error(title, content, { timeOut: -1 }, true); }); break; case 404: @@ -226,7 +267,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { } } - handleValidationErrors(remoteData: RemoteData) { + /** + * Manage validation errors + * @private + */ + private handleValidationErrors(remoteData: RemoteData) { const translations = [this.translateService.get('person.page.orcid.sync-queue.send.validation-error')]; const errorMessage = remoteData.errorMessage; if (errorMessage && errorMessage.indexOf('Error codes:') > 0) { @@ -240,11 +285,6 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { }); } - private getUnauthorizedErrorContent(): Observable { - return this.orcidQueueService.getOrcidAuthorizeUrl(this.item.id).pipe( - switchMap((authorizeUrl) => this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.content', { orcid : authorizeUrl})) - ); - } /** * Unsubscribe from all subscriptions @@ -255,8 +295,4 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { .forEach((subscription) => subscription.unsubscribe()); } - isProfileRecord(orcidQueue: OrcidQueue): boolean { - return orcidQueue.recordType !== 'Publication' && orcidQueue.recordType !== 'Project'; - } - } From 63356aa12746a3421ef89d4a74699e52ec801b56 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 16 Jun 2022 15:02:26 +0200 Subject: [PATCH 050/103] [CST-5339] Refactoring orcid services by adding OrcidAuthService --- src/app/core/orcid/orcid-auth.service.spec.ts | 329 ++++++++++++++++++ src/app/core/orcid/orcid-auth.service.ts | 147 ++++++++ src/app/core/orcid/orcid-queue.service.ts | 21 +- .../researcher-profile.service.spec.ts | 161 +-------- .../profile/researcher-profile.service.ts | 139 +------- .../orcid-auth/orcid-auth.component.spec.ts | 66 ++-- .../orcid-auth/orcid-auth.component.ts | 21 +- .../orcid-page/orcid-page.component.spec.ts | 18 +- .../orcid-page/orcid-page.component.ts | 10 +- .../orcid-queue/orcid-queue.component.spec.ts | 8 +- .../orcid-queue/orcid-queue.component.ts | 22 +- 11 files changed, 563 insertions(+), 379 deletions(-) create mode 100644 src/app/core/orcid/orcid-auth.service.spec.ts create mode 100644 src/app/core/orcid/orcid-auth.service.ts diff --git a/src/app/core/orcid/orcid-auth.service.spec.ts b/src/app/core/orcid/orcid-auth.service.spec.ts new file mode 100644 index 0000000000..27a33a85b1 --- /dev/null +++ b/src/app/core/orcid/orcid-auth.service.spec.ts @@ -0,0 +1,329 @@ +import { cold, getTestScheduler } from 'jasmine-marbles'; +import { TestScheduler } from 'rxjs/testing'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; +import { RouterMock } from '../../shared/mocks/router.mock'; +import { ResearcherProfile } from '../profile/model/researcher-profile.model'; +import { Item } from '../shared/item.model'; +import { AddOperation, RemoveOperation } from 'fast-json-patch'; +import { ConfigurationProperty } from '../shared/configuration-property.model'; +import { ConfigurationDataService } from '../data/configuration-data.service'; +import { createPaginatedList } from '../../shared/testing/utils.test'; +import { NativeWindowRefMock } from '../../shared/mocks/mock-native-window-ref'; +import { URLCombiner } from '../url-combiner/url-combiner'; +import { OrcidAuthService } from './orcid-auth.service'; +import { ResearcherProfileService } from '../profile/researcher-profile.service'; + +describe('OrcidAuthService', () => { + let scheduler: TestScheduler; + let service: OrcidAuthService; + let serviceAsAny: any; + + let researcherProfileService: jasmine.SpyObj; + let configurationDataService: ConfigurationDataService; + let nativeWindowService: NativeWindowRefMock; + let routerStub: any; + + const researcherProfileId = 'beef9946-rt56-479e-8f11-b90cbe9f7241'; + const itemId = 'beef9946-rt56-479e-8f11-b90cbe9f7241'; + + const researcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), { + id: researcherProfileId, + visible: false, + type: 'profile', + _links: { + item: { + href: `https://rest.api/rest/api/profiles/${researcherProfileId}/item` + }, + self: { + href: `https://rest.api/rest/api/profiles/${researcherProfileId}` + }, + } + }); + + const researcherProfilePatched: ResearcherProfile = Object.assign(new ResearcherProfile(), { + id: researcherProfileId, + visible: true, + type: 'profile', + _links: { + item: { + href: `https://rest.api/rest/api/profiles/${researcherProfileId}/item` + }, + self: { + href: `https://rest.api/rest/api/profiles/${researcherProfileId}` + }, + } + }); + + const mockItemUnlinkedToOrcid: Item = Object.assign(new Item(), { + id: 'mockItemUnlinkedToOrcid', + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: { + 'dc.title': [{ + value: 'test person' + }], + 'dspace.entity.type': [{ + 'value': 'Person' + }], + 'dspace.object.owner': [{ + 'value': 'test person', + 'language': null, + 'authority': 'researcher-profile-id', + 'confidence': 600, + 'place': 0 + }], + } + }); + + const mockItemLinkedToOrcid: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])), + metadata: { + 'dc.title': [{ + value: 'test person' + }], + 'dspace.entity.type': [{ + 'value': 'Person' + }], + 'dspace.object.owner': [{ + 'value': 'test person', + 'language': null, + 'authority': 'researcher-profile-id', + 'confidence': 600, + 'place': 0 + }], + 'dspace.orcid.authenticated': [{ + 'value': '2022-06-10T15:15:12.952872', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }], + 'dspace.orcid.scope': [{ + 'value': '/authenticate', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }, { + 'value': '/read-limited', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 1 + }, { + 'value': '/activities/update', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 2 + }, { + 'value': '/person/update', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 3 + }], + 'person.identifier.orcid': [{ + 'value': 'orcid-id', + 'language': null, + 'authority': null, + 'confidence': -1, + 'place': 0 + }] + } + }); + + const disconnectionAllowAdmin = { + uuid: 'orcid.disconnection.allowed-users', + name: 'orcid.disconnection.allowed-users', + values: ['only_admin'] + } as ConfigurationProperty; + + const disconnectionAllowAdminOwner = { + uuid: 'orcid.disconnection.allowed-users', + name: 'orcid.disconnection.allowed-users', + values: ['admin_and_owner'] + } as ConfigurationProperty; + + const authorizeUrl = { + uuid: 'orcid.authorize-url', + name: 'orcid.authorize-url', + values: ['orcid.authorize-url'] + } as ConfigurationProperty; + const appClientId = { + uuid: 'orcid.application-client-id', + name: 'orcid.application-client-id', + values: ['orcid.application-client-id'] + } as ConfigurationProperty; + const orcidScope = { + uuid: 'orcid.scope', + name: 'orcid.scope', + values: ['/authenticate', '/read-limited'] + } as ConfigurationProperty; + + beforeEach(() => { + scheduler = getTestScheduler(); + routerStub = new RouterMock(); + researcherProfileService = jasmine.createSpyObj('ResearcherProfileService', { + findById: jasmine.createSpy('findById'), + updateByOrcidOperations: jasmine.createSpy('updateByOrcidOperations') + }); + configurationDataService = jasmine.createSpyObj('configurationDataService', { + findByPropertyName: jasmine.createSpy('findByPropertyName') + }); + nativeWindowService = new NativeWindowRefMock(); + + service = new OrcidAuthService( + nativeWindowService, + configurationDataService, + researcherProfileService, + routerStub); + + serviceAsAny = service; + }); + + + describe('isLinkedToOrcid', () => { + it('should return true when item has metadata', () => { + const result = service.isLinkedToOrcid(mockItemLinkedToOrcid); + expect(result).toBeTrue(); + }); + + it('should return true when item has no metadata', () => { + const result = service.isLinkedToOrcid(mockItemUnlinkedToOrcid); + expect(result).toBeFalse(); + }); + }); + + describe('onlyAdminCanDisconnectProfileFromOrcid', () => { + it('should return true when property is only_admin', () => { + spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createSuccessfulRemoteDataObject$(disconnectionAllowAdmin)); + const result = service.onlyAdminCanDisconnectProfileFromOrcid(); + const expected = cold('(a|)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + + it('should return false on faild', () => { + spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createFailedRemoteDataObject$()); + const result = service.onlyAdminCanDisconnectProfileFromOrcid(); + const expected = cold('(a|)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('ownerCanDisconnectProfileFromOrcid', () => { + it('should return true when property is admin_and_owner', () => { + spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createSuccessfulRemoteDataObject$(disconnectionAllowAdminOwner)); + const result = service.ownerCanDisconnectProfileFromOrcid(); + const expected = cold('(a|)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + + it('should return false on faild', () => { + spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createFailedRemoteDataObject$()); + const result = service.ownerCanDisconnectProfileFromOrcid(); + const expected = cold('(a|)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('linkOrcidByItem', () => { + beforeEach(() => { + scheduler = getTestScheduler(); + researcherProfileService.updateByOrcidOperations.and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched)); + researcherProfileService.findById.and.returnValue(createSuccessfulRemoteDataObject$(researcherProfile)); + }); + + it('should call updateByOrcidOperations method properly', () => { + const operations: AddOperation[] = [{ + path: '/orcid', + op: 'add', + value: 'test-code' + }]; + + scheduler.schedule(() => service.linkOrcidByItem(mockItemUnlinkedToOrcid, 'test-code').subscribe()); + scheduler.flush(); + + expect(researcherProfileService.updateByOrcidOperations).toHaveBeenCalledWith(researcherProfile, operations); + }); + }); + + describe('unlinkOrcidByItem', () => { + beforeEach(() => { + scheduler = getTestScheduler(); + researcherProfileService.updateByOrcidOperations.and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched)); + researcherProfileService.findById.and.returnValue(createSuccessfulRemoteDataObject$(researcherProfile)); + }); + + it('should call updateByOrcidOperations method properly', () => { + const operations: RemoveOperation[] = [{ + path: '/orcid', + op: 'remove' + }]; + + scheduler.schedule(() => service.unlinkOrcidByItem(mockItemLinkedToOrcid).subscribe()); + scheduler.flush(); + + expect(researcherProfileService.updateByOrcidOperations).toHaveBeenCalledWith(researcherProfile, operations); + }); + }); + + describe('getOrcidAuthorizeUrl', () => { + beforeEach(() => { + routerStub.setRoute('/entities/person/uuid/orcid'); + (service as any).configurationService.findByPropertyName.and.returnValues( + createSuccessfulRemoteDataObject$(authorizeUrl), + createSuccessfulRemoteDataObject$(appClientId), + createSuccessfulRemoteDataObject$(orcidScope) + ); + }); + + it('should build the url properly', () => { + const result = service.getOrcidAuthorizeUrl(mockItemUnlinkedToOrcid); + const redirectUri: string = new URLCombiner(nativeWindowService.nativeWindow.origin, encodeURIComponent(routerStub.url.split('?')[0])).toString(); + const url = 'orcid.authorize-url?client_id=orcid.application-client-id&redirect_uri=' + redirectUri + '&response_type=code&scope=/authenticate /read-limited'; + + const expected = cold('(a|)', { + a: url + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOrcidAuthorizationScopesByItem', () => { + it('should return list of scopes saved in the item', () => { + const orcidScopes = [ + '/authenticate', + '/read-limited', + '/activities/update', + '/person/update' + ]; + const result = service.getOrcidAuthorizationScopesByItem(mockItemLinkedToOrcid); + expect(result).toEqual(orcidScopes); + }); + }); + + describe('getOrcidAuthorizationScopes', () => { + it('should return list of scopes by configuration', () => { + (service as any).configurationService.findByPropertyName.and.returnValue( + createSuccessfulRemoteDataObject$(orcidScope) + ); + const orcidScopes = [ + '/authenticate', + '/read-limited' + ]; + const expected = cold('(a|)', { + a: orcidScopes + }); + const result = service.getOrcidAuthorizationScopes(); + expect(result).toBeObservable(expected); + }); + }); +}); diff --git a/src/app/core/orcid/orcid-auth.service.ts b/src/app/core/orcid/orcid-auth.service.ts new file mode 100644 index 0000000000..7b85dccd9c --- /dev/null +++ b/src/app/core/orcid/orcid-auth.service.ts @@ -0,0 +1,147 @@ +import { Inject, Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +import { combineLatest, Observable } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { AddOperation, RemoveOperation } from 'fast-json-patch'; + +import { ResearcherProfileService } from '../profile/researcher-profile.service'; +import { Item } from '../shared/item.model'; +import { isNotEmpty } from '../../shared/empty.util'; +import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../shared/operators'; +import { RemoteData } from '../data/remote-data'; +import { ConfigurationProperty } from '../shared/configuration-property.model'; +import { ConfigurationDataService } from '../data/configuration-data.service'; +import { ResearcherProfile } from '../profile/model/researcher-profile.model'; +import { URLCombiner } from '../url-combiner/url-combiner'; +import { NativeWindowRef, NativeWindowService } from '../services/window.service'; + +@Injectable({ + providedIn: 'root' +}) +export class OrcidAuthService { + + constructor( + @Inject(NativeWindowService) protected _window: NativeWindowRef, + private configurationService: ConfigurationDataService, + private researcherProfileService: ResearcherProfileService, + private router: Router) { + } + + /** + * Check if the given item is linked to an ORCID profile. + * + * @param item the item to check + * @returns the check result + */ + public isLinkedToOrcid(item: Item): boolean { + return item.hasMetadata('dspace.orcid.authenticated'); + } + + /** + * Returns true if only the admin users can disconnect a researcher profile from ORCID. + * + * @returns the check result + */ + public onlyAdminCanDisconnectProfileFromOrcid(): Observable { + return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe( + map((propertyRD: RemoteData) => { + return propertyRD.hasSucceeded && propertyRD.payload.values.map((value) => value.toLowerCase()).includes('only_admin'); + }) + ); + } + + /** + * Returns true if the profile's owner can disconnect that profile from ORCID. + * + * @returns the check result + */ + public ownerCanDisconnectProfileFromOrcid(): Observable { + return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe( + map((propertyRD: RemoteData) => { + return propertyRD.hasSucceeded && propertyRD.payload.values.map( (value) => value.toLowerCase()).includes('admin_and_owner'); + }) + ); + } + + /** + * Perform a link operation to ORCID profile. + * + * @param person The person item related to the researcher profile + * @param code The auth-code received from orcid + */ + public linkOrcidByItem(person: Item, code: string): Observable> { + const operations: AddOperation[] = [{ + path: '/orcid', + op: 'add', + value: code + }]; + + return this.researcherProfileService.findById(person.firstMetadata('dspace.object.owner').authority).pipe( + getFirstCompletedRemoteData(), + switchMap((profileRD) => this.researcherProfileService.updateByOrcidOperations(profileRD.payload, operations)) + ); + } + + /** + * Perform unlink operation from ORCID profile. + * + * @param person The person item related to the researcher profile + */ + public unlinkOrcidByItem(person: Item): Observable> { + const operations: RemoveOperation[] = [{ + path:'/orcid', + op:'remove' + }]; + + return this.researcherProfileService.findById(person.firstMetadata('dspace.object.owner').authority).pipe( + getFirstCompletedRemoteData(), + switchMap((profileRD) => this.researcherProfileService.updateByOrcidOperations(profileRD.payload, operations)) + ); + } + + /** + * Build and return the url to authenticate with orcid + * + * @param profile + */ + public getOrcidAuthorizeUrl(profile: Item): Observable { + return combineLatest([ + this.configurationService.findByPropertyName('orcid.authorize-url').pipe(getFirstSucceededRemoteDataPayload()), + this.configurationService.findByPropertyName('orcid.application-client-id').pipe(getFirstSucceededRemoteDataPayload()), + this.configurationService.findByPropertyName('orcid.scope').pipe(getFirstSucceededRemoteDataPayload())] + ).pipe( + map(([authorizeUrl, clientId, scopes]) => { + const redirectUri = new URLCombiner(this._window.nativeWindow.origin, encodeURIComponent(this.router.url.split('?')[0])); + console.log(redirectUri.toString()); + return authorizeUrl.values[0] + '?client_id=' + clientId.values[0] + '&redirect_uri=' + redirectUri + '&response_type=code&scope=' + + scopes.values.join(' '); + })); + } + + /** + * Return all orcid authorization scopes saved in the given item + * + * @param item + */ + public getOrcidAuthorizationScopesByItem(item: Item): string[] { + return isNotEmpty(item) ? item.allMetadataValues('dspace.orcid.scope') : []; + } + + /** + * Return all orcid authorization scopes available by configuration + */ + public getOrcidAuthorizationScopes(): Observable { + return this.configurationService.findByPropertyName('orcid.scope').pipe( + getFirstCompletedRemoteData(), + map((propertyRD: RemoteData) => propertyRD.hasSucceeded ? propertyRD.payload.values : []) + ); + } + + private getOrcidDisconnectionAllowedUsersConfiguration(): Observable> { + return this.configurationService.findByPropertyName('orcid.disconnection.allowed-users').pipe( + getFirstCompletedRemoteData() + ); + } + +} diff --git a/src/app/core/orcid/orcid-queue.service.ts b/src/app/core/orcid/orcid-queue.service.ts index 1d50c560ed..6af8b8a4c7 100644 --- a/src/app/core/orcid/orcid-queue.service.ts +++ b/src/app/core/orcid/orcid-queue.service.ts @@ -13,16 +13,13 @@ import { Injectable } from '@angular/core'; import { dataService } from '../cache/builders/build-decorators'; import { ORCID_QUEUE } from './model/orcid-queue.resource-type'; import { ItemDataService } from '../data/item-data.service'; -import { combineLatest, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { RemoteData } from '../data/remote-data'; import { PaginatedList } from '../data/paginated-list.model'; import { RequestParam } from '../cache/models/request-param.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { NoContent } from '../shared/NoContent.model'; import { ConfigurationDataService } from '../data/configuration-data.service'; -import { map } from 'rxjs/operators'; -import { getFirstSucceededRemoteDataPayload } from '../shared/operators'; -import { environment } from '../../../environments/environment'; import { Router } from '@angular/router'; import { CoreState } from '../core-state.model'; @@ -110,20 +107,4 @@ export class OrcidQueueService { this.requestService.setStaleByHrefSubstring(this.dataService.linkPath + '/search/findByOwner'); } - /** - * @param profileId represent a uuid of that user - * @returns orcid authorized url of that user - */ - getOrcidAuthorizeUrl(profileId: string): Observable { - return combineLatest([ - this.configurationService.findByPropertyName('orcid.authorize-url').pipe(getFirstSucceededRemoteDataPayload()), - this.configurationService.findByPropertyName('orcid.application-client-id').pipe(getFirstSucceededRemoteDataPayload()), - this.configurationService.findByPropertyName('orcid.scope').pipe(getFirstSucceededRemoteDataPayload())] - ).pipe( - map(([authorizeUrl, clientId, scopes]) => { - const redirectUri = environment.rest.baseUrl + '/api/cris/orcid/' + profileId + '/?url=' + encodeURIComponent(this.router.url); - return authorizeUrl.values[0] + '?client_id=' + clientId.values[0] + '&redirect_uri=' + redirectUri + '&response_type=code&scope=' - + scopes.values.join(' '); - })); - } } diff --git a/src/app/core/profile/researcher-profile.service.spec.ts b/src/app/core/profile/researcher-profile.service.spec.ts index 11f6e1b13b..899867ec8e 100644 --- a/src/app/core/profile/researcher-profile.service.spec.ts +++ b/src/app/core/profile/researcher-profile.service.spec.ts @@ -12,7 +12,6 @@ import { RequestService } from '../data/request.service'; import { PageInfo } from '../shared/page-info.model'; import { buildPaginatedList } from '../data/paginated-list.model'; import { - createFailedRemoteDataObject$, createNoContentRemoteDataObject$, createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ @@ -23,15 +22,12 @@ import { ResearcherProfileService } from './researcher-profile.service'; import { RouterMock } from '../../shared/mocks/router.mock'; import { ResearcherProfile } from './model/researcher-profile.model'; import { Item } from '../shared/item.model'; -import { AddOperation, RemoveOperation, ReplaceOperation } from 'fast-json-patch'; +import { ReplaceOperation } from 'fast-json-patch'; import { HttpOptions } from '../dspace-rest/dspace-rest.service'; import { PostRequest } from '../data/request.models'; import { followLink } from '../../shared/utils/follow-link-config.model'; import { ConfigurationProperty } from '../shared/configuration-property.model'; -import { ConfigurationDataService } from '../data/configuration-data.service'; import { createPaginatedList } from '../../shared/testing/utils.test'; -import { NativeWindowRefMock } from '../../shared/mocks/mock-native-window-ref'; -import { URLCombiner } from '../url-combiner/url-combiner'; describe('ResearcherProfileService', () => { let scheduler: TestScheduler; @@ -42,8 +38,6 @@ describe('ResearcherProfileService', () => { let objectCache: ObjectCacheService; let halService: HALEndpointService; let responseCacheEntry: RequestEntry; - let configurationDataService: ConfigurationDataService; - let nativeWindowService: NativeWindowRefMock; let routerStub: any; const researcherProfileId = 'beef9946-rt56-479e-8f11-b90cbe9f7241'; @@ -252,13 +246,8 @@ describe('ResearcherProfileService', () => { const itemService = jasmine.createSpyObj('ItemService', { findByHref: jasmine.createSpy('findByHref') }); - configurationDataService = jasmine.createSpyObj('configurationDataService', { - findByPropertyName: jasmine.createSpy('findByPropertyName') - }); - nativeWindowService = new NativeWindowRefMock(); service = new ResearcherProfileService( - nativeWindowService, requestService, rdbService, objectCache, @@ -267,8 +256,7 @@ describe('ResearcherProfileService', () => { http, routerStub, comparator, - itemService, - configurationDataService + itemService ); serviceAsAny = service; @@ -415,121 +403,6 @@ describe('ResearcherProfileService', () => { }); }); - describe('isLinkedToOrcid', () => { - it('should return true when item has metadata', () => { - const result = service.isLinkedToOrcid(mockItemLinkedToOrcid); - expect(result).toBeTrue(); - }); - - it('should return true when item has no metadata', () => { - const result = service.isLinkedToOrcid(mockItemUnlinkedToOrcid); - expect(result).toBeFalse(); - }); - }); - - describe('onlyAdminCanDisconnectProfileFromOrcid', () => { - it('should return true when property is only_admin', () => { - spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createSuccessfulRemoteDataObject$(disconnectionAllowAdmin)); - const result = service.onlyAdminCanDisconnectProfileFromOrcid(); - const expected = cold('(a|)', { - a: true - }); - expect(result).toBeObservable(expected); - }); - - it('should return false on faild', () => { - spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createFailedRemoteDataObject$()); - const result = service.onlyAdminCanDisconnectProfileFromOrcid(); - const expected = cold('(a|)', { - a: false - }); - expect(result).toBeObservable(expected); - }); - }); - - describe('ownerCanDisconnectProfileFromOrcid', () => { - it('should return true when property is admin_and_owner', () => { - spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createSuccessfulRemoteDataObject$(disconnectionAllowAdminOwner)); - const result = service.ownerCanDisconnectProfileFromOrcid(); - const expected = cold('(a|)', { - a: true - }); - expect(result).toBeObservable(expected); - }); - - it('should return false on faild', () => { - spyOn((service as any), 'getOrcidDisconnectionAllowedUsersConfiguration').and.returnValue(createFailedRemoteDataObject$()); - const result = service.ownerCanDisconnectProfileFromOrcid(); - const expected = cold('(a|)', { - a: false - }); - expect(result).toBeObservable(expected); - }); - }); - - describe('linkOrcidByItem', () => { - beforeEach(() => { - scheduler = getTestScheduler(); - spyOn((service as any).dataService, 'patch').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched)); - spyOn((service as any), 'findById').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfile)); - }); - - it('should call patch method properly', () => { - const operations: AddOperation[] = [{ - path: '/orcid', - op: 'add', - value: 'test-code' - }]; - - scheduler.schedule(() => service.linkOrcidByItem(mockItemUnlinkedToOrcid, 'test-code').subscribe()); - scheduler.flush(); - - expect((service as any).dataService.patch).toHaveBeenCalledWith(researcherProfile, operations); - }); - }); - - describe('unlinkOrcidByItem', () => { - beforeEach(() => { - scheduler = getTestScheduler(); - spyOn((service as any).dataService, 'patch').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfilePatched)); - spyOn((service as any), 'findById').and.returnValue(createSuccessfulRemoteDataObject$(researcherProfile)); - }); - - it('should call patch method properly', () => { - const operations: RemoveOperation[] = [{ - path: '/orcid', - op: 'remove' - }]; - - scheduler.schedule(() => service.unlinkOrcidByItem(mockItemLinkedToOrcid).subscribe()); - scheduler.flush(); - - expect((service as any).dataService.patch).toHaveBeenCalledWith(researcherProfile, operations); - }); - }); - - describe('getOrcidAuthorizeUrl', () => { - beforeEach(() => { - routerStub.setRoute('/entities/person/uuid/orcid'); - (service as any).configurationService.findByPropertyName.and.returnValues( - createSuccessfulRemoteDataObject$(authorizeUrl), - createSuccessfulRemoteDataObject$(appClientId), - createSuccessfulRemoteDataObject$(orcidScope) - ); - }); - - it('should build the url properly', () => { - const result = service.getOrcidAuthorizeUrl(mockItemUnlinkedToOrcid); - const redirectUri: string = new URLCombiner(nativeWindowService.nativeWindow.origin, encodeURIComponent(routerStub.url.split('?')[0])).toString(); - const url = 'orcid.authorize-url?client_id=orcid.application-client-id&redirect_uri=' + redirectUri + '&response_type=code&scope=/authenticate /read-limited'; - - const expected = cold('(a|)', { - a: url - }); - expect(result).toBeObservable(expected); - }); - }); - describe('updateByOrcidOperations', () => { beforeEach(() => { scheduler = getTestScheduler(); @@ -543,34 +416,4 @@ describe('ResearcherProfileService', () => { expect((service as any).dataService.patch).toHaveBeenCalledWith(researcherProfile, []); }); }); - - describe('getOrcidAuthorizationScopesByItem', () => { - it('should return list of scopes saved in the item', () => { - const orcidScopes = [ - '/authenticate', - '/read-limited', - '/activities/update', - '/person/update' - ]; - const result = service.getOrcidAuthorizationScopesByItem(mockItemLinkedToOrcid); - expect(result).toEqual(orcidScopes); - }); - }); - - describe('getOrcidAuthorizationScopes', () => { - it('should return list of scopes by configuration', () => { - (service as any).configurationService.findByPropertyName.and.returnValue( - createSuccessfulRemoteDataObject$(orcidScope) - ); - const orcidScopes = [ - '/authenticate', - '/read-limited' - ]; - const expected = cold('(a|)', { - a: orcidScopes - }); - const result = service.getOrcidAuthorizationScopes(); - expect(result).toBeObservable(expected); - }); - }); }); diff --git a/src/app/core/profile/researcher-profile.service.ts b/src/app/core/profile/researcher-profile.service.ts index 0ceb851e2c..882845d133 100644 --- a/src/app/core/profile/researcher-profile.service.ts +++ b/src/app/core/profile/researcher-profile.service.ts @@ -1,41 +1,33 @@ /* eslint-disable max-classes-per-file */ import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Inject, Injectable } from '@angular/core'; +import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; -import { AddOperation, Operation, RemoveOperation, ReplaceOperation } from 'fast-json-patch'; -import { combineLatest, Observable } from 'rxjs'; -import { find, map, switchMap } from 'rxjs/operators'; +import { Operation, ReplaceOperation } from 'fast-json-patch'; +import { Observable } from 'rxjs'; +import { find, map } from 'rxjs/operators'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { ConfigurationDataService } from '../data/configuration-data.service'; import { DataService } from '../data/data.service'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; import { ItemDataService } from '../data/item-data.service'; import { RemoteData } from '../data/remote-data'; import { RequestService } from '../data/request.service'; -import { ConfigurationProperty } from '../shared/configuration-property.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { NoContent } from '../shared/NoContent.model'; -import { - getAllCompletedRemoteData, - getFirstCompletedRemoteData, - getFirstSucceededRemoteDataPayload -} from '../shared/operators'; +import { getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../shared/operators'; import { ResearcherProfile } from './model/researcher-profile.model'; import { RESEARCHER_PROFILE } from './model/researcher-profile.resource-type'; import { HttpOptions } from '../dspace-rest/dspace-rest.service'; import { PostRequest } from '../data/request.models'; -import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isEmpty } from '../../shared/empty.util'; import { CoreState } from '../core-state.model'; import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { Item } from '../shared/item.model'; import { createFailedRemoteDataObject$ } from '../../shared/remote-data.utils'; -import { NativeWindowRef, NativeWindowService } from '../services/window.service'; -import { URLCombiner } from '../url-combiner/url-combiner'; /** * A private DataService implementation to delegate specific methods to. @@ -69,7 +61,6 @@ export class ResearcherProfileService { protected responseMsToLive: number = 10 * 1000; constructor( - @Inject(NativeWindowService) protected _window: NativeWindowRef, protected requestService: RequestService, protected rdbService: RemoteDataBuildService, protected objectCache: ObjectCacheService, @@ -78,8 +69,7 @@ export class ResearcherProfileService { protected http: HttpClient, protected router: Router, protected comparator: DefaultChangeAnalyzer, - protected itemService: ItemDataService, - protected configurationService: ConfigurationDataService) { + protected itemService: ItemDataService) { this.dataService = new ResearcherProfileServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); @@ -165,98 +155,6 @@ export class ResearcherProfileService { return this.dataService.patch(researcherProfile, [replaceOperation]); } - /** - * Check if the given item is linked to an ORCID profile. - * - * @param item the item to check - * @returns the check result - */ - public isLinkedToOrcid(item: Item): boolean { - return item.hasMetadata('dspace.orcid.authenticated'); - } - - /** - * Returns true if only the admin users can disconnect a researcher profile from ORCID. - * - * @returns the check result - */ - public onlyAdminCanDisconnectProfileFromOrcid(): Observable { - return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe( - map((propertyRD: RemoteData) => { - return propertyRD.hasSucceeded && propertyRD.payload.values.map((value) => value.toLowerCase()).includes('only_admin'); - }) - ); - } - - /** - * Returns true if the profile's owner can disconnect that profile from ORCID. - * - * @returns the check result - */ - public ownerCanDisconnectProfileFromOrcid(): Observable { - return this.getOrcidDisconnectionAllowedUsersConfiguration().pipe( - map((propertyRD: RemoteData) => { - return propertyRD.hasSucceeded && propertyRD.payload.values.map( (value) => value.toLowerCase()).includes('admin_and_owner'); - }) - ); - } - - /** - * Perform a link operation to ORCID profile. - * - * @param person The person item related to the researcher profile - * @param code The auth-code received from orcid - */ - public linkOrcidByItem(person: Item, code: string): Observable> { - const operations: AddOperation[] = [{ - path: '/orcid', - op: 'add', - value: code - }]; - - return this.findById(person.firstMetadata('dspace.object.owner').authority).pipe( - getFirstCompletedRemoteData(), - switchMap((profileRD) => this.updateByOrcidOperations(profileRD.payload, operations)) - ); - } - - /** - * Perform unlink operation from ORCID profile. - * - * @param person The person item related to the researcher profile - */ - public unlinkOrcidByItem(person: Item): Observable> { - const operations: RemoveOperation[] = [{ - path:'/orcid', - op:'remove' - }]; - - return this.findById(person.firstMetadata('dspace.object.owner').authority).pipe( - getFirstCompletedRemoteData(), - switchMap((profileRD) => this.updateByOrcidOperations(profileRD.payload, operations)) - ); - } - - /** - * Build and return the url to authenticate with orcid - * - * @param profile - */ - public getOrcidAuthorizeUrl(profile: Item): Observable { - return combineLatest([ - this.configurationService.findByPropertyName('orcid.authorize-url').pipe(getFirstSucceededRemoteDataPayload()), - this.configurationService.findByPropertyName('orcid.application-client-id').pipe(getFirstSucceededRemoteDataPayload()), - this.configurationService.findByPropertyName('orcid.scope').pipe(getFirstSucceededRemoteDataPayload())] - ).pipe( - map(([authorizeUrl, clientId, scopes]) => { - console.log(this._window.nativeWindow.origin, this.router.url); - const redirectUri = new URLCombiner(this._window.nativeWindow.origin, encodeURIComponent(this.router.url.split('?')[0])); - console.log(redirectUri.toString()); - return authorizeUrl.values[0] + '?client_id=' + clientId.values[0] + '&redirect_uri=' + redirectUri + '&response_type=code&scope=' - + scopes.values.join(' '); - })); - } - /** * Creates a researcher profile starting from an external source URI * @param sourceUri URI of source item of researcher profile. @@ -291,29 +189,6 @@ export class ResearcherProfileService { return this.dataService.patch(researcherProfile, operations); } - /** - * Return all orcid authorization scopes saved in the given item - * - * @param item - */ - public getOrcidAuthorizationScopesByItem(item: Item): string[] { - return isNotEmpty(item) ? item.allMetadataValues('dspace.orcid.scope') : []; - } - /** - * Return all orcid authorization scopes available by configuration - */ - public getOrcidAuthorizationScopes(): Observable { - return this.configurationService.findByPropertyName('orcid.scope').pipe( - getFirstCompletedRemoteData(), - map((propertyRD: RemoteData) => propertyRD.hasSucceeded ? propertyRD.payload.values : []) - ); - } - - private getOrcidDisconnectionAllowedUsersConfiguration(): Observable> { - return this.configurationService.findByPropertyName('orcid.disconnection.allowed-users').pipe( - getFirstCompletedRemoteData() - ); - } } diff --git a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.spec.ts b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.spec.ts index 6b5f2d8593..e96e5996fb 100644 --- a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.spec.ts @@ -9,7 +9,7 @@ import { of } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { ResearcherProfileService } from '../../../core/profile/researcher-profile.service'; +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { Item } from '../../../core/shared/item.model'; import { createPaginatedList } from '../../../shared/testing/utils.test'; @@ -25,7 +25,7 @@ describe('OrcidAuthComponent test suite', () => { let comp: OrcidAuthComponent; let fixture: ComponentFixture; let scheduler: TestScheduler; - let researcherProfileService: jasmine.SpyObj; + let orcidAuthService: jasmine.SpyObj; let nativeWindowRef; let notificationsService; @@ -112,7 +112,7 @@ describe('OrcidAuthComponent test suite', () => { }); beforeEach(waitForAsync(() => { - researcherProfileService = jasmine.createSpyObj('researcherProfileService', { + orcidAuthService = jasmine.createSpyObj('researcherProfileService', { getOrcidAuthorizationScopes: jasmine.createSpy('getOrcidAuthorizationScopes'), getOrcidAuthorizationScopesByItem: jasmine.createSpy('getOrcidAuthorizationScopesByItem'), getOrcidAuthorizeUrl: jasmine.createSpy('getOrcidAuthorizeUrl'), @@ -137,7 +137,7 @@ describe('OrcidAuthComponent test suite', () => { providers: [ { provide: NativeWindowService, useFactory: NativeWindowMockFactory }, { provide: NotificationsService, useClass: NotificationsServiceStub }, - { provide: ResearcherProfileService, useValue: researcherProfileService } + { provide: OrcidAuthService, useValue: orcidAuthService } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(OrcidAuthComponent, { @@ -149,17 +149,17 @@ describe('OrcidAuthComponent test suite', () => { scheduler = getTestScheduler(); fixture = TestBed.createComponent(OrcidAuthComponent); comp = fixture.componentInstance; - researcherProfileService.getOrcidAuthorizationScopes.and.returnValue(of(orcidScopes)); + orcidAuthService.getOrcidAuthorizationScopes.and.returnValue(of(orcidScopes)); })); describe('when orcid profile is not linked', () => { beforeEach(waitForAsync(() => { comp.item = mockItemUnlinkedToOrcid; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([]); - researcherProfileService.isLinkedToOrcid.and.returnValue(false); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); - researcherProfileService.getOrcidAuthorizeUrl.and.returnValue(of('oarcidUrl')); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([]); + orcidAuthService.isLinkedToOrcid.and.returnValue(false); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.getOrcidAuthorizeUrl.and.returnValue(of('oarcidUrl')); fixture.detectChanges(); })); @@ -183,7 +183,7 @@ describe('OrcidAuthComponent test suite', () => { describe('when orcid profile is linked', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); })); describe('', () => { @@ -191,16 +191,16 @@ describe('OrcidAuthComponent test suite', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; notificationsService = (comp as any).notificationsService; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); - researcherProfileService.isLinkedToOrcid.and.returnValue(true); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); })); describe('and unlink is successfully', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.unlinkOrcidByItem.and.returnValue(createSuccessfulRemoteDataObject$(new ResearcherProfile())); + orcidAuthService.unlinkOrcidByItem.and.returnValue(createSuccessfulRemoteDataObject$(new ResearcherProfile())); spyOn(comp.unlink, 'emit'); fixture.detectChanges(); })); @@ -217,7 +217,7 @@ describe('OrcidAuthComponent test suite', () => { describe('and unlink is failed', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.unlinkOrcidByItem.and.returnValue(createFailedRemoteDataObject$()); + orcidAuthService.unlinkOrcidByItem.and.returnValue(createFailedRemoteDataObject$()); fixture.detectChanges(); })); @@ -234,10 +234,10 @@ describe('OrcidAuthComponent test suite', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); - researcherProfileService.isLinkedToOrcid.and.returnValue(true); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); fixture.detectChanges(); })); @@ -263,10 +263,10 @@ describe('OrcidAuthComponent test suite', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([...partialOrcidScopes]); - researcherProfileService.isLinkedToOrcid.and.returnValue(true); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([...partialOrcidScopes]); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(false)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); fixture.detectChanges(); })); @@ -294,10 +294,10 @@ describe('OrcidAuthComponent test suite', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); - researcherProfileService.isLinkedToOrcid.and.returnValue(true); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(true)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(false)); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(false)); fixture.detectChanges(); })); @@ -314,10 +314,10 @@ describe('OrcidAuthComponent test suite', () => { beforeEach(waitForAsync(() => { comp.item = mockItemLinkedToOrcid; - researcherProfileService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); - researcherProfileService.isLinkedToOrcid.and.returnValue(true); - researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(true)); - researcherProfileService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.getOrcidAuthorizationScopesByItem.and.returnValue([...orcidScopes]); + orcidAuthService.isLinkedToOrcid.and.returnValue(true); + orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid.and.returnValue(of(true)); + orcidAuthService.ownerCanDisconnectProfileFromOrcid.and.returnValue(of(true)); fixture.detectChanges(); })); diff --git a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.ts b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.ts index b052fdedd8..ea970e7d31 100644 --- a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.ts +++ b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.ts @@ -3,14 +3,13 @@ import { Component, EventEmitter, Inject, Input, OnChanges, OnInit, Output, Simp import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; - -import { ResearcherProfileService } from '../../../core/profile/researcher-profile.service'; import { NativeWindowRef, NativeWindowService } from '../../../core/services/window.service'; import { Item } from '../../../core/shared/item.model'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { RemoteData } from '../../../core/data/remote-data'; import { ResearcherProfile } from '../../../core/profile/model/researcher-profile.model'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; @Component({ selector: 'ds-orcid-auth', @@ -65,7 +64,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges { @Output() unlink: EventEmitter = new EventEmitter(); constructor( - private researcherProfileService: ResearcherProfileService, + private orcidAuthService: OrcidAuthService, private translateService: TranslateService, private notificationsService: NotificationsService, @Inject(NativeWindowService) private _window: NativeWindowRef, @@ -73,7 +72,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges { } ngOnInit() { - this.researcherProfileService.getOrcidAuthorizationScopes().subscribe((scopes: string[]) => { + this.orcidAuthService.getOrcidAuthorizationScopes().subscribe((scopes: string[]) => { this.orcidAuthorizationScopes.next(scopes); this.initOrcidAuthSettings(); }); @@ -160,7 +159,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges { * Link existing person profile with orcid */ linkOrcid(): void { - this.researcherProfileService.getOrcidAuthorizeUrl(this.item).subscribe((authorizeUrl) => { + this.orcidAuthService.getOrcidAuthorizeUrl(this.item).subscribe((authorizeUrl) => { this._window.nativeWindow.location.href = authorizeUrl; }); } @@ -170,7 +169,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges { */ unlinkOrcid(): void { this.unlinkProcessing.next(true); - this.researcherProfileService.unlinkOrcidByItem(this.item).pipe( + this.orcidAuthService.unlinkOrcidByItem(this.item).pipe( getFirstCompletedRemoteData() ).subscribe((remoteData: RemoteData) => { this.unlinkProcessing.next(false); @@ -193,19 +192,19 @@ export class OrcidAuthComponent implements OnInit, OnChanges { this.setMissingOrcidAuthorizations(); - this.researcherProfileService.onlyAdminCanDisconnectProfileFromOrcid().subscribe((result) => { + this.orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid().subscribe((result) => { this.onlyAdminCanDisconnectProfileFromOrcid$.next(result); }); - this.researcherProfileService.ownerCanDisconnectProfileFromOrcid().subscribe((result) => { + this.orcidAuthService.ownerCanDisconnectProfileFromOrcid().subscribe((result) => { this.ownerCanDisconnectProfileFromOrcid$.next(result); }); - this.isOrcidLinked$.next(this.researcherProfileService.isLinkedToOrcid(this.item)); + this.isOrcidLinked$.next(this.orcidAuthService.isLinkedToOrcid(this.item)); } private setMissingOrcidAuthorizations(): void { - const profileScopes = this.researcherProfileService.getOrcidAuthorizationScopesByItem(this.item); + const profileScopes = this.orcidAuthService.getOrcidAuthorizationScopesByItem(this.item); const orcidScopes = this.orcidAuthorizationScopes.value; const missingScopes = orcidScopes.filter((scope) => !profileScopes.includes(scope)); @@ -213,7 +212,7 @@ export class OrcidAuthComponent implements OnInit, OnChanges { } private setOrcidAuthorizationsFromItem(): void { - this.profileAuthorizationScopes.next(this.researcherProfileService.getOrcidAuthorizationScopesByItem(this.item)); + this.profileAuthorizationScopes.next(this.orcidAuthService.getOrcidAuthorizationScopesByItem(this.item)); } } diff --git a/src/app/item-page/orcid-page/orcid-page.component.spec.ts b/src/app/item-page/orcid-page/orcid-page.component.spec.ts index a4af5edf5c..1ed237943e 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-page.component.spec.ts @@ -11,7 +11,6 @@ import { getTestScheduler } from 'jasmine-marbles'; import { AuthService } from '../../core/auth/auth.service'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; -import { ResearcherProfileService } from '../../core/profile/researcher-profile.service'; import { OrcidPageComponent } from './orcid-page.component'; import { createFailedRemoteDataObject$, @@ -23,6 +22,7 @@ import { createPaginatedList } from '../../shared/testing/utils.test'; import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock'; import { ItemDataService } from '../../core/data/item-data.service'; import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model'; +import { OrcidAuthService } from '../../core/orcid/orcid-auth.service'; describe('OrcidPageComponent test suite', () => { let comp: OrcidPageComponent; @@ -32,7 +32,7 @@ describe('OrcidPageComponent test suite', () => { let routeStub: jasmine.SpyObj; let routeData: any; let itemDataService: jasmine.SpyObj; - let researcherProfileService: jasmine.SpyObj; + let orcidAuthService: jasmine.SpyObj; const mockResearcherProfile: ResearcherProfile = Object.assign(new ResearcherProfile(), { id: 'test-id', @@ -88,7 +88,7 @@ describe('OrcidPageComponent test suite', () => { routeStub = new ActivatedRouteStub({}, routeData); - researcherProfileService = jasmine.createSpyObj('researcherProfileService', { + orcidAuthService = jasmine.createSpyObj('OrcidAuthService', { isLinkedToOrcid: jasmine.createSpy('isLinkedToOrcid'), linkOrcidByItem: jasmine.createSpy('linkOrcidByItem'), }); @@ -110,7 +110,7 @@ describe('OrcidPageComponent test suite', () => { declarations: [OrcidPageComponent], providers: [ { provide: ActivatedRoute, useValue: routeStub }, - { provide: ResearcherProfileService, useValue: researcherProfileService }, + { provide: OrcidAuthService, useValue: orcidAuthService }, { provide: AuthService, useValue: authService }, { provide: ItemDataService, useValue: itemDataService }, { provide: PLATFORM_ID, useValue: 'browser' }, @@ -146,7 +146,7 @@ describe('OrcidPageComponent test suite', () => { it('should call isLinkedToOrcid', () => { comp.isLinkedToOrcid(); - expect(researcherProfileService.isLinkedToOrcid).toHaveBeenCalledWith(comp.item.value); + expect(orcidAuthService.isLinkedToOrcid).toHaveBeenCalledWith(comp.item.value); }); it('should update item', fakeAsync(() => { @@ -168,13 +168,13 @@ describe('OrcidPageComponent test suite', () => { describe('and linking to orcid profile is successfully', () => { beforeEach(waitForAsync(() => { - researcherProfileService.linkOrcidByItem.and.returnValue(createSuccessfulRemoteDataObject$(mockResearcherProfile)); + orcidAuthService.linkOrcidByItem.and.returnValue(createSuccessfulRemoteDataObject$(mockResearcherProfile)); itemDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(mockItemLinkedToOrcid)); fixture.detectChanges(); })); it('should call linkOrcidByItem', () => { - expect(researcherProfileService.linkOrcidByItem).toHaveBeenCalledWith(mockItem, 'orcid-code'); + expect(orcidAuthService.linkOrcidByItem).toHaveBeenCalledWith(mockItem, 'orcid-code'); expect(comp.updateItem).toHaveBeenCalled(); }); @@ -193,13 +193,13 @@ describe('OrcidPageComponent test suite', () => { describe('and linking to orcid profile is failed', () => { beforeEach(waitForAsync(() => { - researcherProfileService.linkOrcidByItem.and.returnValue(createFailedRemoteDataObject$()); + orcidAuthService.linkOrcidByItem.and.returnValue(createFailedRemoteDataObject$()); itemDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(mockItemLinkedToOrcid)); fixture.detectChanges(); })); it('should call linkOrcidByItem', () => { - expect(researcherProfileService.linkOrcidByItem).toHaveBeenCalledWith(mockItem, 'orcid-code'); + expect(orcidAuthService.linkOrcidByItem).toHaveBeenCalledWith(mockItem, 'orcid-code'); expect(comp.updateItem).not.toHaveBeenCalled(); }); diff --git a/src/app/item-page/orcid-page/orcid-page.component.ts b/src/app/item-page/orcid-page/orcid-page.component.ts index a4628eed93..f3dbb569d9 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.ts +++ b/src/app/item-page/orcid-page/orcid-page.component.ts @@ -1,10 +1,11 @@ import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { isPlatformBrowser } from '@angular/common'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { ResearcherProfileService } from '../../core/profile/researcher-profile.service'; +import { OrcidAuthService } from '../../core/orcid/orcid-auth.service'; import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../core/shared/operators'; import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; @@ -14,7 +15,6 @@ import { redirectOn4xx } from '../../core/shared/authorized.operators'; import { ItemDataService } from '../../core/data/item-data.service'; import { isNotEmpty } from '../../shared/empty.util'; import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model'; -import { isPlatformBrowser } from '@angular/common'; /** * A component that represents the orcid settings page @@ -50,7 +50,7 @@ export class OrcidPageComponent implements OnInit { @Inject(PLATFORM_ID) private platformId: any, private authService: AuthService, private itemService: ItemDataService, - private researcherProfileService: ResearcherProfileService, + private orcidAuthService: OrcidAuthService, private route: ActivatedRoute, private router: Router ) { @@ -95,7 +95,7 @@ export class OrcidPageComponent implements OnInit { * @returns the check result */ isLinkedToOrcid(): boolean { - return this.researcherProfileService.isLinkedToOrcid(this.item.value); + return this.orcidAuthService.isLinkedToOrcid(this.item.value); } /** @@ -126,7 +126,7 @@ export class OrcidPageComponent implements OnInit { * @param code The auth-code received from ORCID */ private linkProfileToOrcid(person: Item, code: string) { - this.researcherProfileService.linkOrcidByItem(person, code).pipe( + this.orcidAuthService.linkOrcidByItem(person, code).pipe( getFirstCompletedRemoteData() ).subscribe((profileRD: RemoteData) => { this.processingConnection.next(false); diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index accd5e57a5..c39e48b8fe 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -16,13 +16,14 @@ import { createPaginatedList } from '../../../shared/testing/utils.test'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { By } from '@angular/platform-browser'; import { Item } from '../../../core/shared/item.model'; - +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; describe('OrcidQueueComponent test suite', () => { let component: OrcidQueueComponent; let fixture: ComponentFixture; let debugElement: DebugElement; let orcidQueueService: OrcidQueueService; + let orcidAuthService: jasmine.SpyObj; const testOwnerId = 'test-owner-id'; @@ -102,6 +103,10 @@ describe('OrcidQueueComponent test suite', () => { orcidQueueServiceSpy.searchByOwnerId.and.returnValue(createSuccessfulRemoteDataObject$>(createPaginatedList(orcidQueueElements))); beforeEach(waitForAsync(() => { + orcidAuthService = jasmine.createSpyObj('OrcidAuthService', { + getOrcidAuthorizeUrl: jasmine.createSpy('getOrcidAuthorizeUrl') + }); + void TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot({ @@ -114,6 +119,7 @@ describe('OrcidQueueComponent test suite', () => { ], declarations: [OrcidQueueComponent], providers: [ + { provide: OrcidAuthService, useValue: orcidAuthService }, { provide: OrcidQueueService, useValue: orcidQueueServiceSpy }, { provide: OrcidHistoryDataService, useValue: {} }, { provide: PaginationService, useValue: new PaginationServiceStub() }, diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 27f98598a7..c068465829 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -17,6 +17,7 @@ import { NotificationsService } from '../../../shared/notifications/notification import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { AlertType } from '../../../shared/alert/aletr-type'; import { Item } from '../../../core/shared/item.model'; +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; @Component({ selector: 'ds-orcid-queue', @@ -60,7 +61,8 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { */ private subs: Subscription[] = []; - constructor(private orcidQueueService: OrcidQueueService, + constructor(private orcidAuthService: OrcidAuthService, + private orcidQueueService: OrcidQueueService, protected translateService: TranslateService, private paginationService: PaginationService, private notificationsService: NotificationsService, @@ -228,8 +230,11 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { * @private */ private getUnauthorizedErrorContent(): Observable { - return this.orcidQueueService.getOrcidAuthorizeUrl(this.item.id).pipe( - switchMap((authorizeUrl) => this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.content', { orcid: authorizeUrl })) + return this.orcidAuthService.getOrcidAuthorizeUrl(this.item).pipe( + switchMap((authorizeUrl) => this.translateService.get( + 'person.page.orcid.sync-queue.send.unauthorized-error.content', + { orcid: authorizeUrl } + )) ); } @@ -246,24 +251,24 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { this.updateList(); break; case 400: - this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.bad-request-error'), null, { timeOut: -1 }); + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.bad-request-error'), null, { timeOut: 0 }); break; case 401: combineLatest([ this.translateService.get('person.page.orcid.sync-queue.send.unauthorized-error.title'), this.getUnauthorizedErrorContent()], ).subscribe(([title, content]) => { - this.notificationsService.error(title, content, { timeOut: -1 }, true); + this.notificationsService.error(title, content, { timeOut: 0 }, true); }); break; case 404: this.notificationsService.warning(this.translateService.get('person.page.orcid.sync-queue.send.not-found-warning')); break; case 409: - this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.conflict-error'), null, { timeOut: -1 }); + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.conflict-error'), null, { timeOut: 0 }); break; default: - this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.error'), null, { timeOut: -1 }); + this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.send.error'), null, { timeOut: 0 }); } } @@ -281,11 +286,10 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { combineLatest(translations).subscribe((messages) => { const title = messages.shift(); const content = '
    ' + messages.map((message) => `
  • ${message}
  • `).join('') + '
'; - this.notificationsService.error(title, content, { timeOut: -1 }, true); + this.notificationsService.error(title, content, { timeOut: 0 }, true); }); } - /** * Unsubscribe from all subscriptions */ From 5eb635585889e15172ab6e457443de1d8616328b Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 16 Jun 2022 15:44:18 +0200 Subject: [PATCH 051/103] [CST-5339] Make action color as primary --- .../item-page/orcid-page/orcid-queue/orcid-queue.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index fc8eb3c4cf..9358bcf835 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -33,7 +33,7 @@
From 555d98f7003f4e1ad85184ec99df3eacd0b360d8 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Mon, 20 Jun 2022 19:05:57 +0200 Subject: [PATCH 058/103] [CST-5339] Improved project synchronization --- .../item-page/orcid-page/orcid-queue/orcid-queue.component.ts | 2 +- src/assets/i18n/en.json5 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 486ff670d5..99ba33ee82 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -118,7 +118,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy { switch (orcidQueue.recordType.toLowerCase()) { case 'publication': return 'fas fa-book'; - case 'funding': + case 'project': return 'fas fa-wallet'; case 'education': return 'fas fa-school'; diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 5603ea27e8..076d2e80c8 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4608,7 +4608,7 @@ "person.page.orcid.sync-queue.tooltip.publication": "Publication", - "person.page.orcid.sync-queue.tooltip.funding": "Funding", + "person.page.orcid.sync-queue.tooltip.project": "Project", "person.page.orcid.sync-queue.tooltip.affiliation": "Affiliation", From 7724db530b94a90e3e60e660afed7fbffbf50a65 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Tue, 21 Jun 2022 11:32:09 +0200 Subject: [PATCH 059/103] [CST-5339] Added ORCID label --- src/assets/i18n/en.json5 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 076d2e80c8..3d5f15b4f2 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3735,6 +3735,8 @@ "submission.import-external.source.wos": "Web Of Science", + "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.epo": "European Patent Office (EPO)", "submission.import-external.source.loading": "Loading ...", From 20314d462009dba9a852be10ab59e3fdab5a7708 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 21 Jun 2022 13:37:42 +0200 Subject: [PATCH 060/103] [CST-6056] Fix issue with authority suggestion by adding the filter query in the input suggestion object --- .../filter-input-suggestions.component.html | 2 +- .../filter-input-suggestions.component.spec.ts | 2 +- .../filter-input-suggestions.component.ts | 4 ++-- .../input-suggestions/input-suggestions.model.ts | 8 ++++++++ .../search-authority-filter.component.ts | 10 ---------- .../search-facet-filter.component.ts | 11 ++++++----- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html b/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html index 3b150a46c9..726dc9ca0e 100644 --- a/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html +++ b/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html @@ -27,7 +27,7 @@