improved coverage, type docs, removed startsWith option and general refactoring

This commit is contained in:
Kristof De Langhe
2018-08-09 12:37:09 +02:00
parent 883a1d8881
commit 072507b293
13 changed files with 74 additions and 90 deletions

View File

@@ -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<RemoteData<PaginatedList<BrowseEntry>>>;
@@ -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) {

View File

@@ -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<RemoteData<PaginatedList<Item>>>;
@@ -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
});
}

View File

@@ -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', () => {

View File

@@ -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<RemoteData<PaginatedList<Item>>>}
*/
getBrowseItemsFor(definitionID: string, filterValue: string, options: {
pagination?: PaginationComponentOptions;
sort?: SortOptions;

View File

@@ -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');

View File

@@ -38,7 +38,7 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
}
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();
}

View File

@@ -47,6 +47,11 @@ export const getRemoteDataPayload = () =>
<T>(source: Observable<RemoteData<T>>): Observable<T> =>
source.pipe(map((remoteData: RemoteData<T>) => remoteData.payload));
/**
* Get the browse links from a definition by ID given an array of all definitions
* @param {string} definitionID
* @returns {(source: Observable<RemoteData<BrowseDefinition[]>>) => Observable<any>}
*/
export const getBrowseDefinitionLinks = (definitionID: string) =>
(source: Observable<RemoteData<BrowseDefinition[]>>): Observable<any> =>
source.pipe(

View File

@@ -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<RemoteData<PaginatedList<ListableObject>>>;

View File

@@ -1,3 +0,0 @@
<a [routerLink]="['/browse/' + object.key + '/' + object.value]" class="lead">
{{object.value}}
</a>

View File

@@ -1 +0,0 @@
@import '../../../../styles/variables';

View File

@@ -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<MetadataListElementComponent>;
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);
});
});
});

View File

@@ -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<Metadatum> {}

View File

@@ -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,