mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
improved coverage, type docs, removed startsWith option and general refactoring
This commit is contained in:
@@ -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) {
|
||||
|
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -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', () => {
|
||||
|
@@ -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;
|
||||
|
@@ -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');
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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(
|
||||
|
@@ -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>>>;
|
||||
|
@@ -1,3 +0,0 @@
|
||||
<a [routerLink]="['/browse/' + object.key + '/' + object.value]" class="lead">
|
||||
{{object.value}}
|
||||
</a>
|
@@ -1 +0,0 @@
|
||||
@import '../../../../styles/variables';
|
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
@@ -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> {}
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user