From 6a016cd17f49c95e0e58709fd0c9dc3b5cceff39 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 20 Oct 2020 16:40:01 +0200 Subject: [PATCH 01/26] 74199: ItemResolver item to dso refactor --- .../abstract-item-update/abstract-item-update.component.ts | 2 +- src/app/+item-page/edit-item-page/edit-item-page.component.ts | 2 +- .../item-authorizations/item-authorizations.component.spec.ts | 2 +- .../item-authorizations/item-authorizations.component.ts | 2 +- .../item-bitstreams/item-bitstreams.component.spec.ts | 2 +- .../item-collection-mapper.component.spec.ts | 2 +- .../item-collection-mapper/item-collection-mapper.component.ts | 2 +- .../edit-item-page/item-delete/item-delete.component.spec.ts | 2 +- .../item-metadata/item-metadata.component.spec.ts | 2 +- .../edit-item-page/item-move/item-move.component.spec.ts | 2 +- .../+item-page/edit-item-page/item-move/item-move.component.ts | 2 +- .../edit-item-page/item-private/item-private.component.spec.ts | 2 +- .../edit-item-page/item-public/item-public.component.spec.ts | 2 +- .../item-reinstate/item-reinstate.component.spec.ts | 2 +- .../item-relationships/item-relationships.component.spec.ts | 2 +- .../item-withdraw/item-withdraw.component.spec.ts | 2 +- .../abstract-simple-item-action.component.spec.ts | 2 +- .../simple-item-action/abstract-simple-item-action.component.ts | 2 +- src/app/+item-page/full/full-item-page.component.spec.ts | 2 +- src/app/+item-page/item-page-routing.module.ts | 2 +- src/app/+item-page/simple/item-page.component.spec.ts | 2 +- src/app/+item-page/simple/item-page.component.ts | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts b/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts index bde2b5a1b0..f3055d3e51 100644 --- a/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts +++ b/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts @@ -48,7 +48,7 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl ngOnInit(): void { observableCombineLatest(this.route.data, this.route.parent.data).pipe( map(([data, parentData]) => Object.assign({}, data, parentData)), - map((data) => data.item), + map((data) => data.dso), first(), map((data: RemoteData) => data.payload) ).subscribe((item: Item) => { diff --git a/src/app/+item-page/edit-item-page/edit-item-page.component.ts b/src/app/+item-page/edit-item-page/edit-item-page.component.ts index 655582064c..2bd9a30ca3 100644 --- a/src/app/+item-page/edit-item-page/edit-item-page.component.ts +++ b/src/app/+item-page/edit-item-page/edit-item-page.component.ts @@ -47,7 +47,7 @@ export class EditItemPageComponent implements OnInit { this.pages = this.route.routeConfig.children .map((child: any) => child.path) .filter((path: string) => isNotEmpty(path)); // ignore reroutes - this.itemRD$ = this.route.data.pipe(map((data) => data.item)); + this.itemRD$ = this.route.data.pipe(map((data) => data.dso)); } /** diff --git a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.spec.ts b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.spec.ts index c687c829eb..dcf70a30cb 100644 --- a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.spec.ts @@ -74,7 +74,7 @@ describe('ItemAuthorizationsComponent test suite', () => { const routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject(item) + dso: createSuccessfulRemoteDataObject(item) }) }; diff --git a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index 8153990a02..8b89de7c89 100644 --- a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -75,7 +75,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { */ ngOnInit(): void { this.item$ = this.route.data.pipe( - map((data) => data.item), + map((data) => data.dso), getFirstSucceededRemoteDataWithNotEmptyPayload(), map((item: Item) => this.linkService.resolveLink( item, diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.spec.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.spec.ts index f86c57d69e..5f6e3a06c4 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.spec.ts @@ -140,7 +140,7 @@ describe('ItemBitstreamsComponent', () => { }); route = Object.assign({ parent: { - data: observableOf({ item: createMockRD(item) }) + data: observableOf({ dso: createMockRD(item) }) }, data: observableOf({}), url: url diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts index 15b860a782..9aeb1522a6 100644 --- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts @@ -89,7 +89,7 @@ describe('ItemCollectionMapperComponent', () => { clearDiscoveryRequests: () => {} /* tslint:enable:no-empty */ }); - const activatedRouteStub = new ActivatedRouteStub({}, { item: mockItemRD }); + const activatedRouteStub = new ActivatedRouteStub({}, { dso: mockItemRD }); const translateServiceStub = { get: () => of('test-message of item ' + mockItem.name), onLangChange: new EventEmitter(), diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts index 1409e06ddb..df406f826b 100644 --- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts +++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts @@ -92,7 +92,7 @@ export class ItemCollectionMapperComponent implements OnInit { } ngOnInit(): void { - this.itemRD$ = this.route.data.pipe(map((data) => data.item)).pipe(getSucceededRemoteData()) as Observable>; + this.itemRD$ = this.route.data.pipe(map((data) => data.dso)).pipe(getSucceededRemoteData()) as Observable>; this.searchOptions$ = this.searchConfigService.paginatedSearchOptions; this.loadCollectionLists(); } diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts index 18cbd6e855..e7b454e92b 100644 --- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts @@ -138,7 +138,7 @@ describe('ItemDeleteComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject(mockItem) + dso: createSuccessfulRemoteDataObject(mockItem) }) }; diff --git a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts index ed9ab4a891..f30b5cc3b0 100644 --- a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts @@ -130,7 +130,7 @@ describe('ItemMetadataComponent', () => { routeStub = { data: observableOf({}), parent: { - data: observableOf({ item: createSuccessfulRemoteDataObject(item) }) + data: observableOf({ dso: createSuccessfulRemoteDataObject(item) }) } }; paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]); diff --git a/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts b/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts index 77aefe2356..c8c49b118b 100644 --- a/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts @@ -44,7 +44,7 @@ describe('ItemMoveComponent', () => { const routeStub = { data: observableOf({ - item: new RemoteData(false, false, true, null, { + dso: new RemoteData(false, false, true, null, { id: 'item1' }) }) diff --git a/src/app/+item-page/edit-item-page/item-move/item-move.component.ts b/src/app/+item-page/edit-item-page/item-move/item-move.component.ts index abadd2ec4a..1a544af7dc 100644 --- a/src/app/+item-page/edit-item-page/item-move/item-move.component.ts +++ b/src/app/+item-page/edit-item-page/item-move/item-move.component.ts @@ -55,7 +55,7 @@ export class ItemMoveComponent implements OnInit { } ngOnInit(): void { - this.itemRD$ = this.route.data.pipe(map((data) => data.item), getSucceededRemoteData()) as Observable>; + this.itemRD$ = this.route.data.pipe(map((data) => data.dso), getSucceededRemoteData()) as Observable>; this.itemRD$.subscribe((rd) => { this.itemId = rd.payload.id; } diff --git a/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts b/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts index 95b08a9936..52ccbc2133 100644 --- a/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts @@ -51,7 +51,7 @@ describe('ItemPrivateComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject({ + dso: createSuccessfulRemoteDataObject({ id: 'fake-id' }) }) diff --git a/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts b/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts index 53df20bf04..1143874709 100644 --- a/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts @@ -51,7 +51,7 @@ describe('ItemPublicComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject({ + dso: createSuccessfulRemoteDataObject({ id: 'fake-id' }) }) diff --git a/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts b/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts index 5e75b59292..005f330df9 100644 --- a/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts @@ -51,7 +51,7 @@ describe('ItemReinstateComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject({ + dso: createSuccessfulRemoteDataObject({ id: 'fake-id' }) }) diff --git a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts index 5e657ae09d..17fede115e 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts @@ -142,7 +142,7 @@ describe('ItemRelationshipsComponent', () => { routeStub = { data: observableOf({}), parent: { - data: observableOf({ item: new RemoteData(false, false, true, null, item) }) + data: observableOf({ dso: new RemoteData(false, false, true, null, item) }) } }; diff --git a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts index 249298c092..aa6a3e537a 100644 --- a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts @@ -51,7 +51,7 @@ describe('ItemWithdrawComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject({ + dso: createSuccessfulRemoteDataObject({ id: 'fake-id' }) }) diff --git a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts index e6c5cfefc0..31c8a6f808 100644 --- a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts +++ b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts @@ -74,7 +74,7 @@ describe('AbstractSimpleItemActionComponent', () => { routeStub = { data: observableOf({ - item: createSuccessfulRemoteDataObject({ + dso: createSuccessfulRemoteDataObject({ id: 'fake-id' }) }) diff --git a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.ts b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.ts index ca347e1298..1bd8782a30 100644 --- a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.ts +++ b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.ts @@ -42,7 +42,7 @@ export class AbstractSimpleItemActionComponent implements OnInit { ngOnInit(): void { this.itemRD$ = this.route.data.pipe( - map((data) => data.item), + map((data) => data.dso), getSucceededRemoteData() )as Observable>; diff --git a/src/app/+item-page/full/full-item-page.component.spec.ts b/src/app/+item-page/full/full-item-page.component.spec.ts index 0512ea2fef..af966a2530 100644 --- a/src/app/+item-page/full/full-item-page.component.spec.ts +++ b/src/app/+item-page/full/full-item-page.component.spec.ts @@ -34,7 +34,7 @@ const mockItem: Item = Object.assign(new Item(), { } }); const routeStub = Object.assign(new ActivatedRouteStub(), { - data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) }) + data: observableOf({ dso: createSuccessfulRemoteDataObject(mockItem) }) }); const metadataServiceStub = { /* tslint:disable:no-empty */ diff --git a/src/app/+item-page/item-page-routing.module.ts b/src/app/+item-page/item-page-routing.module.ts index e4f17326a4..022d905ff3 100644 --- a/src/app/+item-page/item-page-routing.module.ts +++ b/src/app/+item-page/item-page-routing.module.ts @@ -20,7 +20,7 @@ import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model'; { path: ':id', resolve: { - item: ItemPageResolver, + dso: ItemPageResolver, breadcrumb: ItemBreadcrumbResolver }, runGuardsAndResolvers: 'always', 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 6c26e75908..c2dd0b7015 100644 --- a/src/app/+item-page/simple/item-page.component.spec.ts +++ b/src/app/+item-page/simple/item-page.component.spec.ts @@ -37,7 +37,7 @@ describe('ItemPageComponent', () => { /* tslint:enable:no-empty */ }; const mockRoute = Object.assign(new ActivatedRouteStub(), { - data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) }) + data: observableOf({ dso: createSuccessfulRemoteDataObject(mockItem) }) }); beforeEach(async(() => { diff --git a/src/app/+item-page/simple/item-page.component.ts b/src/app/+item-page/simple/item-page.component.ts index 10deef23e4..591a093cc9 100644 --- a/src/app/+item-page/simple/item-page.component.ts +++ b/src/app/+item-page/simple/item-page.component.ts @@ -55,7 +55,7 @@ export class ItemPageComponent implements OnInit { */ ngOnInit(): void { this.itemRD$ = this.route.data.pipe( - map((data) => data.item as RemoteData), + map((data) => data.dso as RemoteData), redirectToPageNotFoundOn404(this.router) ); this.metadataService.processRemoteData(this.itemRD$); From ac44bb9cb9c5fd8d77298ff35dbb9d56ef66c6e0 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 20 Oct 2020 17:54:12 +0200 Subject: [PATCH 02/26] 74199: Admin search dialogs - intermediate commit --- src/app/core/shared/context.model.ts | 1 + .../dso-selector/dso-selector.component.html | 2 +- .../dso-selector/dso-selector.component.ts | 6 ++ ...sidebar-search-list-element.component.html | 1 + ...n-sidebar-search-list-element.component.ts | 17 ++++++ ...sidebar-search-list-element.component.html | 3 + .../sidebar-search-list-element.component.ts | 56 +++++++++++++++++++ src/app/shared/shared.module.ts | 6 +- 8 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html create mode 100644 src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html create mode 100644 src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts diff --git a/src/app/core/shared/context.model.ts b/src/app/core/shared/context.model.ts index 4699a7977b..207c1fb99d 100644 --- a/src/app/core/shared/context.model.ts +++ b/src/app/core/shared/context.model.ts @@ -13,4 +13,5 @@ export enum Context { EntitySearchModal = 'EntitySearchModal', AdminSearch = 'adminSearch', AdminWorkflowSearch = 'adminWorkflowSearch', + SideBarSearchModal = 'sideBarSearchModal', } 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 92ddf4cf36..8a2f9272c4 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 @@ -16,6 +16,6 @@ title="{{ listEntry.indexableObject.name }}" (click)="onSelect.emit(listEntry.indexableObject)" #listEntryElement> + [linkType]=linkTypes.None [context]="context"> diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts index 37c9a99f59..d0404d61c9 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts @@ -21,6 +21,7 @@ import { PaginatedList } from '../../../core/data/paginated-list'; import { SearchResult } from '../../search/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { ViewMode } from '../../../core/shared/view-mode.model'; +import { Context } from '../../../core/shared/context.model'; @Component({ selector: 'ds-dso-selector', @@ -85,6 +86,11 @@ export class DSOSelectorComponent implements OnInit { */ linkTypes = CollectionElementLinkType; + /** + * This component's context to display listable objects for + */ + context = Context.SideBarSearchModal; + constructor(private searchService: SearchService) { } diff --git a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html new file mode 100644 index 0000000000..be25f1af49 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html @@ -0,0 +1 @@ +Test display for sidebar-search list elements diff --git a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..49724a9309 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts @@ -0,0 +1,17 @@ +import { listableObjectComponent } from '../../../../object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Component } from '@angular/core'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { SidebarSearchListElementComponent } from '../../sidebar-search-list-element.component'; + +@listableObjectComponent('PublicationSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@listableObjectComponent(ItemSearchResult, ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-publication-sidebar-search-list-element', + templateUrl: '../../sidebar-search-list-element.component.html' +}) +export class PublicationSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + +} diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html new file mode 100644 index 0000000000..b0fe1e58d2 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html @@ -0,0 +1,3 @@ +
{{ parentTitle$ | async }}
+
{{ title }}
+
{{ description }}
diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..0489f9f3b7 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts @@ -0,0 +1,56 @@ +import { SearchResult } from '../../search/search-result.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { SearchResultListElementComponent } from '../search-result-list-element/search-result-list-element.component'; +import { Component } from '@angular/core'; +import { hasValue } from '../../empty.util'; +import { Observable } from 'rxjs/internal/Observable'; +import { TruncatableService } from '../../truncatable/truncatable.service'; +import { LinkService } from '../../../core/cache/builders/link.service'; +import { find, map } from 'rxjs/operators'; +import { ChildHALResource } from '../../../core/shared/child-hal-resource.model'; +import { followLink } from '../../utils/follow-link-config.model'; +import { RemoteData } from '../../../core/data/remote-data'; + +@Component({ + selector: 'ds-sidebar-search-list-element', + templateUrl: './sidebar-search-list-element.component.html' +}) +export class SidebarSearchListElementComponent, K extends DSpaceObject> extends SearchResultListElementComponent { + parentTitle$: Observable; + title: string; + description: string; + + public constructor(protected truncatableService: TruncatableService, + protected linkService: LinkService) { + super(truncatableService); + } + + ngOnInit(): void { + super.ngOnInit(); + if (hasValue(this.dso)) { + this.parentTitle$ = this.getParentTitle(); + this.title = this.getTitle(); + this.description = this.getDescription(); + } + } + + getTitle(): string { + return this.firstMetadataValue('dc.title'); + } + + getDescription(): string { + // TODO: Expand description + return this.firstMetadataValue('dc.publisher'); + } + + getParentTitle(): Observable { + // TODO: Remove cast to "any" and replace with proper type-check + const propertyName = (this.dso as any).getParentLinkKey(); + return this.linkService.resolveLink(this.dso, followLink(propertyName))[propertyName].pipe( + find((parentRD: RemoteData) => parentRD.hasSucceeded || parentRD.statusCode === 204), + map((parentRD: RemoteData) => { + return parentRD.payload.firstMetadataValue('dc.title'); + }) + ); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 5f35ed4ceb..5b849eb403 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -210,6 +210,8 @@ import { CollectionDropdownComponent } from './collection-dropdown/collection-dr import { DsSelectComponent } from './ds-select/ds-select.component'; import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-treeview.component'; import { CurationFormComponent } from '../curation-form/curation-form.component'; +import { PublicationSidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component'; +import { SidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/sidebar-search-list-element.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -483,7 +485,9 @@ const ENTRY_COMPONENTS = [ CurationFormComponent, ExportMetadataSelectorComponent, ConfirmationModalComponent, - VocabularyTreeviewComponent + VocabularyTreeviewComponent, + SidebarSearchListElementComponent, + PublicationSidebarSearchListElementComponent, ]; const SHARED_ITEM_PAGE_COMPONENTS = [ From f79ea2b844c5eb7456fb0e9882ec0ae51602b611 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 21 Oct 2020 13:24:21 +0200 Subject: [PATCH 03/26] 74199: Admin search dialogs - sidebar search list element implementations - intermediate commit --- ...e-sidebar-search-list-element.component.ts | 38 ++++++ ...e-sidebar-search-list-element.component.ts | 38 ++++++ ...l-sidebar-search-list-element.component.ts | 31 +++++ .../journal-entities.module.ts | 8 +- ...t-sidebar-search-list-element.component.ts | 33 +++++ ...n-sidebar-search-list-element.component.ts | 59 +++++++++ ...t-sidebar-search-list-element.component.ts | 26 ++++ .../research-entities.module.ts | 8 +- ...sidebar-search-list-element.component.html | 1 - ...n-sidebar-search-list-element.component.ts | 4 + ...sidebar-search-list-element.component.html | 6 +- .../sidebar-search-list-element.component.ts | 113 ++++++++++++++++-- src/assets/i18n/en.json5 | 2 + 13 files changed, 349 insertions(+), 18 deletions(-) create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.ts create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.ts create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.ts delete mode 100644 src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..026a9be15c --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.ts @@ -0,0 +1,38 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; + +@listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-journal-issue-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "JournalIssue" within the context of + * a sidebar search modal + */ +export class JournalIssueSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the description of the Journal Issue by returning its volume number(s) and/or issue number(s) + */ + getDescription(): string { + const volumeNumbers = this.allMetadataValues(['publicationvolume.volumeNumber']); + const issueNumbers = this.allMetadataValues(['publicationissue.issueNumber']); + let description = ''; + if (isNotEmpty(volumeNumbers)) { + description += volumeNumbers.join(', '); + } + if (isNotEmpty(description) && isNotEmpty(issueNumbers)) { + description += ' - '; + } + if (isNotEmpty(issueNumbers)) { + description += issueNumbers.join(', '); + } + return this.undefinedIfEmpty(description); + } +} diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..ce99d14406 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.ts @@ -0,0 +1,38 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; + +@listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-journal-volume-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "JournalVolume" within the context of + * a sidebar search modal + */ +export class JournalVolumeSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the description of the Journal Volume by returning the journal title and volume number(s) (between parentheses) + */ + getDescription(): string { + const titles = this.allMetadataValues(['journal.title']); + const numbers = this.allMetadataValues(['publicationvolume.volumeNumber']); + let description = ''; + if (isNotEmpty(titles)) { + description += titles.join(', '); + } + if (isNotEmpty(numbers)) { + if (isNotEmpty(description)) { + description += ' '; + } + description += numbers.map((n) => `(${n})`).join(' '); + } + return this.undefinedIfEmpty(description); + } +} diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..f222298ee3 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.ts @@ -0,0 +1,31 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; + +@listableObjectComponent('JournalSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-journal-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "Journal" within the context of + * a sidebar search modal + */ +export class JournalSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the description of the Journal by returning its ISSN(s) + */ + getDescription(): string { + const issns = this.allMetadataValues(['creativeworkseries.issn']); + let description = ''; + if (isNotEmpty(issns)) { + description += issns.join(', '); + } + return this.undefinedIfEmpty(description); + } +} diff --git a/src/app/entity-groups/journal-entities/journal-entities.module.ts b/src/app/entity-groups/journal-entities/journal-entities.module.ts index d00eae1e54..11ce6c4c2a 100644 --- a/src/app/entity-groups/journal-entities/journal-entities.module.ts +++ b/src/app/entity-groups/journal-entities/journal-entities.module.ts @@ -18,6 +18,9 @@ import { JournalIssueSearchResultListElementComponent } from './item-list-elemen import { JournalVolumeSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component'; import { JournalIssueSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component'; import { JournalVolumeSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component'; +import { JournalVolumeSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component'; +import { JournalIssueSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component'; +import { JournalSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component'; const ENTRY_COMPONENTS = [ JournalComponent, @@ -34,7 +37,10 @@ const ENTRY_COMPONENTS = [ JournalVolumeSearchResultListElementComponent, JournalIssueSearchResultGridElementComponent, JournalVolumeSearchResultGridElementComponent, - JournalSearchResultGridElementComponent + JournalSearchResultGridElementComponent, + JournalVolumeSidebarSearchListElementComponent, + JournalIssueSidebarSearchListElementComponent, + JournalSidebarSearchListElementComponent, ]; @NgModule({ diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..54fed3125f --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.ts @@ -0,0 +1,33 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; + +@listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-org-unit-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "OrgUnit" within the context of + * a sidebar search modal + */ +export class OrgUnitSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the title of the Org Unit by returning its legal name + */ + getTitle(): string { + return this.firstMetadataValue('organization.legalName'); + } + + /** + * Get the description of the Org Unit by returning its dc.description + */ + getDescription(): string { + return this.firstMetadataValue('dc.description'); + } +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..9cbf66d040 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.ts @@ -0,0 +1,59 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { LinkService } from '../../../../../core/cache/builders/link.service'; +import { TranslateService } from '@ngx-translate/core'; + +@listableObjectComponent('PersonSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-person-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "Person" within the context of + * a sidebar search modal + */ +export class PersonSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + constructor(protected truncatableService: TruncatableService, + protected linkService: LinkService, + protected translateService: TranslateService) { + super(truncatableService, linkService); + } + + /** + * Get the title of the Person by returning a combination of its family name and given name (or "No name found") + */ + getTitle(): string { + const familyName = this.firstMetadataValue('person.familyName'); + const givenName = this.firstMetadataValue('person.givenName'); + let title = ''; + if (isNotEmpty(familyName)) { + title = familyName; + } + if (isNotEmpty(title)) { + title += ', '; + } + if (isNotEmpty(givenName)) { + title += givenName; + } + return this.defaultIfEmpty(title, this.translateService.instant('person.listelement.no-title')); + } + + /** + * Get the description of the Person by returning its job title(s) + */ + getDescription(): string { + const titles = this.allMetadataValues(['person.jobTitle']); + let description = ''; + if (isNotEmpty(titles)) { + description += titles.join(', '); + } + return this.undefinedIfEmpty(description); + } +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..00124cf497 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.ts @@ -0,0 +1,26 @@ +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Component } from '@angular/core'; +import { SidebarSearchListElementComponent } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { isNotEmpty } from '../../../../../shared/empty.util'; + +@listableObjectComponent('ProjectSearchResult', ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-project-sidebar-search-list-element', + templateUrl: '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "Project" within the context of + * a sidebar search modal + */ +export class ProjectSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Projects currently don't support a description + */ + getDescription(): string { + return undefined; + } +} diff --git a/src/app/entity-groups/research-entities/research-entities.module.ts b/src/app/entity-groups/research-entities/research-entities.module.ts index cef3b4539b..1f50ab830a 100644 --- a/src/app/entity-groups/research-entities/research-entities.module.ts +++ b/src/app/entity-groups/research-entities/research-entities.module.ts @@ -26,6 +26,9 @@ import { NameVariantModalComponent } from './submission/name-variant-modal/name- import { OrgUnitInputSuggestionsComponent } from './submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component'; import { OrgUnitSearchResultListSubmissionElementComponent } from './submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component'; import { ExternalSourceEntryListSubmissionElementComponent } from './submission/item-list-elements/external-source-entry/external-source-entry-list-submission-element.component'; +import { OrgUnitSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component'; +import { PersonSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component'; +import { ProjectSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component'; const ENTRY_COMPONENTS = [ OrgUnitComponent, @@ -50,7 +53,10 @@ const ENTRY_COMPONENTS = [ NameVariantModalComponent, OrgUnitSearchResultListSubmissionElementComponent, OrgUnitInputSuggestionsComponent, - ExternalSourceEntryListSubmissionElementComponent + ExternalSourceEntryListSubmissionElementComponent, + OrgUnitSidebarSearchListElementComponent, + PersonSidebarSearchListElementComponent, + ProjectSidebarSearchListElementComponent, ]; @NgModule({ diff --git a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html deleted file mode 100644 index be25f1af49..0000000000 --- a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.html +++ /dev/null @@ -1 +0,0 @@ -Test display for sidebar-search list elements diff --git a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts index 49724a9309..fb79a4924e 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts +++ b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.ts @@ -12,6 +12,10 @@ import { SidebarSearchListElementComponent } from '../../sidebar-search-list-ele selector: 'ds-publication-sidebar-search-list-element', templateUrl: '../../sidebar-search-list-element.component.html' }) +/** + * Component displaying a list element for a {@link ItemSearchResult} of type "Publication" within the context of + * a sidebar search modal + */ export class PublicationSidebarSearchListElementComponent extends SidebarSearchListElementComponent { } diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html index b0fe1e58d2..adcf23dcf7 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html @@ -1,3 +1,3 @@ -
{{ parentTitle$ | async }}
-
{{ title }}
-
{{ description }}
+
{{ parentTitle$ | async }}
+
{{ title }}
+
{{ description }}
diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts index 0489f9f3b7..71547854f9 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts @@ -2,7 +2,7 @@ import { SearchResult } from '../../search/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { SearchResultListElementComponent } from '../search-result-list-element/search-result-list-element.component'; import { Component } from '@angular/core'; -import { hasValue } from '../../empty.util'; +import { hasValue, isNotEmpty } from '../../empty.util'; import { Observable } from 'rxjs/internal/Observable'; import { TruncatableService } from '../../truncatable/truncatable.service'; import { LinkService } from '../../../core/cache/builders/link.service'; @@ -10,14 +10,31 @@ import { find, map } from 'rxjs/operators'; import { ChildHALResource } from '../../../core/shared/child-hal-resource.model'; import { followLink } from '../../utils/follow-link-config.model'; import { RemoteData } from '../../../core/data/remote-data'; +import { of as observableOf } from 'rxjs'; @Component({ selector: 'ds-sidebar-search-list-element', templateUrl: './sidebar-search-list-element.component.html' }) +/** + * Component displaying a list element for a {@link SearchResult} in the sidebar search modal + * It displays the name of the parent, title and description of the object. All of which are customizable in the child + * component by overriding the relevant methods of this component + */ export class SidebarSearchListElementComponent, K extends DSpaceObject> extends SearchResultListElementComponent { + /** + * Observable for the title of the parent object (displayed above the object's title) + */ parentTitle$: Observable; + + /** + * The title for the object to display + */ title: string; + + /** + * A description to display below the title + */ description: string; public constructor(protected truncatableService: TruncatableService, @@ -25,6 +42,9 @@ export class SidebarSearchListElementComponent, K exte super(truncatableService); } + /** + * Initialise the component variables + */ ngOnInit(): void { super.ngOnInit(); if (hasValue(this.dso)) { @@ -34,23 +54,92 @@ export class SidebarSearchListElementComponent, K exte } } + /** + * Get the title of the object's parent + * Retrieve the parent by using the object's parent link and retrieving its 'dc.title' metadata + */ + getParentTitle(): Observable { + return this.getParent().pipe( + map((parentRD: RemoteData) => { + return parentRD ? parentRD.payload.firstMetadataValue('dc.title') : undefined; + }) + ); + } + + /** + * Get the parent of the object + */ + getParent(): Observable> { + if (typeof (this.dso as any).getParentLinkKey === 'function') { + const propertyName = (this.dso as any).getParentLinkKey(); + return this.linkService.resolveLink(this.dso, followLink(propertyName))[propertyName].pipe( + find((parentRD: RemoteData) => parentRD.hasSucceeded || parentRD.statusCode === 204) + ); + } + return observableOf(undefined); + } + + /** + * Get the title of the object + * Default: "dc.title" + */ getTitle(): string { return this.firstMetadataValue('dc.title'); } + /** + * Get the description of the object + * Default: "(dc.publisher, dc.date.issued) authors" + */ getDescription(): string { - // TODO: Expand description - return this.firstMetadataValue('dc.publisher'); + const publisher = this.firstMetadataValue('dc.publisher'); + const date = this.firstMetadataValue('dc.date.issued'); + const authors = this.allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); + let description = ''; + if (isNotEmpty(publisher) || isNotEmpty(date)) { + description += '('; + } + if (isNotEmpty(publisher)) { + description += publisher; + } + if (isNotEmpty(date)) { + if (isNotEmpty(publisher)) { + description += ', '; + } + description += date; + } + if (isNotEmpty(description)) { + description += ') '; + } + if (isNotEmpty(authors)) { + authors.forEach((author, i) => { + description += author; + if (i < (authors.length - 1)) { + description += '; '; + } + }); + } + return this.undefinedIfEmpty(description); } - getParentTitle(): Observable { - // TODO: Remove cast to "any" and replace with proper type-check - const propertyName = (this.dso as any).getParentLinkKey(); - return this.linkService.resolveLink(this.dso, followLink(propertyName))[propertyName].pipe( - find((parentRD: RemoteData) => parentRD.hasSucceeded || parentRD.statusCode === 204), - map((parentRD: RemoteData) => { - return parentRD.payload.firstMetadataValue('dc.title'); - }) - ); + /** + * Return undefined if the provided string is empty + * @param value Value to check + */ + undefinedIfEmpty(value: string) { + return this.defaultIfEmpty(value, undefined); + } + + /** + * Return a default value if the provided string is empty + * @param value Value to check + * @param def Default in case value is empty + */ + defaultIfEmpty(value: string, def: string) { + if (isNotEmpty(value)) { + return value; + } else { + return def; + } } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 84d874388c..a6aaad98ea 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2194,6 +2194,8 @@ "person.listelement.badge": "Person", + "person.listelement.no-title": "No name found", + "person.page.birthdate": "Birth Date", "person.page.email": "Email Address", From 8b2b28df2508c923e06209cef75e06133e981d8e Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 21 Oct 2020 18:04:03 +0200 Subject: [PATCH 04/26] 74199: Infinite scrollable dso-selector + collection/community implementation + authorized-collection-selector --- ...uthorized-collection-selector.component.ts | 40 ++++++ .../dso-selector/dso-selector.component.html | 12 +- .../dso-selector/dso-selector.component.scss | 5 + .../dso-selector/dso-selector.component.ts | 123 ++++++++++++++---- ...create-item-parent-selector.component.html | 3 +- ...n-sidebar-search-list-element.component.ts | 24 ++++ ...y-sidebar-search-list-element.component.ts | 24 ++++ src/app/shared/shared.module.ts | 9 +- src/styles/_custom_variables.scss | 2 + 9 files changed, 212 insertions(+), 30 deletions(-) create mode 100644 src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts create mode 100644 src/app/shared/dso-selector/dso-selector/dso-selector.component.scss create mode 100644 src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.ts diff --git a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts new file mode 100644 index 0000000000..ff9fa81368 --- /dev/null +++ b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts @@ -0,0 +1,40 @@ +import { Component } from '@angular/core'; +import { DSOSelectorComponent } from '../dso-selector.component'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { CollectionDataService } from '../../../../core/data/collection-data.service'; +import { Observable } from 'rxjs/internal/Observable'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators'; +import { map } from 'rxjs/operators'; +import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { SearchResult } from '../../../search/search-result.model'; +import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; + +@Component({ + selector: 'ds-authorized-collection-selector', + templateUrl: '../dso-selector.component.html' +}) +/** + * Component rendering a list of collections to select from + */ +export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent { + constructor(protected searchService: SearchService, + protected collectionDataService: CollectionDataService) { + super(searchService); + } + + /** + * Perform a search for authorized collections with the current query and page + * @param query Query to search objects for + * @param page Page to retrieve + */ + search(query: string, page: number): Observable>> { + return this.collectionDataService.getAuthorizedCollection(query, Object.assign({ + currentPage: page, + elementsPerPage: this.defaultPagination.pageSize + })).pipe( + getFirstSucceededRemoteDataPayload(), + map((list) => new PaginatedList(list.pageInfo, list.page.map((col) => Object.assign(new CollectionSearchResult(), { indexableObject: col })))) + ); + } +} 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 8a2f9272c4..a0b6aff2a3 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 @@ -7,15 +7,23 @@
+
- +
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.scss b/src/app/shared/dso-selector/dso-selector/dso-selector.component.scss new file mode 100644 index 0000000000..37d2ebeca7 --- /dev/null +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.scss @@ -0,0 +1,5 @@ +.scrollable-menu { + height: auto; + max-height: $dso-selector-list-max-height; + overflow-x: hidden; +} diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts index d0404d61c9..8d2d6f758b 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts @@ -3,29 +3,33 @@ import { ElementRef, EventEmitter, Input, + OnDestroy, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; import { FormControl } from '@angular/forms'; - -import { Observable } from 'rxjs'; -import { debounceTime, startWith, switchMap } from 'rxjs/operators'; +import { debounceTime, startWith, switchMap, tap } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { CollectionElementLinkType } from '../../object-collection/collection-element-link.type'; import { PaginatedSearchOptions } from '../../search/paginated-search-options.model'; import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; -import { RemoteData } from '../../../core/data/remote-data'; -import { PaginatedList } from '../../../core/data/paginated-list'; -import { SearchResult } from '../../search/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { ViewMode } from '../../../core/shared/view-mode.model'; import { Context } from '../../../core/shared/context.model'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; +import { Subscription } from 'rxjs/internal/Subscription'; +import { hasValue } from '../../empty.util'; +import { combineLatest as observableCombineLatest } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { PaginatedList } from '../../../core/data/paginated-list'; +import { SearchResult } from '../../search/search-result.model'; @Component({ selector: 'ds-dso-selector', - // styleUrls: ['./dso-selector.component.scss'], + styleUrls: ['./dso-selector.component.scss'], templateUrl: './dso-selector.component.html' }) @@ -33,7 +37,7 @@ import { Context } from '../../../core/shared/context.model'; * Component to render a list of DSO's of which one can be selected * The user can search the list by using the input field */ -export class DSOSelectorComponent implements OnInit { +export class DSOSelectorComponent implements OnInit, OnDestroy { /** * The view mode of the listed objects */ @@ -64,12 +68,29 @@ export class DSOSelectorComponent implements OnInit { /** * Default pagination for this feature */ - private defaultPagination = { id: 'dso-selector', currentPage: 1, pageSize: 5 } as any; + defaultPagination = { id: 'dso-selector', currentPage: 1, pageSize: 5 } as any; /** * List with search results of DSpace objects for the current query */ - listEntries$: Observable>>>; + listEntries: Array> = []; + + /** + * The current page to load + * Dynamically goes up as the user scrolls down until it reaches the last page possible + */ + currentPage$ = new BehaviorSubject(1); + + /** + * Whether or not the list contains a next page to load + * This allows us to avoid next pages from trying to load when there are none + */ + hasNextPage = false; + + /** + * Whether or not the list should be reset next time it receives a page to load + */ + resetList = false; /** * List of element references to all elements @@ -91,31 +112,76 @@ export class DSOSelectorComponent implements OnInit { */ context = Context.SideBarSearchModal; - constructor(private searchService: SearchService) { + /** + * Array to track all subscriptions and unsubscribe them onDestroy + * @type {Array} + */ + public subs: Subscription[] = []; + + constructor(protected searchService: SearchService) { } /** - * Fills the listEntries$ variable with search results based on the input field's current value + * Fills the listEntries variable with search results based on the input field's current value and the current page * The search will always start with the initial currentDSOId value */ ngOnInit(): void { this.input.setValue(this.currentDSOId); this.typesString = this.types.map((type: string) => type.toString().toLowerCase()).join(', '); - this.listEntries$ = this.input.valueChanges - .pipe( + + this.subs.push(observableCombineLatest( + this.input.valueChanges.pipe( debounceTime(this.debounceTime), startWith(this.currentDSOId), - switchMap((query) => { - return this.searchService.search( - new PaginatedSearchOptions({ - query: query, - dsoTypes: this.types, - pagination: this.defaultPagination - }) - ) - } - ) - ) + tap(() => this.currentPage$.next(1)) + ), + this.currentPage$ + ).pipe( + switchMap(([query, page]: [string, number]) => { + if (page === 1) { + // The first page is loading, this means we should reset the list instead of adding to it + this.resetList = true; + } + return this.search(query, page); + }) + ).subscribe((list) => { + if (this.resetList) { + this.listEntries = list.page; + this.resetList = false; + } else { + this.listEntries.push(...list.page); + } + // Check if there are more pages available after the current one + this.hasNextPage = list.totalElements > this.listEntries.length; + })); + } + + /** + * Perform a search for the current query and page + * @param query Query to search objects for + * @param page Page to retrieve + */ + search(query: string, page: number): Observable>> { + return this.searchService.search( + new PaginatedSearchOptions({ + query: query, + dsoTypes: this.types, + pagination: Object.assign({}, this.defaultPagination, { + currentPage: page + }) + }) + ).pipe( + getFirstSucceededRemoteDataPayload() + ); + } + + /** + * When the user reaches the bottom of the page (or almost) and there's a next page available, increase the current page + */ + onScrollDown() { + if (this.hasNextPage) { + this.currentPage$.next(this.currentPage$.value + 1); + } } /** @@ -126,4 +192,11 @@ export class DSOSelectorComponent implements OnInit { this.listElements.first.nativeElement.click(); } } + + /** + * Unsubscribe from all subscriptions + */ + ngOnDestroy(): void { + this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); + } } diff --git a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.html b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.html index ef8865ad87..a188b08b60 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.html +++ b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.html @@ -5,7 +5,6 @@ diff --git a/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..8439ca53f7 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { Collection } from '../../../../core/shared/collection.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../core/shared/context.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { SidebarSearchListElementComponent } from '../sidebar-search-list-element.component'; + +@listableObjectComponent(CollectionSearchResult, ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-collection-sidebar-search-list-element', + templateUrl: '../sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link CollectionSearchResult} within the context of a sidebar search modal + */ +export class CollectionSidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the description of the Collection by returning its abstract + */ + getDescription(): string { + return this.firstMetadataValue('dc.description.abstract'); + } +} diff --git a/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.ts new file mode 100644 index 0000000000..02e09c3fd4 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../core/shared/context.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { SidebarSearchListElementComponent } from '../sidebar-search-list-element.component'; +import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; +import { Community } from '../../../../core/shared/community.model'; + +@listableObjectComponent(CommunitySearchResult, ViewMode.ListElement, Context.SideBarSearchModal) +@Component({ + selector: 'ds-collection-sidebar-search-list-element', + templateUrl: '../sidebar-search-list-element.component.html' +}) +/** + * Component displaying a list element for a {@link CommunitySearchResult} within the context of a sidebar search modal + */ +export class CommunitySidebarSearchListElementComponent extends SidebarSearchListElementComponent { + /** + * Get the description of the Community by returning its abstract + */ + getDescription(): string { + return this.firstMetadataValue('dc.description.abstract'); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 5b849eb403..d8d8b51331 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -212,6 +212,9 @@ import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-tr import { CurationFormComponent } from '../curation-form/curation-form.component'; import { PublicationSidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component'; import { SidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/sidebar-search-list-element.component'; +import { CollectionSidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component'; +import { CommunitySidebarSearchListElementComponent } from './object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component'; +import { AuthorizedCollectionSelectorComponent } from './dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -405,7 +408,8 @@ const COMPONENTS = [ CollectionDropdownComponent, ExportMetadataSelectorComponent, ConfirmationModalComponent, - VocabularyTreeviewComponent + VocabularyTreeviewComponent, + AuthorizedCollectionSelectorComponent, ]; const ENTRY_COMPONENTS = [ @@ -488,6 +492,9 @@ const ENTRY_COMPONENTS = [ VocabularyTreeviewComponent, SidebarSearchListElementComponent, PublicationSidebarSearchListElementComponent, + CollectionSidebarSearchListElementComponent, + CommunitySidebarSearchListElementComponent, + AuthorizedCollectionSelectorComponent, ]; const SHARED_ITEM_PAGE_COMPONENTS = [ diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index c1f155fa39..bc1dfda7e7 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -37,3 +37,5 @@ $edit-item-metadata-field-width: 190px !default; $edit-item-language-field-width: 43px !default; $thumbnail-max-width: 175px !default; + +$dso-selector-list-max-height: 475px !default; From ade5eb53ccfa782c9be783bf1a6b3a9e960bcab4 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 22 Oct 2020 18:03:32 +0200 Subject: [PATCH 05/26] 74199: Infinite scroll size changes --- .../authorized-collection-selector.component.ts | 1 + .../dso-selector/dso-selector/dso-selector.component.html | 2 +- .../shared/dso-selector/dso-selector/dso-selector.component.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts index ff9fa81368..1e58289c3a 100644 --- a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.ts @@ -12,6 +12,7 @@ import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; @Component({ selector: 'ds-authorized-collection-selector', + styleUrls: ['../dso-selector.component.scss'], templateUrl: '../dso-selector.component.html' }) /** 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 a0b6aff2a3..7a04bfc333 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 @@ -9,7 +9,7 @@
Date: Fri, 23 Oct 2020 17:29:10 +0200 Subject: [PATCH 06/26] 74199: Admin search dialogs - Current DSO + context for new item/collection --- .../dso-selector/dso-selector.component.html | 1 + .../dso-selector/dso-selector.component.scss | 7 ++++ .../dso-selector/dso-selector.component.ts | 33 +++++++++++++++---- ...te-collection-parent-selector.component.ts | 1 + ...create-item-parent-selector.component.html | 3 +- .../create-item-parent-selector.component.ts | 1 + .../dso-selector-modal-wrapper.component.html | 3 +- .../dso-selector-modal-wrapper.component.ts | 6 ++++ src/assets/i18n/en.json5 | 4 +++ src/styles/_custom_variables.scss | 2 ++ 10 files changed, 52 insertions(+), 9 deletions(-) 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 7a04bfc333..048e115f8e 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 @@ -20,6 +20,7 @@
diff --git a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts index 5729ac8460..03d7732fb0 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts @@ -20,6 +20,7 @@ export class CreateItemParentSelectorComponent extends DSOSelectorModalWrapperCo objectType = DSpaceObjectType.ITEM; selectorTypes = [DSpaceObjectType.COLLECTION]; action = SelectorActionType.CREATE; + header = 'dso-selector.create.item.sub-level'; constructor(protected activeModal: NgbActiveModal, protected route: ActivatedRoute, private router: Router) { super(activeModal, route); diff --git a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.html b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.html index e1c18ec1e0..85d8797e66 100644 --- a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.html +++ b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.html @@ -5,6 +5,7 @@ diff --git a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts index b56a901b12..59aeceea0f 100644 --- a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts @@ -23,6 +23,12 @@ export abstract class DSOSelectorModalWrapperComponent implements OnInit { */ @Input() dsoRD: RemoteData; + /** + * Optional header to display above the selection list + * Supports i18n keys + */ + @Input() header: string; + /** * The type of the DSO that's being edited, created or exported */ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index a6aaad98ea..97d7ce162a 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1037,6 +1037,8 @@ "dso-selector.create.collection.head": "New collection", + "dso-selector.create.collection.sub-level": "Create a new collection in", + "dso-selector.create.community.head": "New community", "dso-selector.create.community.sub-level": "Create a new community in", @@ -1045,6 +1047,8 @@ "dso-selector.create.item.head": "New item", + "dso-selector.create.item.sub-level": "Create a new item in", + "dso-selector.create.submission.head": "New submission", "dso-selector.edit.collection.head": "Edit collection", diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index bc1dfda7e7..a9a1ecb391 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -39,3 +39,5 @@ $edit-item-language-field-width: 43px !default; $thumbnail-max-width: 175px !default; $dso-selector-list-max-height: 475px !default; +$dso-selector-current-background-color: #eeeeee; +$dso-selector-current-background-hover-color: darken($dso-selector-current-background-color, 10%); From 892e7bdaa1cf4831f92432d47abae917458cf7e8 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 26 Oct 2020 15:43:15 +0100 Subject: [PATCH 07/26] 74199: Tests --- ...ebar-search-list-element.component.spec.ts | 42 ++++++++++ ...ebar-search-list-element.component.spec.ts | 45 +++++++++++ ...ebar-search-list-element.component.spec.ts | 40 ++++++++++ ...ebar-search-list-element.component.spec.ts | 37 +++++++++ ...ebar-search-list-element.component.spec.ts | 45 +++++++++++ ...ebar-search-list-element.component.spec.ts | 32 ++++++++ ...ized-collection-selector.component.spec.ts | 56 +++++++++++++ .../dso-selector.component.spec.ts | 79 ++++++++++++++----- ...ebar-search-list-element.component.spec.ts | 37 +++++++++ ...ebar-search-list-element.component.spec.ts | 36 +++++++++ ...ebar-search-list-element.component.spec.ts | 47 +++++++++++ ...sidebar-search-list-element.component.html | 6 +- ...ebar-search-list-element.component.spec.ts | 69 ++++++++++++++++ 13 files changed, 547 insertions(+), 24 deletions(-) create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.spec.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..b9593e7612 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,42 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { JournalIssueSidebarSearchListElementComponent } from './journal-issue-sidebar-search-list-element.component'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'publicationvolume.volumeNumber': [ + { + value: '5' + } + ], + 'publicationissue.issueNumber': [ + { + value: '7' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('JournalIssueSidebarSearchListElementComponent', + createSidebarSearchListElementTests(JournalIssueSidebarSearchListElementComponent, object, parent, 'parent title', 'title', '5 - 7') +); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..eca1775c7d --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,45 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { JournalVolumeSidebarSearchListElementComponent } from './journal-volume-sidebar-search-list-element.component'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'journal.title': [ + { + value: 'journal title' + } + ], + 'publicationvolume.volumeNumber': [ + { + value: '1' + }, + { + value: '2' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('JournalVolumeSidebarSearchListElementComponent', + createSidebarSearchListElementTests(JournalVolumeSidebarSearchListElementComponent, object, parent, 'parent title', 'title', 'journal title (1) (2)') +); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..a47dbf0e2e --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,40 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { JournalSidebarSearchListElementComponent } from './journal-sidebar-search-list-element.component'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'creativeworkseries.issn': [ + { + value: '1234' + }, + { + value: '5678' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('JournalSidebarSearchListElementComponent', + createSidebarSearchListElementTests(JournalSidebarSearchListElementComponent, object, parent, 'parent title', 'title', '1234, 5678') +); diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..a271273a1b --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,37 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { OrgUnitSidebarSearchListElementComponent } from './org-unit-sidebar-search-list-element.component'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'organization.legalName': [ + { + value: 'title' + } + ], + 'dc.description': [ + { + value: 'description' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('OrgUnitSidebarSearchListElementComponent', + createSidebarSearchListElementTests(OrgUnitSidebarSearchListElementComponent, object, parent, 'parent title', 'title', 'description') +); diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..e93dd78636 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,45 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { PersonSidebarSearchListElementComponent } from './person-sidebar-search-list-element.component'; +import { TranslateService } from '@ngx-translate/core'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'person.familyName': [ + { + value: 'family name' + } + ], + 'person.givenName': [ + { + value: 'given name' + } + ], + 'person.jobTitle': [ + { + value: 'job title' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('PersonSidebarSearchListElementComponent', + createSidebarSearchListElementTests(PersonSidebarSearchListElementComponent, object, parent, 'parent title', 'family name, given name', 'job title', [ + { provide: TranslateService, useValue: jasmine.createSpyObj('translate', { instant: '' }) } + ]) +); diff --git a/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..ec0eb0e7bb --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,32 @@ +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { createSidebarSearchListElementTests } from '../../../../../shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec'; +import { ProjectSidebarSearchListElementComponent } from './project-sidebar-search-list-element.component'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('ProjectSidebarSearchListElementComponent', + createSidebarSearchListElementTests(ProjectSidebarSearchListElementComponent, object, parent, 'parent title', 'title', undefined) +); diff --git a/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.spec.ts new file mode 100644 index 0000000000..25b7465ada --- /dev/null +++ b/src/app/shared/dso-selector/dso-selector/authorized-collection-selector/authorized-collection-selector.component.spec.ts @@ -0,0 +1,56 @@ +import { AuthorizedCollectionSelectorComponent } from './authorized-collection-selector.component'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { VarDirective } from '../../../utils/var.directive'; +import { TranslateModule } from '@ngx-translate/core'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { CollectionDataService } from '../../../../core/data/collection-data.service'; +import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils'; +import { createPaginatedList } from '../../../testing/utils.test'; +import { Collection } from '../../../../core/shared/collection.model'; +import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; + +describe('AuthorizedCollectionSelectorComponent', () => { + let component: AuthorizedCollectionSelectorComponent; + let fixture: ComponentFixture; + + let collectionService; + let collection; + + beforeEach(async(() => { + collection = Object.assign(new Collection(), { + id: 'authorized-collection' + }); + collectionService = jasmine.createSpyObj('collectionService', { + getAuthorizedCollection: createSuccessfulRemoteDataObject$(createPaginatedList([collection])) + }); + TestBed.configureTestingModule({ + declarations: [AuthorizedCollectionSelectorComponent, VarDirective], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + providers: [ + { provide: SearchService, useValue: {} }, + { provide: CollectionDataService, useValue: collectionService } + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuthorizedCollectionSelectorComponent); + component = fixture.componentInstance; + component.types = [DSpaceObjectType.COLLECTION]; + fixture.detectChanges(); + }); + + describe('search', () => { + it('should call getAuthorizedCollection and return the authorized collection in a SearchResult', (done) => { + component.search('', 1).subscribe((result) => { + expect(collectionService.getAuthorizedCollection).toHaveBeenCalled(); + expect(result.page.length).toEqual(1); + expect(result.page[0].indexableObject).toEqual(collection); + done(); + }); + }); + }); +}); diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts index 50b6090aef..7671f012ad 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts @@ -6,10 +6,10 @@ import { SearchService } from '../../../core/shared/search/search.service'; import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; import { ItemSearchResult } from '../../object-collection/shared/item-search-result.model'; import { Item } from '../../../core/shared/item.model'; -import { PaginatedList } from '../../../core/data/paginated-list'; -import { MetadataValue } from '../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; import { PaginatedSearchOptions } from '../../search/paginated-search-options.model'; +import { hasValue } from '../../empty.util'; +import { createPaginatedList } from '../../testing/utils.test'; describe('DSOSelectorComponent', () => { let component: DSOSelectorComponent; @@ -18,19 +18,46 @@ describe('DSOSelectorComponent', () => { const currentDSOId = 'test-uuid-ford-sose'; const type = DSpaceObjectType.ITEM; - const searchResult = new ItemSearchResult(); - const item = new Item(); - item.metadata = { - 'dc.title': [Object.assign(new MetadataValue(), { - value: 'Item title', - language: undefined - })] - }; - searchResult.indexableObject = item; - searchResult.hitHighlights = {}; - const searchService = jasmine.createSpyObj('searchService', { - search: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [searchResult])) - }); + const searchResult = createSearchResult('current'); + + const firstPageResults = [ + createSearchResult('1'), + createSearchResult('2'), + createSearchResult('3'), + ]; + + const nextPageResults = [ + createSearchResult('4'), + createSearchResult('5'), + createSearchResult('6'), + ]; + + const searchService = { + search: (options: PaginatedSearchOptions) => { + if (hasValue(options.query) && options.query.startsWith('search.resourceid')) { + return createSuccessfulRemoteDataObject$(createPaginatedList([searchResult])); + } else if (options.pagination.currentPage === 1) { + return createSuccessfulRemoteDataObject$(createPaginatedList(firstPageResults)); + } else { + return createSuccessfulRemoteDataObject$(createPaginatedList(nextPageResults)); + } + } + } + + function createSearchResult(name: string): ItemSearchResult { + return Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: `test-result-${name}`, + metadata: { + 'dc.title': [ + { + value: `test result - ${name}` + } + ] + } + }) + }) + } beforeEach(async(() => { TestBed.configureTestingModule({ @@ -58,13 +85,23 @@ describe('DSOSelectorComponent', () => { expect(component).toBeTruthy(); }); - it('should initially call the search method on the SearchService with the given DSO uuid', () => { - const searchOptions = new PaginatedSearchOptions({ - query: currentDSOId, - dsoTypes: [type], - pagination: (component as any).defaultPagination + describe('populating listEntries', () => { + it('should not be empty', () => { + expect(component.listEntries.length).toBeGreaterThan(0); }); - expect(searchService.search).toHaveBeenCalledWith(searchOptions); + it('should contain a combination of the current DSO and first page results', () => { + expect(component.listEntries).toEqual([searchResult, ...firstPageResults]); + }); + + describe('when current page increases', () => { + beforeEach(() => { + component.currentPage$.next(2); + }); + + it('should contain a combination of the current DSO, as well as first and second page results', () => { + expect(component.listEntries).toEqual([searchResult, ...firstPageResults, ...nextPageResults]); + }); + }); }); }); diff --git a/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.spec.ts b/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..be3ee7d1bb --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/collection/collection-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,37 @@ +import { CollectionSidebarSearchListElementComponent } from './collection-sidebar-search-list-element.component'; +import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { Collection } from '../../../../core/shared/collection.model'; +import { Community } from '../../../../core/shared/community.model'; +import { createSidebarSearchListElementTests } from '../sidebar-search-list-element.component.spec'; + +const object = Object.assign(new CollectionSearchResult(), { + indexableObject: Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'dc.description.abstract': [ + { + value: 'description' + } + ] + } + }) +}); +const parent = Object.assign(new Community(), { + id: 'test-community', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('CollectionSidebarSearchListElementComponent', + createSidebarSearchListElementTests(CollectionSidebarSearchListElementComponent, object, parent, 'parent title', 'title', 'description') +); diff --git a/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.spec.ts b/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..d6bcfc8581 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/community/community-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,36 @@ +import { Community } from '../../../../core/shared/community.model'; +import { createSidebarSearchListElementTests } from '../sidebar-search-list-element.component.spec'; +import { CommunitySidebarSearchListElementComponent } from './community-sidebar-search-list-element.component'; +import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; + +const object = Object.assign(new CommunitySearchResult(), { + indexableObject: Object.assign(new Community(), { + id: 'test-community', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'dc.description.abstract': [ + { + value: 'description' + } + ] + } + }) +}); +const parent = Object.assign(new Community(), { + id: 'test-parent-community', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('CommunitySidebarSearchListElementComponent', + createSidebarSearchListElementTests(CommunitySidebarSearchListElementComponent, object, parent, 'parent title', 'title', 'description') +); diff --git a/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.spec.ts b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..106289bba6 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/item-types/publication/publication-sidebar-search-list-element.component.spec.ts @@ -0,0 +1,47 @@ +import { createSidebarSearchListElementTests } from '../../sidebar-search-list-element.component.spec'; +import { PublicationSidebarSearchListElementComponent } from './publication-sidebar-search-list-element.component'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { Collection } from '../../../../../core/shared/collection.model'; + +const object = Object.assign(new ItemSearchResult(), { + indexableObject: Object.assign(new Item(), { + id: 'test-item', + metadata: { + 'dc.title': [ + { + value: 'title' + } + ], + 'dc.publisher': [ + { + value: 'publisher' + } + ], + 'dc.date.issued': [ + { + value: 'date' + } + ], + 'dc.contributor.author': [ + { + value: 'author' + } + ] + } + }) +}); +const parent = Object.assign(new Collection(), { + id: 'test-collection', + metadata: { + 'dc.title': [ + { + value: 'parent title' + } + ] + } +}); + +describe('PublicationSidebarSearchListElementComponent', + createSidebarSearchListElementTests(PublicationSidebarSearchListElementComponent, object, parent, 'parent title', 'title', '(publisher, date) author') +); diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html index adcf23dcf7..0bad828932 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html @@ -1,3 +1,3 @@ -
{{ parentTitle$ | async }}
-
{{ title }}
-
{{ description }}
+
+
+
diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts new file mode 100644 index 0000000000..f7ec05df95 --- /dev/null +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.spec.ts @@ -0,0 +1,69 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { VarDirective } from '../../utils/var.directive'; +import { RouterTestingModule } from '@angular/router/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { SearchResult } from '../../search/search-result.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { TruncatableService } from '../../truncatable/truncatable.service'; +import { LinkService } from '../../../core/cache/builders/link.service'; +import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; +import { HALResource } from '../../../core/shared/hal-resource.model'; +import { ChildHALResource } from '../../../core/shared/child-hal-resource.model'; + +export function createSidebarSearchListElementTests( + componentClass: any, + object: SearchResult, + parent: DSpaceObject, + expectedParentTitle: string, + expectedTitle: string, + expectedDescription: string, + extraProviders: any[] = [] +) { + return () => { + let component; + let fixture: ComponentFixture; + + let linkService; + + beforeEach(async(() => { + linkService = jasmine.createSpyObj('linkService', { + resolveLink: Object.assign(new HALResource(), { + [object.indexableObject.getParentLinkKey()]: createSuccessfulRemoteDataObject$(parent) + }) + }); + TestBed.configureTestingModule({ + declarations: [componentClass, VarDirective], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + providers: [ + { provide: TruncatableService, useValue: {} }, + { provide: LinkService, useValue: linkService }, + ...extraProviders + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(componentClass); + component = fixture.componentInstance; + component.object = object; + fixture.detectChanges(); + }); + + it('should contain the correct parent title', (done) => { + component.parentTitle$.subscribe((title) => { + expect(title).toEqual(expectedParentTitle); + done(); + }); + }); + + it('should contain the correct title', () => { + expect(component.title).toEqual(expectedTitle); + }); + + it('should contain the correct description', () => { + expect(component.description).toEqual(expectedDescription); + }); + }; +} From 06769493e1c16f65f77fcad9afeab4acc0b09e7c Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 26 Oct 2020 17:49:56 +0100 Subject: [PATCH 08/26] 74199: Edit current DSO button --- .../collection-page.component.html | 62 ++++++++++--------- .../community-page.component.html | 40 ++++++------ .../item-status/item-status.component.ts | 2 +- .../item-version-history.component.ts | 2 +- .../full/full-item-page.component.html | 7 ++- .../publication/publication.component.html | 11 +++- .../data/feature-authorization/feature-id.ts | 1 + .../journal-issue.component.html | 11 +++- .../journal-volume.component.html | 11 +++- .../item-pages/journal/journal.component.html | 11 +++- .../org-unit/org-unit.component.html | 11 +++- .../item-pages/person/person.component.html | 11 +++- .../item-pages/project/project.component.html | 11 +++- .../dso-page-edit-button.component.html | 6 ++ .../dso-page-edit-button.component.scss | 3 + .../dso-page-edit-button.component.spec.ts | 25 ++++++++ .../dso-page-edit-button.component.ts | 28 +++++++++ src/app/shared/shared.module.ts | 21 ++++--- src/assets/i18n/en.json5 | 20 ++++++ 19 files changed, 214 insertions(+), 80 deletions(-) create mode 100644 src/app/shared/dso-page/dso-page-edit-button/dso-page-edit-button.component.html create mode 100644 src/app/shared/dso-page/dso-page-edit-button/dso-page-edit-button.component.scss create mode 100644 src/app/shared/dso-page/dso-page-edit-button/dso-page-edit-button.component.spec.ts create mode 100644 src/app/shared/dso-page/dso-page-edit-button/dso-page-edit-button.component.ts diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html index 98552ed40b..beb7413415 100644 --- a/src/app/+collection-page/collection-page.component.html +++ b/src/app/+collection-page/collection-page.component.html @@ -3,37 +3,41 @@ *ngVar="(collectionRD$ | async) as collectionRD">
- -
+ +
+
- - - - - + + + + + - - - - - - - - - - -
+ + + + + + + + + +
+
+ +
+
-
- - - - - - - - - - - - - - - -
+
+
+ + + + + + + + + + + + + + +
+
+ +
+
diff --git a/src/app/+item-page/edit-item-page/item-status/item-status.component.ts b/src/app/+item-page/edit-item-page/item-status/item-status.component.ts index dd043330d6..3cd885ddca 100644 --- a/src/app/+item-page/edit-item-page/item-status/item-status.component.ts +++ b/src/app/+item-page/edit-item-page/item-status/item-status.component.ts @@ -56,7 +56,7 @@ export class ItemStatusComponent implements OnInit { } ngOnInit(): void { - this.itemRD$ = this.route.parent.data.pipe(map((data) => data.item)); + this.itemRD$ = this.route.parent.data.pipe(map((data) => data.dso)); this.itemRD$.pipe( first(), map((data: RemoteData) => data.payload) diff --git a/src/app/+item-page/edit-item-page/item-version-history/item-version-history.component.ts b/src/app/+item-page/edit-item-page/item-version-history/item-version-history.component.ts index ce662c5753..7cdd043603 100644 --- a/src/app/+item-page/edit-item-page/item-version-history/item-version-history.component.ts +++ b/src/app/+item-page/edit-item-page/item-version-history/item-version-history.component.ts @@ -30,6 +30,6 @@ export class ItemVersionHistoryComponent { } ngOnInit(): void { - this.itemRD$ = this.route.parent.data.pipe(map((data) => data.item)).pipe(getSucceededRemoteData()) as Observable>; + this.itemRD$ = this.route.parent.data.pipe(map((data) => data.dso)).pipe(getSucceededRemoteData()) as Observable>; } } 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 29d3582492..ce63c269de 100644 --- a/src/app/+item-page/full/full-item-page.component.html +++ b/src/app/+item-page/full/full-item-page.component.html @@ -3,7 +3,12 @@
- +
+ +
+ +
+