merged with master

This commit is contained in:
Christian Scheible
2017-06-16 12:02:55 +02:00
28 changed files with 900 additions and 662 deletions

View File

@@ -1,19 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Collection } from "../core/shared/collection.model";
import { Bitstream } from "../core/shared/bitstream.model";
import { RemoteData } from "../core/data/remote-data";
import { CollectionDataService } from "../core/data/collection-data.service";
import { Subscription } from "rxjs/Subscription";
@Component({
selector: 'ds-collection-page',
styleUrls: ['./collection-page.component.css'],
templateUrl: './collection-page.component.html',
})
export class CollectionPageComponent implements OnInit {
export class CollectionPageComponent implements OnInit, OnDestroy {
collectionData: RemoteData<Collection>;
logoData: RemoteData<Bitstream>;
private subs: Subscription[] = [];
constructor(
private collectionDataService: CollectionDataService,
@@ -24,12 +26,16 @@ export class CollectionPageComponent implements OnInit {
ngOnInit(): void {
this.route.params.subscribe((params: Params) => {
this.collectionData = this.collectionDataService.findById(params['id'])
this.collectionData.payload
.subscribe(collection => this.logoData = collection.logo);
this.collectionData = this.collectionDataService.findById(params['id']);
this.subs.push(this.collectionData.payload
.subscribe(collection => this.logoData = collection.logo));
});
}
ngOnDestroy(): void {
this.subs.forEach(sub => sub.unsubscribe());
}
universalInit() {
}
}

View File

@@ -1,7 +1,7 @@
import "reflect-metadata";
import { GenericConstructor } from "../../shared/generic-constructor";
import { CacheableObject } from "../object-cache.reducer";
import { NormalizedDSOType } from "../models/normalized-dspace-object-type";
import { ResourceType } from "../../shared/resource-type";
const mapsToMetadataKey = Symbol("mapsTo");
const relationshipKey = Symbol("relationship");
@@ -16,7 +16,7 @@ export const getMapsTo = function(target: any) {
return Reflect.getOwnMetadata(mapsToMetadataKey, target);
};
export const relationship = function(value: NormalizedDSOType): any {
export const relationship = function(value: ResourceType): any {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
if (!target || !propertyKey) {
return;

View File

@@ -13,7 +13,8 @@ import { Observable } from "rxjs/Observable";
import { RemoteData } from "../../data/remote-data";
import { GenericConstructor } from "../../shared/generic-constructor";
import { getMapsTo, getResourceType, getRelationships } from "./build-decorators";
import { NormalizedDSOFactory } from "../models/normalized-dspace-object-factory";
import { NormalizedObjectFactory } from "../models/normalized-object-factory";
import { Request } from "../../data/request.models";
@Injectable()
export class RemoteDataBuildService {
@@ -124,13 +125,13 @@ export class RemoteDataBuildService {
relationships.forEach((relationship: string) => {
if (hasValue(normalized[relationship])) {
const resourceType = getResourceType(normalized, relationship);
const resourceConstructor = NormalizedDSOFactory.getConstructor(resourceType);
const resourceConstructor = NormalizedObjectFactory.getConstructor(resourceType);
if (Array.isArray(normalized[relationship])) {
// without the setTimeout, the actions inside requestService.configure
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
setTimeout(() => {
normalized[relationship].forEach((href: string) => {
this.requestService.configure(href, resourceConstructor)
this.requestService.configure(new Request(href))
});
}, 0);
@@ -145,7 +146,7 @@ export class RemoteDataBuildService {
// without the setTimeout, the actions inside requestService.configure
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
setTimeout(() => {
this.requestService.configure(normalized[relationship], resourceConstructor);
this.requestService.configure(new Request(normalized[relationship]));
},0);
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);

View File

@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization } from "cerialize";
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
import { Bundle } from "../../shared/bundle.model";
import { mapsTo, relationship } from "../builders/build-decorators";
import { NormalizedDSOType } from "./normalized-dspace-object-type";
import { ResourceType } from "../../shared/resource-type";
@mapsTo(Bundle)
@inheritSerialization(NormalizedDSpaceObject)
@@ -11,7 +11,7 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
* The primary bitstream of this Bundle
*/
@autoserialize
@relationship(NormalizedDSOType.NormalizedBitstream)
@relationship(ResourceType.Bitstream)
primaryBitstream: string;
/**
@@ -25,6 +25,6 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
owner: string;
@autoserialize
@relationship(NormalizedDSOType.NormalizedBitstream)
@relationship(ResourceType.Bitstream)
bitstreams: Array<string>;
}

View File

@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
import { Collection } from "../../shared/collection.model";
import { mapsTo, relationship } from "../builders/build-decorators";
import { NormalizedDSOType } from "./normalized-dspace-object-type";
import { ResourceType } from "../../shared/resource-type";
@mapsTo(Collection)
@inheritSerialization(NormalizedDSpaceObject)
@@ -18,7 +18,7 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
* The Bitstream that represents the logo of this Collection
*/
@autoserialize
@relationship(NormalizedDSOType.NormalizedBitstream)
@relationship(ResourceType.Bitstream)
logo: string;
/**
@@ -32,7 +32,7 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
owner: string;
@autoserialize
@relationship(NormalizedDSOType.NormalizedItem)
@relationship(ResourceType.Item)
items: Array<string>;
}

View File

@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
import { Community } from "../../shared/community.model";
import { mapsTo, relationship } from "../builders/build-decorators";
import { NormalizedDSOType } from "./normalized-dspace-object-type";
import { ResourceType } from "../../shared/resource-type";
@mapsTo(Community)
@inheritSerialization(NormalizedDSpaceObject)
@@ -18,7 +18,7 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
* The Bitstream that represents the logo of this Community
*/
@autoserialize
@relationship(NormalizedDSOType.NormalizedBitstream)
@relationship(ResourceType.Bitstream)
logo: string;
/**
@@ -32,7 +32,7 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
owner: string;
@autoserialize
@relationship(NormalizedDSOType.NormalizedCollection)
@relationship(ResourceType.Collection)
collections: Array<string>;
}

View File

@@ -1,7 +0,0 @@
export enum NormalizedDSOType {
NormalizedBitstream,
NormalizedBundle,
NormalizedItem,
NormalizedCollection,
NormalizedCommunity
}

View File

@@ -1,6 +1,7 @@
import { autoserialize, autoserializeAs } from "cerialize";
import { CacheableObject } from "../object-cache.reducer";
import { Metadatum } from "../../shared/metadatum.model";
import { ResourceType } from "../../shared/resource-type";
/**
* An abstract model class for a DSpaceObject.
@@ -26,7 +27,7 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
* A string representing the kind of DSpaceObject, e.g. community, item, …
*/
@autoserialize
type: string;
type: ResourceType;
/**
* The name for this DSpaceObject
@@ -49,5 +50,6 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
/**
* The DSpaceObject that owns this DSpaceObject
*/
@autoserialize
owner: string;
}

View File

@@ -2,7 +2,7 @@ import { inheritSerialization, autoserialize } from "cerialize";
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
import { Item } from "../../shared/item.model";
import { mapsTo, relationship } from "../builders/build-decorators";
import { NormalizedDSOType } from "./normalized-dspace-object-type";
import { ResourceType } from "../../shared/resource-type";
@mapsTo(Item)
@inheritSerialization(NormalizedDSpaceObject)
@@ -33,7 +33,7 @@ export class NormalizedItem extends NormalizedDSpaceObject {
* An array of Collections that are direct parents of this Item
*/
@autoserialize
@relationship(NormalizedDSOType.NormalizedCollection)
@relationship(ResourceType.Collection)
parents: Array<string>;
/**
@@ -42,6 +42,6 @@ export class NormalizedItem extends NormalizedDSpaceObject {
owner: string;
@autoserialize
@relationship(NormalizedDSOType.NormalizedBundle)
@relationship(ResourceType.Bundle)
bundles: Array<string>;
}

View File

@@ -4,25 +4,25 @@ import { NormalizedBundle } from "./normalized-bundle.model";
import { NormalizedItem } from "./normalized-item.model";
import { NormalizedCollection } from "./normalized-collection.model";
import { GenericConstructor } from "../../shared/generic-constructor";
import { NormalizedDSOType } from "./normalized-dspace-object-type";
import { NormalizedCommunity } from "./normalized-community.model";
import { ResourceType } from "../../shared/resource-type";
export class NormalizedDSOFactory {
public static getConstructor(type: NormalizedDSOType): GenericConstructor<NormalizedDSpaceObject> {
export class NormalizedObjectFactory {
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedDSpaceObject> {
switch (type) {
case NormalizedDSOType.NormalizedBitstream: {
case ResourceType.Bitstream: {
return NormalizedBitstream
}
case NormalizedDSOType.NormalizedBundle: {
case ResourceType.Bundle: {
return NormalizedBundle
}
case NormalizedDSOType.NormalizedItem: {
case ResourceType.Item: {
return NormalizedItem
}
case NormalizedDSOType.NormalizedCollection: {
case ResourceType.Collection: {
return NormalizedCollection
}
case NormalizedDSOType.NormalizedCommunity: {
case ResourceType.Community: {
return NormalizedCommunity
}
default: {

View File

@@ -9,8 +9,12 @@ export class SuccessResponse extends Response {
}
export class ErrorResponse extends Response {
constructor(public errorMessage: string) {
errorMessage: string;
constructor(error: Error) {
super(false);
console.error(error);
this.errorMessage = error.message;
}
}

View File

@@ -33,11 +33,8 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
findAll(scopeID?: string): RemoteData<Array<TDomain>> {
const href = this.getFindAllHref(scopeID);
if (!this.responseCache.has(href) && !this.requestService.isPending(href)) {
const request = new FindAllRequest(href, this.normalizedResourceType, scopeID);
this.store.dispatch(new RequestConfigureAction(request));
this.store.dispatch(new RequestExecuteAction(href));
}
const request = new FindAllRequest(href, scopeID);
this.requestService.configure(request);
return this.rdbService.buildList<TNormalized, TDomain>(href, this.normalizedResourceType);
// return this.rdbService.buildList(href);
}
@@ -48,21 +45,14 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
findById(id: string): RemoteData<TDomain> {
const href = this.getFindByIDHref(id);
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
const request = new FindByIDRequest(href, this.normalizedResourceType, id);
this.store.dispatch(new RequestConfigureAction(request));
this.store.dispatch(new RequestExecuteAction(href));
}
const request = new FindByIDRequest(href, id);
this.requestService.configure(request);
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
// return this.rdbService.buildSingle(href);
}
findByHref(href: string): RemoteData<TDomain> {
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
const request = new Request(href, this.normalizedResourceType);
this.store.dispatch(new RequestConfigureAction(request));
this.store.dispatch(new RequestExecuteAction(href));
}
this.requestService.configure(new Request(href));
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
// return this.rdbService.buildSingle(href));
}

View File

@@ -8,7 +8,7 @@ import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.seriali
import { CacheableObject } from "../cache/object-cache.reducer";
import { Observable } from "rxjs";
import { Response, SuccessResponse, ErrorResponse } from "../cache/response-cache.models";
import { hasNoValue } from "../../shared/empty.util";
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from "../../shared/empty.util";
import { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
import { RequestState, RequestEntry } from "./request.reducer";
import {
@@ -17,6 +17,12 @@ import {
} from "./request.actions";
import { ResponseCacheService } from "../cache/response-cache.service";
import { RequestService } from "./request.service";
import { NormalizedObjectFactory } from "../cache/models/normalized-object-factory";
import { ResourceType } from "../shared/resource-type";
function isObjectLevel(halObj: any) {
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
}
@Injectable()
export class RequestEffects {
@@ -38,30 +44,87 @@ export class RequestEffects {
.take(1);
})
.flatMap((entry: RequestEntry) => {
const [ifArray, ifNotArray] = this.restApi.get(entry.request.href)
.share() // share ensures restApi.get() doesn't get called twice when the partitions are used below
.partition((data: DSpaceRESTV2Response) => Array.isArray(data._embedded));
return Observable.merge(
ifArray.map((data: DSpaceRESTV2Response) => {
return new DSpaceRESTv2Serializer(entry.request.resourceType).deserializeArray(data);
}).do((cos: CacheableObject[]) => cos.forEach((t) => this.addToObjectCache(t)))
.map((cos: Array<CacheableObject>): Array<string> => cos.map(t => t.uuid)),
ifNotArray.map((data: DSpaceRESTV2Response) => {
return new DSpaceRESTv2Serializer(entry.request.resourceType).deserialize(data);
}).do((co: CacheableObject) => this.addToObjectCache(co))
.map((co: CacheableObject): Array<string> => [co.uuid])
).map((ids: Array<string>) => new SuccessResponse(ids))
return this.restApi.get(entry.request.href)
.map((data: DSpaceRESTV2Response) => this.processEmbedded(data._embedded))
.map((ids: Array<string>) => new SuccessResponse(ids))
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
.map((response: Response) => new RequestCompleteAction(entry.request.href))
.catch((error: Error) => Observable.of(new ErrorResponse(error.message))
.catch((error: Error) => Observable.of(new ErrorResponse(error))
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
});
protected processEmbedded(_embedded: any): Array<string> {
if (isNotEmpty(_embedded)) {
if (isObjectLevel(_embedded)) {
return this.deserializeAndCache(_embedded);
}
else {
let uuids = [];
Object.keys(_embedded)
.filter(property => _embedded.hasOwnProperty(property))
.forEach(property => {
uuids = [...uuids, ...this.deserializeAndCache(_embedded[property])];
});
return uuids;
}
}
}
protected deserializeAndCache(obj): Array<string> {
let type: ResourceType;
const isArray = Array.isArray(obj);
if (isArray && isEmpty(obj)) {
return [];
}
if (isArray) {
type = obj[0]["type"];
}
else {
type = obj["type"];
}
if (hasValue(type)) {
const normObjConstructor = NormalizedObjectFactory.getConstructor(type);
if (hasValue(normObjConstructor)) {
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
if (isArray) {
obj.forEach(o => {
if (isNotEmpty(o._embedded)) {
this.processEmbedded(o._embedded);
}
});
const normalizedObjArr = serializer.deserializeArray(obj);
normalizedObjArr.forEach(t => this.addToObjectCache(t));
return normalizedObjArr.map(t => t.uuid);
}
else {
if (isNotEmpty(obj._embedded)) {
this.processEmbedded(obj._embedded);
}
const normalizedObj = serializer.deserialize(obj);
this.addToObjectCache(normalizedObj);
return [normalizedObj.uuid];
}
}
else {
//TODO move check to Validator?
throw new Error(`The server returned an object with an unknown a known type: ${type}`);
}
}
else {
//TODO move check to Validator
throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
}
}
protected addToObjectCache(co: CacheableObject): void {
if (hasNoValue(co) || hasNoValue(co.uuid)) {
throw new Error('The server returned an invalid object');

View File

@@ -5,28 +5,25 @@ import { GenericConstructor } from "../shared/generic-constructor";
export class Request<T> {
constructor(
public href: string,
public resourceType: GenericConstructor<T>
) {}
}
export class FindByIDRequest<T> extends Request<T> {
constructor(
href: string,
resourceType: GenericConstructor<T>,
public resourceID: string
) {
super(href, resourceType);
super(href);
}
}
export class FindAllRequest<T> extends Request<T> {
constructor(
href: string,
resourceType: GenericConstructor<T>,
public scopeID?: string,
public paginationOptions?: PaginationOptions,
public sortOptions?: SortOptions
) {
super(href, resourceType);
super(href);
}
}

View File

@@ -8,7 +8,6 @@ import { RequestConfigureAction, RequestExecuteAction } from "./request.actions"
import { ResponseCacheService } from "../cache/response-cache.service";
import { ObjectCacheService } from "../cache/object-cache.service";
import { CacheableObject } from "../cache/object-cache.reducer";
import { GenericConstructor } from "../shared/generic-constructor";
@Injectable()
export class RequestService {
@@ -35,14 +34,13 @@ export class RequestService {
return this.store.select<RequestEntry>('core', 'data', 'request', href);
}
configure<T extends CacheableObject>(href: string, normalizedType: GenericConstructor<T>): void {
const isCached = this.objectCache.hasBySelfLink(href);
const isPending = this.isPending(href);
configure<T extends CacheableObject>(request: Request<T>): void {
const isCached = this.objectCache.hasBySelfLink(request.href);
const isPending = this.isPending(request.href);
if (!(isCached || isPending)) {
const request = new Request(href, normalizedType);
this.store.dispatch(new RequestConfigureAction(request));
this.store.dispatch(new RequestExecuteAction(href));
this.store.dispatch(new RequestExecuteAction(request.href));
}
}
}

View File

@@ -84,14 +84,10 @@ describe("DSpaceRESTv2Serializer", () => {
it("should turn a valid document describing a single entity in to a valid model", () => {
const serializer = new DSpaceRESTv2Serializer(TestModel);
const doc = {
"_embedded": testResponses[0],
};
const model = serializer.deserialize(testResponses[0]);
const model = serializer.deserialize(doc);
expect(model.id).toBe(doc._embedded.id);
expect(model.name).toBe(doc._embedded.name);
expect(model.id).toBe(testResponses[0].id);
expect(model.name).toBe(testResponses[0].name);
});
//TODO cant implement/test this yet - depends on how relationships
@@ -127,12 +123,8 @@ describe("DSpaceRESTv2Serializer", () => {
it("should throw an error when dealing with a document describing an array", () => {
const serializer = new DSpaceRESTv2Serializer(TestModel);
const doc = {
"_embedded": testResponses
};
expect(() => {
serializer.deserialize(doc);
serializer.deserialize(testResponses);
}).toThrow();
});

View File

@@ -3,6 +3,7 @@ import { Serializer } from "../serializer";
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
import { GenericConstructor } from "../shared/generic-constructor";
import { hasNoValue, hasValue } from "../../shared/empty.util";
/**
* This Serializer turns responses from v2 of DSpace's REST API
@@ -49,13 +50,13 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
* @param response An object returned by the backend
* @returns a model of type T
*/
deserialize(response: DSpaceRESTV2Response): T {
deserialize(response: any): T {
// TODO enable validation, once rest data stabilizes
// new DSpaceRESTv2Validator(response).validate();
if (Array.isArray(response._embedded)) {
if (Array.isArray(response)) {
throw new Error('Expected a single model, use deserializeArray() instead');
}
let normalized = Object.assign({}, response._embedded, this.normalizeLinks(response._embedded._links));
let normalized = Object.assign({}, response, this.normalizeLinks(response._links));
return <T> Deserialize(normalized, this.modelType);
}
@@ -65,13 +66,13 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
* @param response An object returned by the backend
* @returns an array of models of type T
*/
deserializeArray(response: DSpaceRESTV2Response): Array<T> {
deserializeArray(response: any): Array<T> {
//TODO enable validation, once rest data stabilizes
// new DSpaceRESTv2Validator(response).validate();
if (!Array.isArray(response._embedded)) {
if (!Array.isArray(response)) {
throw new Error('Expected an Array, use deserialize() instead');
}
let normalized = response._embedded.map((resource) => {
let normalized = response.map((resource) => {
return Object.assign({}, resource, this.normalizeLinks(resource._links));
});

View File

@@ -2,6 +2,7 @@ import { Metadatum } from "./metadatum.model"
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
import { CacheableObject } from "../cache/object-cache.reducer";
import { RemoteData } from "../data/remote-data";
import { ResourceType } from "./resource-type";
/**
* An abstract model class for a DSpaceObject.
@@ -23,7 +24,7 @@ export abstract class DSpaceObject implements CacheableObject {
/**
* A string representing the kind of DSpaceObject, e.g. community, item, …
*/
type: string;
type: ResourceType;
/**
* The name for this DSpaceObject

View File

@@ -0,0 +1,11 @@
/**
* TODO replace with actual string enum after upgrade to TypeScript 2.4:
* https://github.com/Microsoft/TypeScript/pull/15486
*/
export enum ResourceType {
Bundle = <any> "bundle",
Bitstream = <any> "bitstream",
Item = <any> "item",
Collection = <any> "collection",
Community = <any> "community"
}

View File

@@ -247,12 +247,12 @@ describe('Pagination component', () => {
changePage(testFixture, 3);
tick();
expect(routerStub.navigate).toHaveBeenCalledWith([{pageId: 'test', page: 3, pageSize: 10}]);
expect(routerStub.navigate).toHaveBeenCalledWith([], { queryParams: { pageId: 'test', page: 3, pageSize: 10 } });
expect(paginationComponent.currentPage).toEqual(3);
changePageSize(testFixture, '20');
tick();
expect(routerStub.navigate).toHaveBeenCalledWith([{pageId: 'test', page: 3, pageSize: 20}]);
expect(routerStub.navigate).toHaveBeenCalledWith([], { queryParams: { pageId: 'test', page: 3, pageSize: 20 } });
expect(paginationComponent.pageSize).toEqual(20);
}));

View File

@@ -58,6 +58,11 @@ export class PaginationComponent implements OnDestroy, OnInit {
*/
public currentPage = 1;
/**
* Current URL query parameters
*/
public currentQueryParams = {};
/**
* An observable of HostWindowState type
*/
@@ -121,14 +126,15 @@ export class PaginationComponent implements OnDestroy, OnInit {
this.pageSize = this.paginationOptions.pageSize;
this.pageSizeOptions = this.paginationOptions.pageSizeOptions;
this.routeSubscription = this.route.params
.map(params => params)
.subscribe(params => {
if(this.id == params['pageId']
&& (this.paginationOptions.currentPage != params['page']
|| this.paginationOptions.pageSize != params['pageSize'])
this.routeSubscription = this.route.queryParams
.map(queryParams => queryParams)
.subscribe(queryParams => {
this.currentQueryParams = queryParams;
if(this.id == queryParams['pageId']
&& (this.paginationOptions.currentPage != queryParams['page']
|| this.paginationOptions.pageSize != queryParams['pageSize'])
) {
this.validateParams(params['page'], params['pageSize']);
this.validateParams(queryParams['page'], queryParams['pageSize']);
}
});
this.setShowingDetail();
@@ -162,7 +168,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
* The page being navigated to.
*/
public doPageChange(page: number) {
this.router.navigate([{ pageId: this.id, page: page, pageSize: this.pageSize }]);
this.router.navigate([], { queryParams: Object.assign({}, this.currentQueryParams, { pageId: this.id, page: page, pageSize: this.pageSize }) });
this.currentPage = page;
this.setShowingDetail();
this.pageChange.emit(page);
@@ -175,7 +181,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
* The new page size.
*/
public setPageSize(pageSize: number) {
this.router.navigate([{ pageId: this.id, page: this.currentPage, pageSize: pageSize }]);
this.router.navigate([], { queryParams: Object.assign({}, this.currentQueryParams, { pageId: this.id, page: this.currentPage, pageSize: pageSize }) });
this.pageSize = pageSize;
this.setShowingDetail();
this.pageSizeChange.emit(pageSize);

View File

@@ -4,7 +4,6 @@ import { BehaviorSubject } from "rxjs";
export class RouterStub {
//noinspection TypeScriptUnresolvedFunction
navigate = jasmine.createSpy('navigate');
//navigate1: jasmine.createSpy('navigate');
}
export class ActivatedRouteStub {
@@ -12,6 +11,7 @@ export class ActivatedRouteStub {
// ActivatedRoute.params is Observable
private subject = new BehaviorSubject(this.testParams);
params = this.subject.asObservable();
queryParams = this.subject.asObservable();
constructor(params?: Params) {
if (params) {

View File

@@ -82,7 +82,7 @@ export function createMockApi() {
let id = req.params.community_id;
try {
req.community_id = id;
req.community = COMMUNITIES.find((community) => {
req.community = COMMUNITIES["communities"].find((community) => {
return community.id === id;
});
next();
@@ -143,7 +143,7 @@ export function createMockApi() {
let id = req.params.collection_id;
try {
req.collection_id = id;
req.collection = COLLECTIONS.find((collection) => {
req.collection = COLLECTIONS["collections"].find((collection) => {
return collection.id === id;
});
next();
@@ -205,7 +205,7 @@ export function createMockApi() {
let id = req.params.item_id;
try {
req.item_id = id;
req.item = ITEMS.find((item) => {
req.item = ITEMS["items"].find((item) => {
return item.id === id;
});
next();
@@ -250,7 +250,7 @@ export function createMockApi() {
let id = req.params.bundle_id;
try {
req.bundle_id = id;
req.bundle = BUNDLES.find((bundle) => {
req.bundle = BUNDLES["bundles"].find((bundle) => {
return bundle.id === id;
});
next();
@@ -280,7 +280,7 @@ export function createMockApi() {
let id = req.params.bitstream_id;
try {
req.bitstream_id = id;
req.bitstream = BITSTREAMS.find((bitstream) => {
req.bitstream = BITSTREAMS["bitstreams"].find((bitstream) => {
return bitstream.id === id;
});
next();

View File

@@ -1,4 +1,5 @@
export const BITSTREAMS = [
export const BITSTREAMS = {
"bitstreams": [
{
"_links": {
"self": { "href": "/bitstreams/3678" },
@@ -51,6 +52,7 @@ export const BITSTREAMS = [
},
"id": "8934",
"uuid": "ba7d24f2-8fc7-4b8e-b7b6-6c32be1c12a6",
"type": "bitstream",
"name": "license.txt",
"size": 41183,
"checksum": {
@@ -77,4 +79,5 @@ export const BITSTREAMS = [
"format": "PNG",
"mimetype": "image/png"
},
];
]
};

View File

@@ -1,4 +1,5 @@
export const BUNDLES = [
export const BUNDLES = {
"bundles": [
{
"_links": {
"self": { "href": "/bundles/2355" },
@@ -50,9 +51,11 @@ export const BUNDLES = [
},
"id": "8475",
"uuid": "99f78e5e-3677-43b0-aaef-cddaa1a49092",
"type": "bundle",
"name": "LICENSE",
"metadata": [
{ "key": "dc.title", "value": "LICENSE", "language": "en" }
]
}
];
]
};

View File

@@ -1,4 +1,5 @@
export const COLLECTIONS = [
export const COLLECTIONS = {
"collections": [
{
"_links": {
"self": { "href": "/collections/5179" },
@@ -72,4 +73,5 @@ export const COLLECTIONS = [
}
]
}
];
]
};

View File

@@ -1,4 +1,5 @@
export const ITEMS = [
export const ITEMS = {
"items": [
{
"_links": {
"self": {
@@ -16,12 +17,9 @@ export const ITEMS = [
{
"href": "/bundles/2355"
},
{
"href": "/bundles/5687"
},
{
"href": "/bundles/8475"
}
// {
// "href": "/bundles/5687"
// }
]
},
"id": "8871",
@@ -93,8 +91,95 @@ export const ITEMS = [
"value": "(not specified)",
"language": "en"
}
],
"_embedded": {
"parents": [
{
"_links": {
"self": { "href": "/collections/6547" },
"items": [
{ "href": "/items/8871" },
{ "href": "/items/9978" }
]
},
"id": "6547",
"uuid": "598ce822-c357-46f3-ab70-63724d02d6ad",
"type": "collection",
"name": "Another Test Collection",
"handle": "123456789/6547",
"metadata": [
{
"key": "dc.rights",
"value": "<p>© 2005-2016 JOHN DOE SOME RIGHTS RESERVED</p>",
"language": null
},
{
"key": "dc.description",
"value": "<p class='lead'>Another introductory text dolor sit amet, consectetur adipiscing elit. Duis laoreet lorem erat, eget auctor est ultrices quis. Nullam ac tincidunt quam. In nec nisl odio. In egestas aliquam tincidunt.</p>\r\n<p>Integer vitae diam id dolor pharetra dignissim in sed enim. Vivamus pulvinar tristique sem a iaculis. Aenean ultricies dui vel facilisis laoreet. Integer porta erat eu ultrices rhoncus. Sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum.</p>",
"language": null
},
{
"key": "dc.description.abstract",
"value": "Another collection for testing purposes",
"language": null
},
{
"key": "dc.description.tableofcontents",
"value": "<p>Some more news sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum. Donec sed ultricies erat, nec sollicitudin mauris. Duis varius nulla quis quam vulputate, at hendrerit turpis rutrum. Integer nec facilisis sapien. Fusce fringilla malesuada lectus id pulvinar. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae</p>",
"language": null
}
]
}
],
"bundles": [
{
"_links": {
"self": { "href": "/bundles/2355" },
"items": [
{ "href": "/items/8871" }
],
"bitstreams": [
{ "href": "/bitstreams/3678" },
],
"primaryBitstream": { "href": "/bitstreams/3678" }
},
"id": "2355",
"uuid": "35e0606d-5e18-4f9c-aa61-74fc751cc3f9",
"type": "bundle",
"name": "ORIGINAL",
"metadata": [
{ "key": "dc.title", "value": "ORIGINAL", "language": "en" }
],
"_embedded": {
"bitstreams": [
{
"_links": {
"self": { "href": "/bitstreams/3678" },
"bundle": { "href": "/bundles/35e0606d-5e18-4f9c-aa61-74fc751cc3f9" },
"retrieve": { "href": "/bitstreams/43c57c2b-206f-4645-8c8f-5f10c84b09fa/retrieve" }
},
"id": "3678",
"uuid": "43c57c2b-206f-4645-8c8f-5f10c84b09fa",
"type": "bitstream",
"name": "do_open_access_CRL.pdf",
"size": 636626,
"checksum": {
"value": "063dfbbbac873aa3fca479b878eccff3",
"algorithm": "MD5"
},
"metadata": [
{ "key": "dc.title", "value": "do_open_access_CRL.pdf", "language": null },
{ "key": "dc.description", "value": "Conference Paper", "language": "en" }
],
"format": "Adobe PDF",
"mimetype": "application/pdf"
}
]
}
}
]
}
},
{
"_links": {
"self": {
@@ -112,9 +197,9 @@ export const ITEMS = [
{
"href": "/bundles/2355"
},
{
"href": "/bundles/5687"
}
// {
// "href": "/bundles/5687"
// }
]
},
"id": "9978",
@@ -166,6 +251,84 @@ export const ITEMS = [
"value": "(not specified)",
"language": "en"
}
],
"_embedded": {
"parents": [
{
"_links": {
"self": { "href": "/collections/5179" },
"items": [
{ "href": "/items/8871" },
{ "href": "/items/9978" }
],
"logo": { "href": "/bitstreams/4688" }
},
"id": "5179",
"uuid": "9e32a2e2-6b91-4236-a361-995ccdc14c60",
"type": "collection",
"name": "A Test Collection",
"handle": "123456789/5179",
"metadata": [
{
"key": "dc.rights",
"value": "<p>© 2005-2016 JOHN DOE SOME RIGHTS RESERVED</p>",
"language": null
},
{
"key": "dc.description",
"value": "<p class='lead'>An introductory text dolor sit amet, consectetur adipiscing elit. Duis laoreet lorem erat, eget auctor est ultrices quis. Nullam ac tincidunt quam. In nec nisl odio. In egestas aliquam tincidunt.</p>\r\n<p>Integer vitae diam id dolor pharetra dignissim in sed enim. Vivamus pulvinar tristique sem a iaculis. Aenean ultricies dui vel facilisis laoreet. Integer porta erat eu ultrices rhoncus. Sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum.</p>",
"language": null
},
{
"key": "dc.description.abstract",
"value": "A collection for testing purposes",
"language": null
},
{
"key": "dc.description.tableofcontents",
"value": "<p>Some news sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum. Donec sed ultricies erat, nec sollicitudin mauris. Duis varius nulla quis quam vulputate, at hendrerit turpis rutrum. Integer nec facilisis sapien. Fusce fringilla malesuada lectus id pulvinar. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae</p>",
"language": null
}
]
},
{
"_links": {
"self": { "href": "/collections/6547" },
"items": [
{ "href": "/items/8871" },
{ "href": "/items/9978" }
]
},
"id": "6547",
"uuid": "598ce822-c357-46f3-ab70-63724d02d6ad",
"type": "collection",
"name": "Another Test Collection",
"handle": "123456789/6547",
"metadata": [
{
"key": "dc.rights",
"value": "<p>© 2005-2016 JOHN DOE SOME RIGHTS RESERVED</p>",
"language": null
},
{
"key": "dc.description",
"value": "<p class='lead'>Another introductory text dolor sit amet, consectetur adipiscing elit. Duis laoreet lorem erat, eget auctor est ultrices quis. Nullam ac tincidunt quam. In nec nisl odio. In egestas aliquam tincidunt.</p>\r\n<p>Integer vitae diam id dolor pharetra dignissim in sed enim. Vivamus pulvinar tristique sem a iaculis. Aenean ultricies dui vel facilisis laoreet. Integer porta erat eu ultrices rhoncus. Sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum.</p>",
"language": null
},
{
"key": "dc.description.abstract",
"value": "Another collection for testing purposes",
"language": null
},
{
"key": "dc.description.tableofcontents",
"value": "<p>Some more news sed condimentum malesuada ex sit amet ullamcorper. Morbi a ipsum dolor. Vivamus interdum eget lacus ut fermentum. Donec sed ultricies erat, nec sollicitudin mauris. Duis varius nulla quis quam vulputate, at hendrerit turpis rutrum. Integer nec facilisis sapien. Fusce fringilla malesuada lectus id pulvinar. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae</p>",
"language": null
}
]
}
];
]
}
}
]
};

View File

@@ -1,4 +1,5 @@
export const METADATA = [
export const METADATA = {
"metadata": [
{
"type": "metadata",
"id": "d58a3098-b390-4cd6-8f52-b088b3daa637",
@@ -179,4 +180,5 @@ export const METADATA = [
"language": "en"
}
}
];
]
};