diff --git a/src/app/+browse-by/+browse-by-author-page/browse-by-author-page.component.ts b/src/app/+browse-by/+browse-by-author-page/browse-by-author-page.component.ts index 1605b4afab..1553889741 100644 --- a/src/app/+browse-by/+browse-by-author-page/browse-by-author-page.component.ts +++ b/src/app/+browse-by/+browse-by-author-page/browse-by-author-page.component.ts @@ -18,6 +18,9 @@ import { Item } from '../../core/shared/item.model'; styleUrls: ['./browse-by-author-page.component.scss'], templateUrl: './browse-by-author-page.component.html' }) +/** + * Component for browsing (items) by author (dc.contributor.author) + */ export class BrowseByAuthorPageComponent implements OnInit { authors$: Observable>>; @@ -55,7 +58,6 @@ export class BrowseByAuthorPageComponent implements OnInit { const pageSize = +params.pageSize || this.paginationConfig.pageSize; const sortDirection = params.sortDirection || this.sortConfig.direction; const sortField = params.sortField || this.sortConfig.field; - const startsWith = +params.query || params.query || ''; this.value = +params.value || params.value || ''; const pagination = Object.assign({}, this.paginationConfig, @@ -67,8 +69,7 @@ export class BrowseByAuthorPageComponent implements OnInit { ); const searchOptions = { pagination: pagination, - sort: sort, - startsWith: startsWith + sort: sort }; if (isNotEmpty(this.value)) { this.updatePageWithItems(searchOptions, this.value); @@ -79,10 +80,10 @@ export class BrowseByAuthorPageComponent implements OnInit { } /** + * Updates the current page with searchOptions * @param searchOptions Options to narrow down your search: * { pagination: PaginationComponentOptions, - * sort: SortOptions, - * startsWith: string } + * sort: SortOptions } */ updatePage(searchOptions) { this.authors$ = this.browseService.getBrowseEntriesFor('author', searchOptions); @@ -90,10 +91,10 @@ export class BrowseByAuthorPageComponent implements OnInit { } /** + * Updates the current page with searchOptions and display items linked to author * @param searchOptions Options to narrow down your search: * { pagination: PaginationComponentOptions, - * sort: SortOptions, - * startsWith: string } + * sort: SortOptions } * @param author The author's name for displaying items */ updatePageWithItems(searchOptions, author: string) { diff --git a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts index 6483ac8d17..3205091952 100644 --- a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts @@ -17,6 +17,9 @@ import { Collection } from '../../core/shared/collection.model'; styleUrls: ['./browse-by-title-page.component.scss'], templateUrl: './browse-by-title-page.component.html' }) +/** + * Component for browsing items by title (dc.title) + */ export class BrowseByTitlePageComponent implements OnInit { items$: Observable>>; @@ -52,7 +55,6 @@ export class BrowseByTitlePageComponent implements OnInit { const page = +params.page || this.paginationConfig.currentPage; const pageSize = +params.pageSize || this.paginationConfig.pageSize; const sortDirection = +params.page || this.sortConfig.direction; - const startsWith = +params.query || params.query || ''; const pagination = Object.assign({}, this.paginationConfig, { currentPage: page, pageSize: pageSize } @@ -63,18 +65,22 @@ export class BrowseByTitlePageComponent implements OnInit { ); this.updatePage({ pagination: pagination, - sort: sort, - startsWith: startsWith + sort: sort }); })); } + /** + * Updates the current page with searchOptions + * @param searchOptions Options to narrow down your search: + * { pagination: PaginationComponentOptions, + * sort: SortOptions } + */ updatePage(searchOptions) { this.items$ = this.itemDataService.findAll({ currentPage: searchOptions.pagination.currentPage, elementsPerPage: searchOptions.pagination.pageSize, - sort: searchOptions.sort, - startsWith: searchOptions.startsWith + sort: searchOptions.sort }); } diff --git a/src/app/core/browse/browse.service.spec.ts b/src/app/core/browse/browse.service.spec.ts index 5118ea7ecc..daaca1e5b2 100644 --- a/src/app/core/browse/browse.service.spec.ts +++ b/src/app/core/browse/browse.service.spec.ts @@ -6,7 +6,7 @@ import { getMockResponseCacheService } from '../../shared/mocks/mock-response-ca import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ResponseCacheService } from '../cache/response-cache.service'; -import { BrowseEndpointRequest, BrowseEntriesRequest } from '../data/request.models'; +import { BrowseEndpointRequest, BrowseEntriesRequest, BrowseItemsRequest } from '../data/request.models'; import { RequestService } from '../data/request.service'; import { BrowseDefinition } from '../shared/browse-definition.model'; import { BrowseService } from './browse.service'; @@ -143,7 +143,9 @@ describe('BrowseService', () => { }); - describe('getBrowseEntriesFor', () => { + describe('getBrowseEntriesFor and getBrowseItemsFor', () => { + const mockAuthorName = 'Donald Smith'; + beforeEach(() => { responseCache = initMockResponseCacheService(true); requestService = getMockRequestService(); @@ -156,7 +158,7 @@ describe('BrowseService', () => { spyOn(rdbService, 'toRemoteDataObservable').and.callThrough(); }); - describe('when called with a valid browse definition id', () => { + describe('when getBrowseEntriesFor is called with a valid browse definition id', () => { it('should configure a new BrowseEntriesRequest', () => { const expected = new BrowseEntriesRequest(requestService.generateRequestId(), browseDefinitions[1]._links.entries); @@ -175,7 +177,26 @@ describe('BrowseService', () => { }); - describe('when called with an invalid browse definition id', () => { + describe('when getBrowseItemsFor is called with a valid browse definition id', () => { + it('should configure a new BrowseItemsRequest', () => { + const expected = new BrowseItemsRequest(requestService.generateRequestId(), browseDefinitions[1]._links.items + '?filterValue=' + mockAuthorName); + + scheduler.schedule(() => service.getBrowseItemsFor(browseDefinitions[1].id, mockAuthorName).subscribe()); + scheduler.flush(); + + expect(requestService.configure).toHaveBeenCalledWith(expected); + }); + + it('should call RemoteDataBuildService to create the RemoteData Observable', () => { + service.getBrowseItemsFor(browseDefinitions[1].id, mockAuthorName); + + expect(rdbService.toRemoteDataObservable).toHaveBeenCalled(); + + }); + + }); + + describe('when getBrowseEntriesFor is called with an invalid browse definition id', () => { it('should throw an Error', () => { const definitionID = 'invalidID'; @@ -184,6 +205,16 @@ describe('BrowseService', () => { expect(service.getBrowseEntriesFor(definitionID)).toBeObservable(expected); }); }); + + describe('when getBrowseItemsFor is called with an invalid browse definition id', () => { + it('should throw an Error', () => { + + const definitionID = 'invalidID'; + const expected = cold('--#-', undefined, new Error(`No metadata browse definition could be found for id '${definitionID}'`)) + + expect(service.getBrowseItemsFor(definitionID, mockAuthorName)).toBeObservable(expected); + }); + }); }); describe('getBrowseURLFor', () => { diff --git a/src/app/core/browse/browse.service.ts b/src/app/core/browse/browse.service.ts index 2e4a0a3508..003f92698c 100644 --- a/src/app/core/browse/browse.service.ts +++ b/src/app/core/browse/browse.service.ts @@ -133,6 +133,15 @@ export class BrowseService { return this.rdb.toRemoteDataObservable(requestEntry$, responseCache$, payload$); } + /** + * Get all items linked to a certain metadata value + * @param {string} definitionID definition ID to define the metadata-field (e.g. author) + * @param {string} filterValue metadata value to filter by (e.g. author's name) + * @param options Options to narrow down your search: + * { pagination: PaginationComponentOptions, + * sort: SortOptions } + * @returns {Observable>>} + */ getBrowseItemsFor(definitionID: string, filterValue: string, options: { pagination?: PaginationComponentOptions; sort?: SortOptions; diff --git a/src/app/core/data/item-data.service.spec.ts b/src/app/core/data/item-data.service.spec.ts index 718fbde2f6..4cf126157a 100644 --- a/src/app/core/data/item-data.service.spec.ts +++ b/src/app/core/data/item-data.service.spec.ts @@ -21,19 +21,17 @@ describe('ItemDataService', () => { const halEndpointService = {} as HALEndpointService; const scopeID = '4af28e99-6a9c-4036-a199-e1b587046d39'; - const startsWith = 'a'; const options = Object.assign(new FindAllOptions(), { scopeID: scopeID, sort: { field: '', direction: undefined - }, - startsWith: startsWith + } }); const browsesEndpoint = 'https://rest.api/discover/browses'; const itemBrowseEndpoint = `${browsesEndpoint}/author/items`; - const scopedEndpoint = `${itemBrowseEndpoint}?scope=${scopeID}&startsWith=${startsWith}`; + const scopedEndpoint = `${itemBrowseEndpoint}?scope=${scopeID}`; const serviceEndpoint = `https://rest.api/core/items`; const browseError = new Error('getBrowseURL failed'); diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts index eb0896efdd..e86003f308 100644 --- a/src/app/core/data/item-data.service.ts +++ b/src/app/core/data/item-data.service.ts @@ -38,7 +38,7 @@ export class ItemDataService extends DataService { } return this.bs.getBrowseURLFor(field, this.linkPath) .filter((href: string) => isNotEmpty(href)) - .map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}` + (options.startsWith ? `&startsWith=${options.startsWith}` : '')).toString()) + .map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}`).toString()) .distinctUntilChanged(); } diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 9009473765..1efc7885c8 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -47,6 +47,11 @@ export const getRemoteDataPayload = () => (source: Observable>): Observable => source.pipe(map((remoteData: RemoteData) => remoteData.payload)); +/** + * Get the browse links from a definition by ID given an array of all definitions + * @param {string} definitionID + * @returns {(source: Observable>) => Observable} + */ export const getBrowseDefinitionLinks = (definitionID: string) => (source: Observable>): Observable => source.pipe( diff --git a/src/app/shared/browse-by/browse-by.component.ts b/src/app/shared/browse-by/browse-by.component.ts index 196134224c..062b41a440 100644 --- a/src/app/shared/browse-by/browse-by.component.ts +++ b/src/app/shared/browse-by/browse-by.component.ts @@ -17,6 +17,9 @@ import { ListableObject } from '../object-collection/shared/listable-object.mode fadeInOut ] }) +/** + * Component to display a browse-by page for any ListableObject + */ export class BrowseByComponent { @Input() title: string; @Input() objects$: Observable>>; diff --git a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.html b/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.html deleted file mode 100644 index c05c4c10c9..0000000000 --- a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.html +++ /dev/null @@ -1,3 +0,0 @@ - - {{object.value}} - diff --git a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.scss b/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.scss deleted file mode 100644 index 45a533cd01..0000000000 --- a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../styles/variables'; diff --git a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.spec.ts b/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.spec.ts deleted file mode 100644 index 8098a6a8c9..0000000000 --- a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { MetadataListElementComponent } from './metadata-list-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../utils/truncate.pipe'; -import { Item } from '../../../core/shared/item.model'; -import { Observable } from 'rxjs/Observable'; -import { Metadatum } from '../../../core/shared/metadatum.model'; - -let metadataListElementComponent: MetadataListElementComponent; -let fixture: ComponentFixture; - -const mockValue: Metadatum = Object.assign(new Metadatum(), { - key: 'dc.contributor.author', - value: 'De Langhe Kristof' -}); - -describe('MetadataListElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MetadataListElementComponent , TruncatePipe], - providers: [ - { provide: 'objectElementProvider', useValue: {mockValue}} - ], - - schemas: [ NO_ERRORS_SCHEMA ] - }).overrideComponent(MetadataListElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(MetadataListElementComponent); - metadataListElementComponent = fixture.componentInstance; - })); - - describe('When the metadatum is loaded', () => { - beforeEach(() => { - metadataListElementComponent.object = mockValue; - fixture.detectChanges(); - }); - - it('should show the value as a link', () => { - const metadatumLink = fixture.debugElement.query(By.css('a.lead')); - expect(metadatumLink.nativeElement.textContent.trim()).toBe(mockValue.value); - }); - }); -}); diff --git a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.ts b/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.ts deleted file mode 100644 index 12e140c7bf..0000000000 --- a/src/app/shared/object-list/metadata-list-element/metadata-list-element.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, Input, Inject } from '@angular/core'; - -import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; -import { ViewMode } from '../../../+search-page/search-options.model'; -import { Metadatum } from '../../../core/shared/metadatum.model'; - -@Component({ - selector: 'ds-metadata-list-element', - styleUrls: ['./metadata-list-element.component.scss'], - templateUrl: './metadata-list-element.component.html' -}) - -@renderElementsFor(Metadatum, ViewMode.List) -export class MetadataListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 223eab4c69..7ae6163bf1 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -72,7 +72,6 @@ import { NumberPickerComponent } from './number-picker/number-picker.component'; import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; import { MockAdminGuard } from './mocks/mock-admin-guard.service'; -import { MetadataListElementComponent } from './object-list/metadata-list-element/metadata-list-element.component'; import { BrowseByModule } from '../+browse-by/browse-by.module'; import { BrowseByComponent } from './browse-by/browse-by.component'; import { BrowseEntryListElementComponent } from './object-list/browse-entry-list-element/browse-entry-list-element.component'; @@ -149,7 +148,6 @@ const COMPONENTS = [ const ENTRY_COMPONENTS = [ // put shared entry components (components that are created dynamically) here ItemListElementComponent, - MetadataListElementComponent, CollectionListElementComponent, CommunityListElementComponent, SearchResultListElementComponent,