mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-14 05:23:06 +00:00
Merge remote-tracking branch 'remotes/origin/master' into no-image
# Conflicts: # src/app/collection-page/collection-page.module.ts # src/app/collection-page/logo/collection-page-logo.component.html # src/app/collection-page/logo/collection-page-logo.component.ts
This commit is contained in:
@@ -10,6 +10,15 @@
|
|||||||
"license": "License"
|
"license": "License"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"community": {
|
||||||
|
"page": {
|
||||||
|
"news": "News",
|
||||||
|
"license": "License"
|
||||||
|
},
|
||||||
|
"sub-collection-list": {
|
||||||
|
"head": "Collections of this Community"
|
||||||
|
}
|
||||||
|
},
|
||||||
"item": {
|
"item": {
|
||||||
"page": {
|
"page": {
|
||||||
"author": "Author",
|
"author": "Author",
|
||||||
|
@@ -10,6 +10,7 @@ import { AppRoutingModule } from './app-routing.module';
|
|||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { HeaderComponent } from './header/header.component';
|
import { HeaderComponent } from './header/header.component';
|
||||||
import { CollectionPageModule } from './collection-page/collection-page.module';
|
import { CollectionPageModule } from './collection-page/collection-page.module';
|
||||||
|
import { CommunityPageModule } from './community-page/community-page.module';
|
||||||
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
||||||
|
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
|||||||
HomeModule,
|
HomeModule,
|
||||||
ItemPageModule,
|
ItemPageModule,
|
||||||
CollectionPageModule,
|
CollectionPageModule,
|
||||||
|
CommunityPageModule,
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
AppRoutingModule
|
AppRoutingModule
|
||||||
],
|
],
|
||||||
|
@@ -1,16 +1,32 @@
|
|||||||
<div class="collection-page" *ngIf="collectionData.hasSucceeded | async">
|
<div class="collection-page" *ngIf="collectionData.hasSucceeded | async">
|
||||||
<ds-collection-page-name [name]="(collectionData.payload | async)?.name"></ds-collection-page-name>
|
<!-- Collection Name -->
|
||||||
<ds-collection-page-logo *ngIf="logoData" [logo]="logoData.payload | async"></ds-collection-page-logo>
|
<ds-comcol-page-header
|
||||||
<ds-collection-page-introductory-text
|
[name]="(collectionData.payload | async)?.name">
|
||||||
[introductoryText]="(collectionData.payload | async)?.introductoryText">
|
</ds-comcol-page-header>
|
||||||
</ds-collection-page-introductory-text>
|
<!-- Collection logo -->
|
||||||
<ds-collection-page-news
|
<ds-comcol-page-logo *ngIf="logoData"
|
||||||
[sidebarText]="(collectionData.payload | async)?.sidebarText">
|
[logo]="logoData.payload | async"
|
||||||
</ds-collection-page-news>
|
[alternateText]="'Collection Logo'">
|
||||||
<ds-collection-page-copyright
|
</ds-comcol-page-logo>
|
||||||
[copyrightText]="(collectionData.payload | async)?.copyrightText">
|
<!-- Introductionary text -->
|
||||||
</ds-collection-page-copyright>
|
<ds-comcol-page-content
|
||||||
<ds-collection-page-license
|
[content]="(collectionData.payload | async)?.introductoryText"
|
||||||
[license]="(collectionData.payload | async)?.license">
|
[hasInnerHtml]="true">
|
||||||
</ds-collection-page-license>
|
</ds-comcol-page-content>
|
||||||
|
<!-- News -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(collectionData.payload | async)?.sidebarText"
|
||||||
|
[hasInnerHtml]="true"
|
||||||
|
[title]="'community.page.news'">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
<!-- Copyright -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(collectionData.payload | async)?.copyrightText"
|
||||||
|
[hasInnerHtml]="true">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
<!-- Licence -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(collectionData.payload | async)?.license"
|
||||||
|
[title]="'collection.page.license'">
|
||||||
|
</ds-comcol-page-content>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,19 +1,21 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
import { Collection } from "../core/shared/collection.model";
|
import { Collection } from "../core/shared/collection.model";
|
||||||
import { Bitstream } from "../core/shared/bitstream.model";
|
import { Bitstream } from "../core/shared/bitstream.model";
|
||||||
import { RemoteData } from "../core/data/remote-data";
|
import { RemoteData } from "../core/data/remote-data";
|
||||||
import { CollectionDataService } from "../core/data/collection-data.service";
|
import { CollectionDataService } from "../core/data/collection-data.service";
|
||||||
|
import { Subscription } from "rxjs/Subscription";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-collection-page',
|
selector: 'ds-collection-page',
|
||||||
styleUrls: ['./collection-page.component.css'],
|
styleUrls: ['./collection-page.component.css'],
|
||||||
templateUrl: './collection-page.component.html',
|
templateUrl: './collection-page.component.html',
|
||||||
})
|
})
|
||||||
export class CollectionPageComponent implements OnInit {
|
export class CollectionPageComponent implements OnInit, OnDestroy {
|
||||||
collectionData: RemoteData<Collection>;
|
collectionData: RemoteData<Collection>;
|
||||||
logoData: RemoteData<Bitstream>;
|
logoData: RemoteData<Bitstream>;
|
||||||
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private collectionDataService: CollectionDataService,
|
private collectionDataService: CollectionDataService,
|
||||||
@@ -24,12 +26,16 @@ export class CollectionPageComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.route.params.subscribe((params: Params) => {
|
this.route.params.subscribe((params: Params) => {
|
||||||
this.collectionData = this.collectionDataService.findById(params['id'])
|
this.collectionData = this.collectionDataService.findById(params['id']);
|
||||||
this.collectionData.payload
|
this.subs.push(this.collectionData.payload
|
||||||
.subscribe(collection => this.logoData = collection.logo);
|
.subscribe(collection => this.logoData = collection.logo));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
universalInit() {
|
universalInit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,13 +5,6 @@ import { TranslateModule } from "@ngx-translate/core";
|
|||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
import { CollectionPageComponent } from './collection-page.component';
|
import { CollectionPageComponent } from './collection-page.component';
|
||||||
import { FieldWrapperComponent } from './field-wrapper/field-wrapper.component';
|
|
||||||
import { CollectionPageNameComponent } from './name/collection-page-name.component';
|
|
||||||
import { CollectionPageLogoComponent } from './logo/collection-page-logo.component';
|
|
||||||
import { CollectionPageIntroductoryTextComponent } from './introductory-text/collection-page-introductory-text.component';
|
|
||||||
import { CollectionPageNewsComponent } from './news/collection-page-news.component';
|
|
||||||
import { CollectionPageCopyrightComponent } from './copyright/collection-page-copyright.component';
|
|
||||||
import { CollectionPageLicenseComponent } from './license/collection-page-license.component';
|
|
||||||
import { CollectionPageRoutingModule } from './collection-page-routing.module';
|
import { CollectionPageRoutingModule } from './collection-page-routing.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -23,13 +16,6 @@ import { CollectionPageRoutingModule } from './collection-page-routing.module';
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
CollectionPageComponent,
|
CollectionPageComponent,
|
||||||
FieldWrapperComponent,
|
|
||||||
CollectionPageNameComponent,
|
|
||||||
CollectionPageLogoComponent,
|
|
||||||
CollectionPageIntroductoryTextComponent,
|
|
||||||
CollectionPageNewsComponent,
|
|
||||||
CollectionPageCopyrightComponent,
|
|
||||||
CollectionPageLicenseComponent,
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CollectionPageModule { }
|
export class CollectionPageModule { }
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
<ds-field-wrapper *ngIf="copyrightText" class="collection-page-copyright">
|
|
||||||
<p [innerHtml]="copyrightText"></p>
|
|
||||||
</ds-field-wrapper>
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-copyright',
|
|
||||||
styleUrls: ['./collection-page-copyright.component.css'],
|
|
||||||
templateUrl: './collection-page-copyright.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageCopyrightComponent {
|
|
||||||
@Input() copyrightText: String;
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
<div class="collection-page-field-wrapper">
|
|
||||||
<ng-content></ng-content>
|
|
||||||
</div>
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-field-wrapper',
|
|
||||||
styleUrls: ['./field-wrapper.component.css'],
|
|
||||||
templateUrl: './field-wrapper.component.html',
|
|
||||||
})
|
|
||||||
export class FieldWrapperComponent {
|
|
||||||
@Input() name: String;
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
<ds-field-wrapper *ngIf="introductoryText" class="collection-page-introductory-text">
|
|
||||||
<p [innerHtml]="introductoryText"></p>
|
|
||||||
</ds-field-wrapper>
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-introductory-text',
|
|
||||||
styleUrls: ['./collection-page-introductory-text.component.css'],
|
|
||||||
templateUrl: './collection-page-introductory-text.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageIntroductoryTextComponent {
|
|
||||||
@Input() introductoryText: String;
|
|
||||||
}
|
|
@@ -1,4 +0,0 @@
|
|||||||
<ds-field-wrapper *ngIf="license" class="collection-page-license">
|
|
||||||
<h2>{{ 'collection.page.license' | translate }}</h2>
|
|
||||||
<p>{{ license }}</p>
|
|
||||||
</ds-field-wrapper>
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-license',
|
|
||||||
styleUrls: ['./collection-page-license.component.css'],
|
|
||||||
templateUrl: './collection-page-license.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageLicenseComponent {
|
|
||||||
@Input() license: String;
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
<ds-field-wrapper *ngIf="logo" class="collection-page-logo">
|
|
||||||
<img [src]="logo.url" class="img-responsive" alt="Collection logo" (error)="errorHandler($event)"/>
|
|
||||||
</ds-field-wrapper>
|
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
@@ -1,25 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
import { Bitstream } from "../../core/shared/bitstream.model";
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-logo',
|
|
||||||
styleUrls: ['./collection-page-logo.component.css'],
|
|
||||||
templateUrl: './collection-page-logo.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageLogoComponent {
|
|
||||||
@Input() logo: Bitstream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default 'holder.js' image
|
|
||||||
*/
|
|
||||||
holderSource: string = "data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23EEEEEE%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E";
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler(event) {
|
|
||||||
event.currentTarget.src = this.holderSource;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-name',
|
|
||||||
styleUrls: ['./collection-page-name.component.css'],
|
|
||||||
templateUrl: './collection-page-name.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageNameComponent {
|
|
||||||
@Input() name: String;
|
|
||||||
}
|
|
@@ -1,4 +0,0 @@
|
|||||||
<ds-field-wrapper *ngIf="sidebarText" class="collection-page-news">
|
|
||||||
<h2>{{ 'collection.page.news' | translate }}</h2>
|
|
||||||
<p [innerHtml]="sidebarText"></p>
|
|
||||||
</ds-field-wrapper>
|
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-collection-page-news',
|
|
||||||
styleUrls: ['./collection-page-news.component.css'],
|
|
||||||
templateUrl: './collection-page-news.component.html',
|
|
||||||
})
|
|
||||||
export class CollectionPageNewsComponent {
|
|
||||||
@Input() sidebarText: String;
|
|
||||||
}
|
|
13
src/app/community-page/community-page-routing.module.ts
Normal file
13
src/app/community-page/community-page-routing.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { CommunityPageComponent } from './community-page.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild([
|
||||||
|
{ path: 'communities/:id', component: CommunityPageComponent }
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CommunityPageRoutingModule { }
|
26
src/app/community-page/community-page.component.html
Normal file
26
src/app/community-page/community-page.component.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<div class="community-page" *ngIf="communityData.hasSucceeded | async">
|
||||||
|
<!-- Community name -->
|
||||||
|
<ds-comcol-page-header [name]="(communityData.payload | async)?.name"></ds-comcol-page-header>
|
||||||
|
<!-- Community logo -->
|
||||||
|
<ds-comcol-page-logo *ngIf="logoData"
|
||||||
|
[logo]="logoData.payload | async"
|
||||||
|
[alternateText]="'Community Logo'">
|
||||||
|
</ds-comcol-page-logo>
|
||||||
|
<!-- Introductionary text -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(communityData.payload | async)?.introductoryText"
|
||||||
|
[hasInnerHtml]="true">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
<!-- News -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(communityData.payload | async)?.sidebarText"
|
||||||
|
[hasInnerHtml]="true"
|
||||||
|
[title]="'community.page.news'">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
<!-- Copyright -->
|
||||||
|
<ds-comcol-page-content
|
||||||
|
[content]="(communityData.payload | async)?.copyrightText"
|
||||||
|
[hasInnerHtml]="true">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
<ds-community-page-sub-collection-list></ds-community-page-sub-collection-list>
|
||||||
|
</div>
|
1
src/app/community-page/community-page.component.scss
Normal file
1
src/app/community-page/community-page.component.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import '../../styles/variables.scss';
|
41
src/app/community-page/community-page.component.ts
Normal file
41
src/app/community-page/community-page.component.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
|
import { Community } from "../core/shared/community.model";
|
||||||
|
import { Bitstream } from "../core/shared/bitstream.model";
|
||||||
|
import { RemoteData } from "../core/data/remote-data";
|
||||||
|
import { CommunityDataService } from "../core/data/community-data.service";
|
||||||
|
import { Subscription } from "rxjs/Subscription";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-community-page',
|
||||||
|
styleUrls: ['./community-page.component.css'],
|
||||||
|
templateUrl: './community-page.component.html',
|
||||||
|
})
|
||||||
|
export class CommunityPageComponent implements OnInit, OnDestroy {
|
||||||
|
communityData: RemoteData<Community>;
|
||||||
|
logoData: RemoteData<Bitstream>;
|
||||||
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private communityDataService: CommunityDataService,
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {
|
||||||
|
this.universalInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.route.params.subscribe((params: Params) => {
|
||||||
|
this.communityData = this.communityDataService.findById(params['id']);
|
||||||
|
this.subs.push(this.communityData.payload
|
||||||
|
.subscribe(community => this.logoData = community.logo));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
}
|
||||||
|
}
|
25
src/app/community-page/community-page.module.ts
Normal file
25
src/app/community-page/community-page.module.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterModule } from "@angular/router";
|
||||||
|
|
||||||
|
import { TranslateModule } from "@ngx-translate/core";
|
||||||
|
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
import { CommunityPageComponent } from './community-page.component';
|
||||||
|
import { CommunityPageSubCollectionListComponent } from './sub-collection-list/community-page-sub-collection-list.component';
|
||||||
|
import { CommunityPageRoutingModule } from './community-page-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommunityPageRoutingModule,
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule,
|
||||||
|
RouterModule,
|
||||||
|
SharedModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CommunityPageComponent,
|
||||||
|
CommunityPageSubCollectionListComponent,
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CommunityPageModule { }
|
@@ -0,0 +1,11 @@
|
|||||||
|
<div *ngIf="subCollections.hasSucceeded | async">
|
||||||
|
<h2>{{'community.sub-collection-list.head' | translate}}</h2>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let collection of (subCollections.payload | async)">
|
||||||
|
<p>
|
||||||
|
<span class="lead"><a [routerLink]="['/collections', collection.id]">{{collection.name}}</a></span><br>
|
||||||
|
<span class="text-muted">{{collection.shortDescription}}</span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
@@ -0,0 +1,28 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CollectionDataService } from "../../core/data/collection-data.service";
|
||||||
|
import { RemoteData } from "../../core/data/remote-data";
|
||||||
|
import { Collection } from "../../core/shared/collection.model";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-community-page-sub-collection-list',
|
||||||
|
styleUrls: ['./community-page-sub-collection-list.component.css'],
|
||||||
|
templateUrl: './community-page-sub-collection-list.component.html',
|
||||||
|
})
|
||||||
|
export class CommunityPageSubCollectionListComponent implements OnInit {
|
||||||
|
subCollections: RemoteData<Collection[]>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private cds: CollectionDataService
|
||||||
|
) {
|
||||||
|
this.universalInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.subCollections = this.cds.findAll();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { CacheableObject } from "../object-cache.reducer";
|
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 mapsToMetadataKey = Symbol("mapsTo");
|
||||||
const relationshipKey = Symbol("relationship");
|
const relationshipKey = Symbol("relationship");
|
||||||
@@ -16,7 +16,7 @@ export const getMapsTo = function(target: any) {
|
|||||||
return Reflect.getOwnMetadata(mapsToMetadataKey, target);
|
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) {
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
if (!target || !propertyKey) {
|
if (!target || !propertyKey) {
|
||||||
return;
|
return;
|
||||||
|
@@ -13,7 +13,8 @@ import { Observable } from "rxjs/Observable";
|
|||||||
import { RemoteData } from "../../data/remote-data";
|
import { RemoteData } from "../../data/remote-data";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { getMapsTo, getResourceType, getRelationships } from "./build-decorators";
|
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()
|
@Injectable()
|
||||||
export class RemoteDataBuildService {
|
export class RemoteDataBuildService {
|
||||||
@@ -29,37 +30,33 @@ export class RemoteDataBuildService {
|
|||||||
href: string,
|
href: string,
|
||||||
normalizedType: GenericConstructor<TNormalized>
|
normalizedType: GenericConstructor<TNormalized>
|
||||||
): RemoteData<TDomain> {
|
): RemoteData<TDomain> {
|
||||||
const requestObs = this.store.select<RequestEntry>('core', 'data', 'request', href);
|
const requestHrefObs = this.objectCache.getRequestHrefBySelfLink(href);
|
||||||
const responseCacheObs = this.responseCache.get(href);
|
|
||||||
|
|
||||||
const requestPending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.requestPending).distinctUntilChanged();
|
const requestObs = Observable.race(
|
||||||
|
this.store.select<RequestEntry>('core', 'data', 'request', href).filter(entry => hasValue(entry)),
|
||||||
|
requestHrefObs.flatMap(requestHref =>
|
||||||
|
this.store.select<RequestEntry>('core', 'data', 'request', requestHref)).filter(entry => hasValue(entry))
|
||||||
|
);
|
||||||
|
|
||||||
const responsePending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.responsePending).distinctUntilChanged();
|
const responseCacheObs = Observable.race(
|
||||||
|
this.responseCache.get(href).filter(entry => hasValue(entry)),
|
||||||
|
requestHrefObs.flatMap(requestHref => this.responseCache.get(requestHref)).filter(entry => hasValue(entry))
|
||||||
|
);
|
||||||
|
|
||||||
|
const requestPending = requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged();
|
||||||
|
|
||||||
|
const responsePending = requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged();
|
||||||
|
|
||||||
const isSuccessFul = responseCacheObs
|
const isSuccessFul = responseCacheObs
|
||||||
.map((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful).distinctUntilChanged();
|
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged();
|
||||||
|
|
||||||
const errorMessage = responseCacheObs
|
const errorMessage = responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => hasValue(entry) && !entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
||||||
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const payload =
|
const payload = this.objectCache.getBySelfLink<TNormalized>(href, normalizedType)
|
||||||
Observable.race(
|
.map((normalized: TNormalized) => {
|
||||||
this.objectCache.getBySelfLink<TNormalized>(href, normalizedType),
|
|
||||||
responseCacheObs
|
|
||||||
.filter((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful)
|
|
||||||
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
|
||||||
if (isNotEmpty(resourceUUIDs)) {
|
|
||||||
return this.objectCache.get(resourceUUIDs[0], normalizedType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Observable.of(undefined);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.distinctUntilChanged()
|
|
||||||
).map((normalized: TNormalized) => {
|
|
||||||
return this.build<TNormalized, TDomain>(normalized);
|
return this.build<TNormalized, TDomain>(normalized);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,23 +74,24 @@ export class RemoteDataBuildService {
|
|||||||
href: string,
|
href: string,
|
||||||
normalizedType: GenericConstructor<TNormalized>
|
normalizedType: GenericConstructor<TNormalized>
|
||||||
): RemoteData<TDomain[]> {
|
): RemoteData<TDomain[]> {
|
||||||
const requestObs = this.store.select<RequestEntry>('core', 'data', 'request', href);
|
const requestObs = this.store.select<RequestEntry>('core', 'data', 'request', href)
|
||||||
const responseCacheObs = this.responseCache.get(href);
|
.filter(entry => hasValue(entry));
|
||||||
|
const responseCacheObs = this.responseCache.get(href).filter(entry => hasValue(entry));
|
||||||
|
|
||||||
const requestPending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.requestPending).distinctUntilChanged();
|
const requestPending = requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged();
|
||||||
|
|
||||||
const responsePending = requestObs.map((entry: RequestEntry) => hasValue(entry) && entry.responsePending).distinctUntilChanged();
|
const responsePending = requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged();
|
||||||
|
|
||||||
const isSuccessFul = responseCacheObs
|
const isSuccessFul = responseCacheObs
|
||||||
.map((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful).distinctUntilChanged();
|
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged();
|
||||||
|
|
||||||
const errorMessage = responseCacheObs
|
const errorMessage = responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => hasValue(entry) && !entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
||||||
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
.map((entry: ResponseCacheEntry) => (<ErrorResponse> entry.response).errorMessage)
|
||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const payload = responseCacheObs
|
const payload = responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => hasValue(entry) && entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
||||||
.flatMap((resourceUUIDs: Array<string>) => {
|
.flatMap((resourceUUIDs: Array<string>) => {
|
||||||
return this.objectCache.getList(resourceUUIDs, normalizedType)
|
return this.objectCache.getList(resourceUUIDs, normalizedType)
|
||||||
@@ -124,13 +122,13 @@ export class RemoteDataBuildService {
|
|||||||
relationships.forEach((relationship: string) => {
|
relationships.forEach((relationship: string) => {
|
||||||
if (hasValue(normalized[relationship])) {
|
if (hasValue(normalized[relationship])) {
|
||||||
const resourceType = getResourceType(normalized, relationship);
|
const resourceType = getResourceType(normalized, relationship);
|
||||||
const resourceConstructor = NormalizedDSOFactory.getConstructor(resourceType);
|
const resourceConstructor = NormalizedObjectFactory.getConstructor(resourceType);
|
||||||
if (Array.isArray(normalized[relationship])) {
|
if (Array.isArray(normalized[relationship])) {
|
||||||
// without the setTimeout, the actions inside requestService.configure
|
// without the setTimeout, the actions inside requestService.configure
|
||||||
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
normalized[relationship].forEach((href: string) => {
|
normalized[relationship].forEach((href: string) => {
|
||||||
this.requestService.configure(href, resourceConstructor)
|
this.requestService.configure(new Request(href))
|
||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
@@ -145,7 +143,7 @@ export class RemoteDataBuildService {
|
|||||||
// without the setTimeout, the actions inside requestService.configure
|
// without the setTimeout, the actions inside requestService.configure
|
||||||
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
// are dispatched, but sometimes don't arrive. I'm unsure why atm.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.requestService.configure(normalized[relationship], resourceConstructor);
|
this.requestService.configure(new Request(normalized[relationship]));
|
||||||
},0);
|
},0);
|
||||||
|
|
||||||
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);
|
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization } from "cerialize";
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Bundle } from "../../shared/bundle.model";
|
import { Bundle } from "../../shared/bundle.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Bundle)
|
@mapsTo(Bundle)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -11,7 +11,7 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
|
|||||||
* The primary bitstream of this Bundle
|
* The primary bitstream of this Bundle
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBitstream)
|
@relationship(ResourceType.Bitstream)
|
||||||
primaryBitstream: string;
|
primaryBitstream: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +25,6 @@ export class NormalizedBundle extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBitstream)
|
@relationship(ResourceType.Bitstream)
|
||||||
bitstreams: Array<string>;
|
bitstreams: Array<string>;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Collection } from "../../shared/collection.model";
|
import { Collection } from "../../shared/collection.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Collection)
|
@mapsTo(Collection)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -18,7 +18,7 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
|
|||||||
* The Bitstream that represents the logo of this Collection
|
* The Bitstream that represents the logo of this Collection
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBitstream)
|
@relationship(ResourceType.Bitstream)
|
||||||
logo: string;
|
logo: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +32,7 @@ export class NormalizedCollection extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedItem)
|
@relationship(ResourceType.Item)
|
||||||
items: Array<string>;
|
items: Array<string>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize, inheritSerialization, autoserializeAs } from "cerialize"
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Community } from "../../shared/community.model";
|
import { Community } from "../../shared/community.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Community)
|
@mapsTo(Community)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -17,6 +17,8 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* The Bitstream that represents the logo of this Community
|
* The Bitstream that represents the logo of this Community
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
|
@relationship(ResourceType.Bitstream)
|
||||||
logo: string;
|
logo: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +32,7 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedCollection)
|
@relationship(ResourceType.Collection)
|
||||||
collections: Array<string>;
|
collections: Array<string>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
export enum NormalizedDSOType {
|
|
||||||
NormalizedBitstream,
|
|
||||||
NormalizedBundle,
|
|
||||||
NormalizedItem,
|
|
||||||
NormalizedCollection,
|
|
||||||
NormalizedCommunity
|
|
||||||
}
|
|
@@ -1,6 +1,7 @@
|
|||||||
import { autoserialize, autoserializeAs } from "cerialize";
|
import { autoserialize, autoserializeAs } from "cerialize";
|
||||||
import { CacheableObject } from "../object-cache.reducer";
|
import { CacheableObject } from "../object-cache.reducer";
|
||||||
import { Metadatum } from "../../shared/metadatum.model";
|
import { Metadatum } from "../../shared/metadatum.model";
|
||||||
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* 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, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
type: string;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
@@ -49,5 +50,6 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* The DSpaceObject that owns this DSpaceObject
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
owner: string;
|
owner: string;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import { inheritSerialization, autoserialize } from "cerialize";
|
|||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Item } from "../../shared/item.model";
|
import { Item } from "../../shared/item.model";
|
||||||
import { mapsTo, relationship } from "../builders/build-decorators";
|
import { mapsTo, relationship } from "../builders/build-decorators";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
@mapsTo(Item)
|
@mapsTo(Item)
|
||||||
@inheritSerialization(NormalizedDSpaceObject)
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
@@ -33,7 +33,7 @@ export class NormalizedItem extends NormalizedDSpaceObject {
|
|||||||
* An array of Collections that are direct parents of this Item
|
* An array of Collections that are direct parents of this Item
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedCollection)
|
@relationship(ResourceType.Collection)
|
||||||
parents: Array<string>;
|
parents: Array<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,6 +42,6 @@ export class NormalizedItem extends NormalizedDSpaceObject {
|
|||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
@relationship(NormalizedDSOType.NormalizedBundle)
|
@relationship(ResourceType.Bundle)
|
||||||
bundles: Array<string>;
|
bundles: Array<string>;
|
||||||
}
|
}
|
||||||
|
@@ -4,25 +4,25 @@ import { NormalizedBundle } from "./normalized-bundle.model";
|
|||||||
import { NormalizedItem } from "./normalized-item.model";
|
import { NormalizedItem } from "./normalized-item.model";
|
||||||
import { NormalizedCollection } from "./normalized-collection.model";
|
import { NormalizedCollection } from "./normalized-collection.model";
|
||||||
import { GenericConstructor } from "../../shared/generic-constructor";
|
import { GenericConstructor } from "../../shared/generic-constructor";
|
||||||
import { NormalizedDSOType } from "./normalized-dspace-object-type";
|
|
||||||
import { NormalizedCommunity } from "./normalized-community.model";
|
import { NormalizedCommunity } from "./normalized-community.model";
|
||||||
|
import { ResourceType } from "../../shared/resource-type";
|
||||||
|
|
||||||
export class NormalizedDSOFactory {
|
export class NormalizedObjectFactory {
|
||||||
public static getConstructor(type: NormalizedDSOType): GenericConstructor<NormalizedDSpaceObject> {
|
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedDSpaceObject> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NormalizedDSOType.NormalizedBitstream: {
|
case ResourceType.Bitstream: {
|
||||||
return NormalizedBitstream
|
return NormalizedBitstream
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedBundle: {
|
case ResourceType.Bundle: {
|
||||||
return NormalizedBundle
|
return NormalizedBundle
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedItem: {
|
case ResourceType.Item: {
|
||||||
return NormalizedItem
|
return NormalizedItem
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedCollection: {
|
case ResourceType.Collection: {
|
||||||
return NormalizedCollection
|
return NormalizedCollection
|
||||||
}
|
}
|
||||||
case NormalizedDSOType.NormalizedCommunity: {
|
case ResourceType.Community: {
|
||||||
return NormalizedCommunity
|
return NormalizedCommunity
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
9
src/app/core/cache/object-cache.actions.ts
vendored
9
src/app/core/cache/object-cache.actions.ts
vendored
@@ -20,6 +20,7 @@ export class AddToObjectCacheAction implements Action {
|
|||||||
objectToCache: CacheableObject;
|
objectToCache: CacheableObject;
|
||||||
timeAdded: number;
|
timeAdded: number;
|
||||||
msToLive: number;
|
msToLive: number;
|
||||||
|
requestHref: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,9 +32,13 @@ export class AddToObjectCacheAction implements Action {
|
|||||||
* the time it was added
|
* the time it was added
|
||||||
* @param msToLive
|
* @param msToLive
|
||||||
* the amount of milliseconds before it should expire
|
* the amount of milliseconds before it should expire
|
||||||
|
* @param requestHref
|
||||||
|
* The href of the request that resulted in this object
|
||||||
|
* This isn't necessarily the same as the object's self
|
||||||
|
* link, it could have been part of a list for example
|
||||||
*/
|
*/
|
||||||
constructor(objectToCache: CacheableObject, timeAdded: number, msToLive: number) {
|
constructor(objectToCache: CacheableObject, timeAdded: number, msToLive: number, requestHref: string) {
|
||||||
this.payload = { objectToCache, timeAdded, msToLive };
|
this.payload = { objectToCache, timeAdded, msToLive, requestHref };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
src/app/core/cache/object-cache.reducer.spec.ts
vendored
15
src/app/core/cache/object-cache.reducer.spec.ts
vendored
@@ -24,7 +24,8 @@ describe("objectCacheReducer", () => {
|
|||||||
foo: "bar"
|
foo: "bar"
|
||||||
},
|
},
|
||||||
timeAdded: new Date().getTime(),
|
timeAdded: new Date().getTime(),
|
||||||
msToLive: 900000
|
msToLive: 900000,
|
||||||
|
requestHref: "https://rest.api/endpoint/uuid1"
|
||||||
},
|
},
|
||||||
[uuid2]: {
|
[uuid2]: {
|
||||||
data: {
|
data: {
|
||||||
@@ -32,7 +33,8 @@ describe("objectCacheReducer", () => {
|
|||||||
foo: "baz"
|
foo: "baz"
|
||||||
},
|
},
|
||||||
timeAdded: new Date().getTime(),
|
timeAdded: new Date().getTime(),
|
||||||
msToLive: 900000
|
msToLive: 900000,
|
||||||
|
requestHref: "https://rest.api/endpoint/uuid2"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
deepFreeze(testState);
|
deepFreeze(testState);
|
||||||
@@ -56,7 +58,8 @@ describe("objectCacheReducer", () => {
|
|||||||
const objectToCache = {uuid: uuid1};
|
const objectToCache = {uuid: uuid1};
|
||||||
const timeAdded = new Date().getTime();
|
const timeAdded = new Date().getTime();
|
||||||
const msToLive = 900000;
|
const msToLive = 900000;
|
||||||
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive);
|
const requestHref = "https://rest.api/endpoint/uuid1";
|
||||||
|
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref);
|
||||||
const newState = objectCacheReducer(state, action);
|
const newState = objectCacheReducer(state, action);
|
||||||
|
|
||||||
expect(newState[uuid1].data).toEqual(objectToCache);
|
expect(newState[uuid1].data).toEqual(objectToCache);
|
||||||
@@ -68,7 +71,8 @@ describe("objectCacheReducer", () => {
|
|||||||
const objectToCache = {uuid: uuid1, foo: "baz", somethingElse: true};
|
const objectToCache = {uuid: uuid1, foo: "baz", somethingElse: true};
|
||||||
const timeAdded = new Date().getTime();
|
const timeAdded = new Date().getTime();
|
||||||
const msToLive = 900000;
|
const msToLive = 900000;
|
||||||
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive);
|
const requestHref = "https://rest.api/endpoint/uuid1";
|
||||||
|
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref);
|
||||||
const newState = objectCacheReducer(testState, action);
|
const newState = objectCacheReducer(testState, action);
|
||||||
|
|
||||||
expect(newState[uuid1].data['foo']).toBe("baz");
|
expect(newState[uuid1].data['foo']).toBe("baz");
|
||||||
@@ -80,7 +84,8 @@ describe("objectCacheReducer", () => {
|
|||||||
const objectToCache = {uuid: uuid1};
|
const objectToCache = {uuid: uuid1};
|
||||||
const timeAdded = new Date().getTime();
|
const timeAdded = new Date().getTime();
|
||||||
const msToLive = 900000;
|
const msToLive = 900000;
|
||||||
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive);
|
const requestHref = "https://rest.api/endpoint/uuid1";
|
||||||
|
const action = new AddToObjectCacheAction(objectToCache, timeAdded, msToLive, requestHref);
|
||||||
deepFreeze(state);
|
deepFreeze(state);
|
||||||
|
|
||||||
objectCacheReducer(state, action);
|
objectCacheReducer(state, action);
|
||||||
|
4
src/app/core/cache/object-cache.reducer.ts
vendored
4
src/app/core/cache/object-cache.reducer.ts
vendored
@@ -22,6 +22,7 @@ export class ObjectCacheEntry implements CacheEntry {
|
|||||||
data: CacheableObject;
|
data: CacheableObject;
|
||||||
timeAdded: number;
|
timeAdded: number;
|
||||||
msToLive: number;
|
msToLive: number;
|
||||||
|
requestHref: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,7 +84,8 @@ function addToObjectCache(state: ObjectCacheState, action: AddToObjectCacheActio
|
|||||||
[action.payload.objectToCache.uuid]: {
|
[action.payload.objectToCache.uuid]: {
|
||||||
data: action.payload.objectToCache,
|
data: action.payload.objectToCache,
|
||||||
timeAdded: action.payload.timeAdded,
|
timeAdded: action.payload.timeAdded,
|
||||||
msToLive: action.payload.msToLive
|
msToLive: action.payload.msToLive,
|
||||||
|
requestHref: action.payload.requestHref
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
29
src/app/core/cache/object-cache.service.ts
vendored
29
src/app/core/cache/object-cache.service.ts
vendored
@@ -22,9 +22,13 @@ export class ObjectCacheService {
|
|||||||
* The object to add
|
* The object to add
|
||||||
* @param msToLive
|
* @param msToLive
|
||||||
* The number of milliseconds it should be cached for
|
* The number of milliseconds it should be cached for
|
||||||
|
* @param requestHref
|
||||||
|
* The href of the request that resulted in this object
|
||||||
|
* This isn't necessarily the same as the object's self
|
||||||
|
* link, it could have been part of a list for example
|
||||||
*/
|
*/
|
||||||
add(objectToCache: CacheableObject, msToLive: number): void {
|
add(objectToCache: CacheableObject, msToLive: number, requestHref: string): void {
|
||||||
this.store.dispatch(new AddToObjectCacheAction(objectToCache, new Date().getTime(), msToLive));
|
this.store.dispatch(new AddToObjectCacheAction(objectToCache, new Date().getTime(), msToLive, requestHref));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,9 +58,7 @@ export class ObjectCacheService {
|
|||||||
* An observable of the requested object
|
* An observable of the requested object
|
||||||
*/
|
*/
|
||||||
get<T extends CacheableObject>(uuid: string, type: GenericConstructor<T>): Observable<T> {
|
get<T extends CacheableObject>(uuid: string, type: GenericConstructor<T>): Observable<T> {
|
||||||
return this.store.select<ObjectCacheEntry>('core', 'cache', 'object', uuid)
|
return this.getEntry(uuid)
|
||||||
.filter(entry => this.isValid(entry))
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.map((entry: ObjectCacheEntry) => <T> Object.assign(new type(), entry.data));
|
.map((entry: ObjectCacheEntry) => <T> Object.assign(new type(), entry.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +67,23 @@ export class ObjectCacheService {
|
|||||||
.flatMap((uuid: string) => this.get(uuid, type))
|
.flatMap((uuid: string) => this.get(uuid, type))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEntry(uuid: string): Observable<ObjectCacheEntry> {
|
||||||
|
return this.store.select<ObjectCacheEntry>('core', 'cache', 'object', uuid)
|
||||||
|
.filter(entry => this.isValid(entry))
|
||||||
|
.distinctUntilChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequestHref(uuid: string): Observable<string> {
|
||||||
|
return this.getEntry(uuid)
|
||||||
|
.map((entry: ObjectCacheEntry) => entry.requestHref)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequestHrefBySelfLink(self: string): Observable<string> {
|
||||||
|
return this.store.select<string>('core', 'index', 'href', self)
|
||||||
|
.flatMap((uuid: string) => this.getRequestHref(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an observable for an array of objects of the same type
|
* Get an observable for an array of objects of the same type
|
||||||
* with the specified UUIDs
|
* with the specified UUIDs
|
||||||
|
6
src/app/core/cache/response-cache.models.ts
vendored
6
src/app/core/cache/response-cache.models.ts
vendored
@@ -9,8 +9,12 @@ export class SuccessResponse extends Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ErrorResponse extends Response {
|
export class ErrorResponse extends Response {
|
||||||
constructor(public errorMessage: string) {
|
errorMessage: string;
|
||||||
|
|
||||||
|
constructor(error: Error) {
|
||||||
super(false);
|
super(false);
|
||||||
|
console.error(error);
|
||||||
|
this.errorMessage = error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,11 +33,8 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
|
|
||||||
findAll(scopeID?: string): RemoteData<Array<TDomain>> {
|
findAll(scopeID?: string): RemoteData<Array<TDomain>> {
|
||||||
const href = this.getFindAllHref(scopeID);
|
const href = this.getFindAllHref(scopeID);
|
||||||
if (!this.responseCache.has(href) && !this.requestService.isPending(href)) {
|
const request = new FindAllRequest(href, scopeID);
|
||||||
const request = new FindAllRequest(href, this.normalizedResourceType, scopeID);
|
this.requestService.configure(request);
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildList<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildList<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildList(href);
|
// return this.rdbService.buildList(href);
|
||||||
}
|
}
|
||||||
@@ -48,21 +45,14 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
|
|
||||||
findById(id: string): RemoteData<TDomain> {
|
findById(id: string): RemoteData<TDomain> {
|
||||||
const href = this.getFindByIDHref(id);
|
const href = this.getFindByIDHref(id);
|
||||||
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
const request = new FindByIDRequest(href, id);
|
||||||
const request = new FindByIDRequest(href, this.normalizedResourceType, id);
|
this.requestService.configure(request);
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildSingle(href);
|
// return this.rdbService.buildSingle(href);
|
||||||
}
|
}
|
||||||
|
|
||||||
findByHref(href: string): RemoteData<TDomain> {
|
findByHref(href: string): RemoteData<TDomain> {
|
||||||
if (!this.objectCache.hasBySelfLink(href) && !this.requestService.isPending(href)) {
|
this.requestService.configure(new Request(href));
|
||||||
const request = new Request(href, this.normalizedResourceType);
|
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
|
||||||
}
|
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
||||||
// return this.rdbService.buildSingle(href));
|
// return this.rdbService.buildSingle(href));
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ import { DSpaceRESTv2Serializer } from "../dspace-rest-v2/dspace-rest-v2.seriali
|
|||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { Response, SuccessResponse, ErrorResponse } from "../cache/response-cache.models";
|
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 { GlobalConfig, GLOBAL_CONFIG } from "../../../config";
|
||||||
import { RequestState, RequestEntry } from "./request.reducer";
|
import { RequestState, RequestEntry } from "./request.reducer";
|
||||||
import {
|
import {
|
||||||
@@ -17,6 +17,12 @@ import {
|
|||||||
} from "./request.actions";
|
} from "./request.actions";
|
||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { RequestService } from "./request.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()
|
@Injectable()
|
||||||
export class RequestEffects {
|
export class RequestEffects {
|
||||||
@@ -38,34 +44,91 @@ export class RequestEffects {
|
|||||||
.take(1);
|
.take(1);
|
||||||
})
|
})
|
||||||
.flatMap((entry: RequestEntry) => {
|
.flatMap((entry: RequestEntry) => {
|
||||||
const [ifArray, ifNotArray] = this.restApi.get(entry.request.href)
|
return this.restApi.get(entry.request.href)
|
||||||
.share() // share ensures restApi.get() doesn't get called twice when the partitions are used below
|
.map((data: DSpaceRESTV2Response) => this.processEmbedded(data._embedded, entry.request.href))
|
||||||
.partition((data: DSpaceRESTV2Response) => Array.isArray(data._embedded));
|
.map((ids: Array<string>) => new SuccessResponse(ids))
|
||||||
|
|
||||||
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))
|
|
||||||
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
||||||
.map((response: Response) => new RequestCompleteAction(entry.request.href))
|
.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))
|
.do((response: Response) => this.responseCache.add(entry.request.href, response, this.EnvConfig.cache.msToLive))
|
||||||
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
|
.map((response: Response) => new RequestCompleteAction(entry.request.href)));
|
||||||
});
|
});
|
||||||
|
|
||||||
protected addToObjectCache(co: CacheableObject): void {
|
protected processEmbedded(_embedded: any, requestHref): Array<string> {
|
||||||
|
|
||||||
|
if (isNotEmpty(_embedded)) {
|
||||||
|
if (isObjectLevel(_embedded)) {
|
||||||
|
return this.deserializeAndCache(_embedded, requestHref);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let uuids = [];
|
||||||
|
Object.keys(_embedded)
|
||||||
|
.filter(property => _embedded.hasOwnProperty(property))
|
||||||
|
.forEach(property => {
|
||||||
|
uuids = [...uuids, ...this.deserializeAndCache(_embedded[property], requestHref)];
|
||||||
|
});
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected deserializeAndCache(obj, requestHref): 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, requestHref);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const normalizedObjArr = serializer.deserializeArray(obj);
|
||||||
|
normalizedObjArr.forEach(t => this.addToObjectCache(t, requestHref));
|
||||||
|
return normalizedObjArr.map(t => t.uuid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isNotEmpty(obj._embedded)) {
|
||||||
|
this.processEmbedded(obj._embedded, requestHref);
|
||||||
|
}
|
||||||
|
const normalizedObj = serializer.deserialize(obj);
|
||||||
|
this.addToObjectCache(normalizedObj, requestHref);
|
||||||
|
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, requestHref: string): void {
|
||||||
if (hasNoValue(co) || hasNoValue(co.uuid)) {
|
if (hasNoValue(co) || hasNoValue(co.uuid)) {
|
||||||
throw new Error('The server returned an invalid object');
|
throw new Error('The server returned an invalid object');
|
||||||
}
|
}
|
||||||
this.objectCache.add(co, this.EnvConfig.cache.msToLive);
|
this.objectCache.add(co, this.EnvConfig.cache.msToLive, requestHref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,28 +5,25 @@ import { GenericConstructor } from "../shared/generic-constructor";
|
|||||||
export class Request<T> {
|
export class Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
public href: string,
|
public href: string,
|
||||||
public resourceType: GenericConstructor<T>
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FindByIDRequest<T> extends Request<T> {
|
export class FindByIDRequest<T> extends Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
href: string,
|
href: string,
|
||||||
resourceType: GenericConstructor<T>,
|
|
||||||
public resourceID: string
|
public resourceID: string
|
||||||
) {
|
) {
|
||||||
super(href, resourceType);
|
super(href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FindAllRequest<T> extends Request<T> {
|
export class FindAllRequest<T> extends Request<T> {
|
||||||
constructor(
|
constructor(
|
||||||
href: string,
|
href: string,
|
||||||
resourceType: GenericConstructor<T>,
|
|
||||||
public scopeID?: string,
|
public scopeID?: string,
|
||||||
public paginationOptions?: PaginationOptions,
|
public paginationOptions?: PaginationOptions,
|
||||||
public sortOptions?: SortOptions
|
public sortOptions?: SortOptions
|
||||||
) {
|
) {
|
||||||
super(href, resourceType);
|
super(href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,9 @@ import { RequestConfigureAction, RequestExecuteAction } from "./request.actions"
|
|||||||
import { ResponseCacheService } from "../cache/response-cache.service";
|
import { ResponseCacheService } from "../cache/response-cache.service";
|
||||||
import { ObjectCacheService } from "../cache/object-cache.service";
|
import { ObjectCacheService } from "../cache/object-cache.service";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
import { ResponseCacheEntry } from "../cache/response-cache.reducer";
|
||||||
|
import { request } from "http";
|
||||||
|
import { SuccessResponse } from "../cache/response-cache.models";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RequestService {
|
export class RequestService {
|
||||||
@@ -35,14 +37,25 @@ export class RequestService {
|
|||||||
return this.store.select<RequestEntry>('core', 'data', 'request', href);
|
return this.store.select<RequestEntry>('core', 'data', 'request', href);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<T extends CacheableObject>(href: string, normalizedType: GenericConstructor<T>): void {
|
configure<T extends CacheableObject>(request: Request<T>): void {
|
||||||
const isCached = this.objectCache.hasBySelfLink(href);
|
let isCached = this.objectCache.hasBySelfLink(request.href);
|
||||||
const isPending = this.isPending(href);
|
|
||||||
|
if (!isCached && this.responseCache.has(request.href)) {
|
||||||
|
//if it isn't cached it may be a list endpoint, if so verify
|
||||||
|
//every object included in the response is still cached
|
||||||
|
this.responseCache.get(request.href)
|
||||||
|
.take(1)
|
||||||
|
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => (<SuccessResponse> entry.response).resourceUUIDs)
|
||||||
|
.map((resourceUUIDs: Array<string>) => resourceUUIDs.every(uuid => this.objectCache.has(uuid)))
|
||||||
|
.subscribe(c => isCached = c);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPending = this.isPending(request.href);
|
||||||
|
|
||||||
if (!(isCached || isPending)) {
|
if (!(isCached || isPending)) {
|
||||||
const request = new Request(href, normalizedType);
|
|
||||||
this.store.dispatch(new RequestConfigureAction(request));
|
this.store.dispatch(new RequestConfigureAction(request));
|
||||||
this.store.dispatch(new RequestExecuteAction(href));
|
this.store.dispatch(new RequestExecuteAction(request.href));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -84,14 +84,10 @@ describe("DSpaceRESTv2Serializer", () => {
|
|||||||
|
|
||||||
it("should turn a valid document describing a single entity in to a valid model", () => {
|
it("should turn a valid document describing a single entity in to a valid model", () => {
|
||||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||||
const doc = {
|
const model = serializer.deserialize(testResponses[0]);
|
||||||
"_embedded": testResponses[0],
|
|
||||||
};
|
|
||||||
|
|
||||||
const model = serializer.deserialize(doc);
|
expect(model.id).toBe(testResponses[0].id);
|
||||||
|
expect(model.name).toBe(testResponses[0].name);
|
||||||
expect(model.id).toBe(doc._embedded.id);
|
|
||||||
expect(model.name).toBe(doc._embedded.name);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO cant implement/test this yet - depends on how relationships
|
//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", () => {
|
it("should throw an error when dealing with a document describing an array", () => {
|
||||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||||
const doc = {
|
|
||||||
"_embedded": testResponses
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
serializer.deserialize(doc);
|
serializer.deserialize(testResponses);
|
||||||
}).toThrow();
|
}).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ import { Serializer } from "../serializer";
|
|||||||
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
|
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
|
||||||
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
|
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
|
||||||
import { GenericConstructor } from "../shared/generic-constructor";
|
import { GenericConstructor } from "../shared/generic-constructor";
|
||||||
|
import { hasNoValue, hasValue } from "../../shared/empty.util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Serializer turns responses from v2 of DSpace's REST API
|
* 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
|
* @param response An object returned by the backend
|
||||||
* @returns a model of type T
|
* @returns a model of type T
|
||||||
*/
|
*/
|
||||||
deserialize(response: DSpaceRESTV2Response): T {
|
deserialize(response: any): T {
|
||||||
// TODO enable validation, once rest data stabilizes
|
// TODO enable validation, once rest data stabilizes
|
||||||
// new DSpaceRESTv2Validator(response).validate();
|
// new DSpaceRESTv2Validator(response).validate();
|
||||||
if (Array.isArray(response._embedded)) {
|
if (Array.isArray(response)) {
|
||||||
throw new Error('Expected a single model, use deserializeArray() instead');
|
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);
|
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
|
* @param response An object returned by the backend
|
||||||
* @returns an array of models of type T
|
* @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
|
//TODO enable validation, once rest data stabilizes
|
||||||
// new DSpaceRESTv2Validator(response).validate();
|
// new DSpaceRESTv2Validator(response).validate();
|
||||||
if (!Array.isArray(response._embedded)) {
|
if (!Array.isArray(response)) {
|
||||||
throw new Error('Expected an Array, use deserialize() instead');
|
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));
|
return Object.assign({}, resource, this.normalizeLinks(resource._links));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ import { Metadatum } from "./metadatum.model"
|
|||||||
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
import { RemoteData } from "../data/remote-data";
|
import { RemoteData } from "../data/remote-data";
|
||||||
|
import { ResourceType } from "./resource-type";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* 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, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
|
11
src/app/core/shared/resource-type.ts
Normal file
11
src/app/core/shared/resource-type.ts
Normal 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"
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
<div *ngIf="content" class="content-with-optional-title">
|
||||||
|
<h2 *ngIf="title">{{ title | translate }}</h2>
|
||||||
|
<div *ngIf="hasInnerHtml" [innerHtml]="content"></div>
|
||||||
|
<div *ngIf="!hasInnerHtml">{{content}}</div>
|
||||||
|
</div>
|
@@ -0,0 +1,37 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component renders any content inside of this component.
|
||||||
|
* If there is a title set it will render the title.
|
||||||
|
* If hasInnerHtml is true the content will be handled as html.
|
||||||
|
* To see how it is used see collection-page or community-page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-comcol-page-content',
|
||||||
|
styleUrls: ['./comcol-page-content.component.css'],
|
||||||
|
templateUrl: './comcol-page-content.component.html'
|
||||||
|
})
|
||||||
|
export class ComcolPageContentComponent {
|
||||||
|
|
||||||
|
// Optional title
|
||||||
|
@Input() title: string;
|
||||||
|
|
||||||
|
// The content to render. Might be html
|
||||||
|
@Input() content: string;
|
||||||
|
|
||||||
|
// flag whether the content contains html syntax or not
|
||||||
|
@Input() hasInnerHtml: boolean;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-comcol-page-header',
|
||||||
|
styleUrls: ['./comcol-page-header.component.css'],
|
||||||
|
templateUrl: './comcol-page-header.component.html',
|
||||||
|
})
|
||||||
|
export class ComcolPageHeaderComponent {
|
||||||
|
@Input() name: String;
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div *ngIf="logo" class="dso-logo">
|
||||||
|
<img [src]="logo.url" class="img-responsive" [attr.alt]="alternateText ? alternateText : null" />
|
||||||
|
</div>
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
import { Bitstream } from "../../core/shared/bitstream.model";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-comcol-page-logo',
|
||||||
|
styleUrls: ['./comcol-page-logo.component.css'],
|
||||||
|
templateUrl: './comcol-page-logo.component.html',
|
||||||
|
})
|
||||||
|
export class ComcolPageLogoComponent {
|
||||||
|
@Input() logo: Bitstream;
|
||||||
|
|
||||||
|
@Input() alternateText: string;
|
||||||
|
}
|
@@ -247,12 +247,12 @@ describe('Pagination component', () => {
|
|||||||
|
|
||||||
changePage(testFixture, 3);
|
changePage(testFixture, 3);
|
||||||
tick();
|
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);
|
expect(paginationComponent.currentPage).toEqual(3);
|
||||||
|
|
||||||
changePageSize(testFixture, '20');
|
changePageSize(testFixture, '20');
|
||||||
tick();
|
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);
|
expect(paginationComponent.pageSize).toEqual(20);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@@ -58,6 +58,11 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
public currentPage = 1;
|
public currentPage = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current URL query parameters
|
||||||
|
*/
|
||||||
|
public currentQueryParams = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An observable of HostWindowState type
|
* An observable of HostWindowState type
|
||||||
*/
|
*/
|
||||||
@@ -121,14 +126,15 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
this.pageSize = this.paginationOptions.pageSize;
|
this.pageSize = this.paginationOptions.pageSize;
|
||||||
this.pageSizeOptions = this.paginationOptions.pageSizeOptions;
|
this.pageSizeOptions = this.paginationOptions.pageSizeOptions;
|
||||||
|
|
||||||
this.routeSubscription = this.route.params
|
this.routeSubscription = this.route.queryParams
|
||||||
.map(params => params)
|
.map(queryParams => queryParams)
|
||||||
.subscribe(params => {
|
.subscribe(queryParams => {
|
||||||
if(this.id == params['pageId']
|
this.currentQueryParams = queryParams;
|
||||||
&& (this.paginationOptions.currentPage != params['page']
|
if(this.id == queryParams['pageId']
|
||||||
|| this.paginationOptions.pageSize != params['pageSize'])
|
&& (this.paginationOptions.currentPage != queryParams['page']
|
||||||
|
|| this.paginationOptions.pageSize != queryParams['pageSize'])
|
||||||
) {
|
) {
|
||||||
this.validateParams(params['page'], params['pageSize']);
|
this.validateParams(queryParams['page'], queryParams['pageSize']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.setShowingDetail();
|
this.setShowingDetail();
|
||||||
@@ -162,7 +168,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
* The page being navigated to.
|
* The page being navigated to.
|
||||||
*/
|
*/
|
||||||
public doPageChange(page: number) {
|
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.currentPage = page;
|
||||||
this.setShowingDetail();
|
this.setShowingDetail();
|
||||||
this.pageChange.emit(page);
|
this.pageChange.emit(page);
|
||||||
@@ -175,7 +181,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
* The new page size.
|
* The new page size.
|
||||||
*/
|
*/
|
||||||
public setPageSize(pageSize: number) {
|
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.pageSize = pageSize;
|
||||||
this.setShowingDetail();
|
this.setShowingDetail();
|
||||||
this.pageSizeChange.emit(pageSize);
|
this.pageSizeChange.emit(pageSize);
|
||||||
|
@@ -14,6 +14,9 @@ import { ThumbnailComponent } from "../thumbnail/thumbnail.component";
|
|||||||
import { SafeUrlPipe } from "./utils/safe-url-pipe";
|
import { SafeUrlPipe } from "./utils/safe-url-pipe";
|
||||||
import { HostWindowService } from "./host-window.service";
|
import { HostWindowService } from "./host-window.service";
|
||||||
import { NativeWindowFactory, NativeWindowService } from "./window.service";
|
import { NativeWindowFactory, NativeWindowService } from "./window.service";
|
||||||
|
import { ComcolPageContentComponent } from "./comcol-page-content/comcol-page-content.component";
|
||||||
|
import { ComcolPageHeaderComponent } from "./comcol-page-header/comcol-page-header.component";
|
||||||
|
import { ComcolPageLogoComponent } from "./comcol-page-logo/comcol-page-logo.component";
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -35,7 +38,10 @@ const PIPES = [
|
|||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
// put shared components here
|
// put shared components here
|
||||||
PaginationComponent,
|
PaginationComponent,
|
||||||
ThumbnailComponent
|
ThumbnailComponent,
|
||||||
|
ComcolPageContentComponent,
|
||||||
|
ComcolPageHeaderComponent,
|
||||||
|
ComcolPageLogoComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
|
@@ -4,7 +4,6 @@ import { BehaviorSubject } from "rxjs";
|
|||||||
export class RouterStub {
|
export class RouterStub {
|
||||||
//noinspection TypeScriptUnresolvedFunction
|
//noinspection TypeScriptUnresolvedFunction
|
||||||
navigate = jasmine.createSpy('navigate');
|
navigate = jasmine.createSpy('navigate');
|
||||||
//navigate1: jasmine.createSpy('navigate');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActivatedRouteStub {
|
export class ActivatedRouteStub {
|
||||||
@@ -12,6 +11,7 @@ export class ActivatedRouteStub {
|
|||||||
// ActivatedRoute.params is Observable
|
// ActivatedRoute.params is Observable
|
||||||
private subject = new BehaviorSubject(this.testParams);
|
private subject = new BehaviorSubject(this.testParams);
|
||||||
params = this.subject.asObservable();
|
params = this.subject.asObservable();
|
||||||
|
queryParams = this.subject.asObservable();
|
||||||
|
|
||||||
constructor(params?: Params) {
|
constructor(params?: Params) {
|
||||||
if (params) {
|
if (params) {
|
||||||
|
@@ -82,7 +82,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.community_id;
|
let id = req.params.community_id;
|
||||||
try {
|
try {
|
||||||
req.community_id = id;
|
req.community_id = id;
|
||||||
req.community = COMMUNITIES.find((community) => {
|
req.community = COMMUNITIES["communities"].find((community) => {
|
||||||
return community.id === id;
|
return community.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -143,7 +143,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.collection_id;
|
let id = req.params.collection_id;
|
||||||
try {
|
try {
|
||||||
req.collection_id = id;
|
req.collection_id = id;
|
||||||
req.collection = COLLECTIONS.find((collection) => {
|
req.collection = COLLECTIONS["collections"].find((collection) => {
|
||||||
return collection.id === id;
|
return collection.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -205,7 +205,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.item_id;
|
let id = req.params.item_id;
|
||||||
try {
|
try {
|
||||||
req.item_id = id;
|
req.item_id = id;
|
||||||
req.item = ITEMS.find((item) => {
|
req.item = ITEMS["items"].find((item) => {
|
||||||
return item.id === id;
|
return item.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -250,7 +250,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.bundle_id;
|
let id = req.params.bundle_id;
|
||||||
try {
|
try {
|
||||||
req.bundle_id = id;
|
req.bundle_id = id;
|
||||||
req.bundle = BUNDLES.find((bundle) => {
|
req.bundle = BUNDLES["bundles"].find((bundle) => {
|
||||||
return bundle.id === id;
|
return bundle.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -280,7 +280,7 @@ export function createMockApi() {
|
|||||||
let id = req.params.bitstream_id;
|
let id = req.params.bitstream_id;
|
||||||
try {
|
try {
|
||||||
req.bitstream_id = id;
|
req.bitstream_id = id;
|
||||||
req.bitstream = BITSTREAMS.find((bitstream) => {
|
req.bitstream = BITSTREAMS["bitstreams"].find((bitstream) => {
|
||||||
return bitstream.id === id;
|
return bitstream.id === id;
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const BITSTREAMS = [
|
export const BITSTREAMS = {
|
||||||
|
"bitstreams": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/bitstreams/3678" },
|
"self": { "href": "/bitstreams/3678" },
|
||||||
@@ -51,6 +52,7 @@ export const BITSTREAMS = [
|
|||||||
},
|
},
|
||||||
"id": "8934",
|
"id": "8934",
|
||||||
"uuid": "ba7d24f2-8fc7-4b8e-b7b6-6c32be1c12a6",
|
"uuid": "ba7d24f2-8fc7-4b8e-b7b6-6c32be1c12a6",
|
||||||
|
"type": "bitstream",
|
||||||
"name": "license.txt",
|
"name": "license.txt",
|
||||||
"size": 41183,
|
"size": 41183,
|
||||||
"checksum": {
|
"checksum": {
|
||||||
@@ -77,4 +79,5 @@ export const BITSTREAMS = [
|
|||||||
"format": "PNG",
|
"format": "PNG",
|
||||||
"mimetype": "image/png"
|
"mimetype": "image/png"
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const BUNDLES = [
|
export const BUNDLES = {
|
||||||
|
"bundles": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/bundles/2355" },
|
"self": { "href": "/bundles/2355" },
|
||||||
@@ -50,9 +51,11 @@ export const BUNDLES = [
|
|||||||
},
|
},
|
||||||
"id": "8475",
|
"id": "8475",
|
||||||
"uuid": "99f78e5e-3677-43b0-aaef-cddaa1a49092",
|
"uuid": "99f78e5e-3677-43b0-aaef-cddaa1a49092",
|
||||||
|
"type": "bundle",
|
||||||
"name": "LICENSE",
|
"name": "LICENSE",
|
||||||
"metadata": [
|
"metadata": [
|
||||||
{ "key": "dc.title", "value": "LICENSE", "language": "en" }
|
{ "key": "dc.title", "value": "LICENSE", "language": "en" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const COLLECTIONS = [
|
export const COLLECTIONS = {
|
||||||
|
"collections": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": { "href": "/collections/5179" },
|
"self": { "href": "/collections/5179" },
|
||||||
@@ -72,4 +73,5 @@ export const COLLECTIONS = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const COMMUNITIES = [
|
export const COMMUNITIES = {
|
||||||
|
"communities": [
|
||||||
{
|
{
|
||||||
"name": "Community 1",
|
"name": "Community 1",
|
||||||
"handle": "10673/1",
|
"handle": "10673/1",
|
||||||
@@ -34,11 +35,12 @@ export const COMMUNITIES = [
|
|||||||
],
|
],
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
"href": "http://dspace7.4science.it/dspace-spring-rest/api/core/community/9076bd16-e69a-48d6-9e41-0238cb40d863"
|
"href": "/communities/6631"
|
||||||
},
|
},
|
||||||
"collections": [
|
"collections": [
|
||||||
{ "href": "/collections/5179" }
|
{ "href": "/collections/5179" }
|
||||||
]
|
],
|
||||||
|
"logo": { "href": "/bitstreams/4688" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -76,11 +78,12 @@ export const COMMUNITIES = [
|
|||||||
],
|
],
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
"href": "http://dspace7.4science.it/dspace-spring-rest/api/core/community/9076bd16-e69a-48d6-9e41-0238cb40d863"
|
"href": "/communities/2365"
|
||||||
},
|
},
|
||||||
"collections": [
|
"collections": [
|
||||||
{ "href": "/collections/6547" }
|
{ "href": "/collections/6547" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const ITEMS = [
|
export const ITEMS = {
|
||||||
|
"items": [
|
||||||
{
|
{
|
||||||
"_links": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
@@ -16,12 +17,9 @@ export const ITEMS = [
|
|||||||
{
|
{
|
||||||
"href": "/bundles/2355"
|
"href": "/bundles/2355"
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
"href": "/bundles/5687"
|
// "href": "/bundles/5687"
|
||||||
},
|
// }
|
||||||
{
|
|
||||||
"href": "/bundles/8475"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": "8871",
|
"id": "8871",
|
||||||
@@ -93,8 +91,95 @@ export const ITEMS = [
|
|||||||
"value": "(not specified)",
|
"value": "(not specified)",
|
||||||
"language": "en"
|
"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": {
|
"_links": {
|
||||||
"self": {
|
"self": {
|
||||||
@@ -112,9 +197,9 @@ export const ITEMS = [
|
|||||||
{
|
{
|
||||||
"href": "/bundles/2355"
|
"href": "/bundles/2355"
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
"href": "/bundles/5687"
|
// "href": "/bundles/5687"
|
||||||
}
|
// }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": "9978",
|
"id": "9978",
|
||||||
@@ -166,6 +251,84 @@ export const ITEMS = [
|
|||||||
"value": "(not specified)",
|
"value": "(not specified)",
|
||||||
"language": "en"
|
"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
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
export const METADATA = [
|
export const METADATA = {
|
||||||
|
"metadata": [
|
||||||
{
|
{
|
||||||
"type": "metadata",
|
"type": "metadata",
|
||||||
"id": "d58a3098-b390-4cd6-8f52-b088b3daa637",
|
"id": "d58a3098-b390-4cd6-8f52-b088b3daa637",
|
||||||
@@ -179,4 +180,5 @@ export const METADATA = [
|
|||||||
"language": "en"
|
"language": "en"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@@ -10,5 +10,5 @@
|
|||||||
* ];
|
* ];
|
||||||
**/
|
**/
|
||||||
export const routes: string[] = [
|
export const routes: string[] = [
|
||||||
'home', 'items/:id' , 'collections/:id', '**'
|
'home', 'items/:id' , 'collections/:id', 'communities/:id', '**'
|
||||||
];
|
];
|
||||||
|
Reference in New Issue
Block a user