55946: Intermediate commit

This commit is contained in:
Kristof De Langhe
2018-10-09 14:09:56 +02:00
parent 3a809cc671
commit 6bc4d061f1
10 changed files with 208 additions and 9 deletions

View File

@@ -5,11 +5,13 @@ import { EditItemPageRoutingModule } from './edit-item-page.routing.module';
import { EditItemPageComponent } from './edit-item-page.component';
import { ItemCollectionMapperComponent } from './item-collection-mapper/item-collection-mapper.component';
import { ItemStatusComponent } from './item-status/item-status.component';
import { SearchPageModule } from '../../+search-page/search-page.module';
@NgModule({
imports: [
CommonModule,
SharedModule,
SearchPageModule,
EditItemPageRoutingModule
],
declarations: [

View File

@@ -15,7 +15,7 @@ import { ItemCollectionMapperComponent } from './item-collection-mapper/item-col
}
},
{
path: 'map',
path: 'mapper',
component: ItemCollectionMapperComponent,
resolve: {
item: ItemPageResolver

View File

@@ -1,7 +1,38 @@
<div class="container">
<div class="row">
<div class="col-12">
<p>It works!</p>
<h2>{{'item.edit.item-mapper.head' | translate}}</h2>
<p [innerHTML]="'item.edit.item-mapper.item' | translate:{ name: (itemRD$ | async)?.payload?.name }" id="item-name"></p>
<p>{{'item.edit.item-mapper.description' | translate}}</p>
<div class="row">
<div class="col-12 col-lg-6">
<ds-search-form id="search-form"
[query]="(searchOptions$ | async)?.query"
[scope]="(searchOptions$ | async)?.scope"
[currentUrl]="getCurrentUrl()">
</ds-search-form>
</div>
</div>
<ngb-tabset (tabChange)="tabChange($event)">
<ngb-tab title="{{'item.edit.item-mapper.tabs.browse' | translate}}">
<ng-template ngbTabContent>
<div class="mt-2">
<div *ngFor="let col of (itemCollectionsRD$ | async)?.payload">{{col.name}}</div>
</div>
</ng-template>
</ngb-tab>
<ngb-tab title="{{'item.edit.item-mapper.tabs.map' | translate}}">
<ng-template ngbTabContent>
<div class="mt-2">
</div>
</ng-template>
</ngb-tab>
</ngb-tabset>
<button [routerLink]="['/items/', (itemRD$ | async)?.payload?.id]" class="btn btn-outline-secondary">{{'item.edit.item-mapper.return' | translate}}</button>
</div>
</div>
</div>

View File

@@ -1,5 +1,20 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { fadeIn, fadeInOut } from '../../../shared/animations/fade';
import { Observable } from 'rxjs/Observable';
import { PaginatedSearchOptions } from '../../../+search-page/paginated-search-options.model';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list';
import { Collection } from '../../../core/shared/collection.model';
import { Item } from '../../../core/shared/item.model';
import { getSucceededRemoteData } from '../../../core/shared/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { SearchService } from '../../../+search-page/search-service/search.service';
import { SearchConfigurationService } from '../../../+search-page/search-service/search-configuration.service';
import { map, switchMap } from 'rxjs/operators';
import { CollectionDataService } from '../../../core/data/collection-data.service';
import { ItemDataService } from '../../../core/data/item-data.service';
@Component({
selector: 'ds-item-collection-mapper',
@@ -14,6 +29,81 @@ import { fadeIn, fadeInOut } from '../../../shared/animations/fade';
/**
* Component for mapping collections to an item
*/
export class ItemCollectionMapperComponent {
export class ItemCollectionMapperComponent implements OnInit {
/**
* The item to map to collections
*/
itemRD$: Observable<RemoteData<Item>>;
/**
* Search options
*/
searchOptions$: Observable<PaginatedSearchOptions>;
/**
* List of collections to show under the "Browse" tab
* Collections that are mapped to the item
*/
itemCollectionsRD$: Observable<RemoteData<Collection[]>>;
/**
* List of collections to show under the "Map" tab
* Collections that are not mapped to the item
*/
mappingCollectionsRD$: Observable<RemoteData<PaginatedList<Collection>>>;
/**
* Sort on title ASC by default
* @type {SortOptions}
*/
defaultSortOptions: SortOptions = new SortOptions('dc.title', SortDirection.ASC);
constructor(private route: ActivatedRoute,
private router: Router,
private searchConfigService: SearchConfigurationService,
private searchService: SearchService,
private collectionDataService: CollectionDataService,
private itemDataService: ItemDataService) {
}
ngOnInit(): void {
this.itemRD$ = this.route.data.map((data) => data.item).pipe(getSucceededRemoteData()) as Observable<RemoteData<Item>>;
this.searchOptions$ = this.searchConfigService.paginatedSearchOptions;
this.loadCollectionLists();
}
/**
* Load itemCollectionsRD$ with a fixed scope to only obtain the collections that own this item
* Load mappingCollectionsRD$ to only obtain collections that don't own this item
* TODO: When the API support it, fetch collections excluding the item's scope (currently fetches all collections)
*/
loadCollectionLists() {
this.itemCollectionsRD$ = this.itemRD$.pipe(
map((itemRD: RemoteData<Item>) => itemRD.payload),
switchMap((item: Item) => this.itemDataService.getMappedCollections(item.id))
);
this.mappingCollectionsRD$ = this.collectionDataService.findAll();
}
/**
* Clear url parameters on tab change (temporary fix until pagination is improved)
* @param event
*/
tabChange(event) {
// TODO: Fix tabs to maintain their own pagination options (once the current pagination system is improved)
// Temporary solution: Clear url params when changing tabs
this.router.navigateByUrl(this.getCurrentUrl());
}
/**
* Get current url without parameters
* @returns {string}
*/
getCurrentUrl(): string {
if (this.router.url.indexOf('?') > -1) {
return this.router.url.substring(0, this.router.url.indexOf('?'));
}
return this.router.url;
}
}

View File

@@ -54,7 +54,7 @@ export class ItemStatusComponent implements OnInit {
this.statusDataKeys = Object.keys(this.statusData);
this.actions = Object.assign({
mappedCollections: this.getCurrentUrl() + '/map'
mappedCollections: this.getCurrentUrl() + '/mapper'
});
this.actionsKeys = Object.keys(this.actions);
}

View File

@@ -65,6 +65,7 @@ import { UploaderService } from '../shared/uploader/uploader.service';
import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
import { DSpaceObjectDataService } from './data/dspace-object-data.service';
import { ItemSelectService } from '../shared/item-select/item-select.service';
import { MappingCollectionsReponseParsingService } from './data/mapping-collections-reponse-parsing.service';
const IMPORTS = [
CommonModule,
@@ -111,6 +112,7 @@ const PROVIDERS = [
RegistryMetadataschemasResponseParsingService,
RegistryMetadatafieldsResponseParsingService,
RegistryBitstreamformatsResponseParsingService,
MappingCollectionsReponseParsingService,
MetadataschemaParsingService,
DebugResponseParsingService,
SearchResponseParsingService,

View File

@@ -3,7 +3,7 @@ import { Inject, Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { isEmpty, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
import { ensureArrayHasValue, isEmpty, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
import { BrowseService } from '../browse/browse.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { NormalizedItem } from '../cache/models/normalized-item.model';
@@ -15,11 +15,21 @@ import { URLCombiner } from '../url-combiner/url-combiner';
import { DataService } from './data.service';
import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { FindAllOptions, PostRequest, RestRequest } from './request.models';
import { FindAllOptions, GetRequest, MappingCollectionsRequest, PostRequest, RestRequest } from './request.models';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { configureRequest, getResponseFromSelflink } from '../shared/operators';
import {
configureRequest,
filterSuccessfulResponses,
getRequestFromSelflink,
getResponseFromSelflink
} from '../shared/operators';
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
import { RestResponse } from '../cache/response-cache.models';
import { DSOSuccessResponse, GenericSuccessResponse, RestResponse } from '../cache/response-cache.models';
import { BrowseDefinition } from '../shared/browse-definition.model';
import { Collection } from '../shared/collection.model';
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
import { RemoteData } from './remote-data';
import { PaginatedList } from './paginated-list';
@Injectable()
export class ItemDataService extends DataService<NormalizedItem, Item> {
@@ -71,4 +81,16 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
);
}
public getMappedCollections(itemId: string): Observable<RemoteData<Collection[]>> {
const request$ = this.getMappingCollectionsEndpoint(itemId).pipe(
isNotEmptyOperator(),
distinctUntilChanged(),
map((endpointURL: string) => new MappingCollectionsRequest(this.requestService.generateRequestId(), endpointURL)),
configureRequest(this.requestService)
);
// TODO: Create a remotedata object
return undefined;
}
}

View File

@@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
import { ResponseParsingService } from './parsing.service';
import { RestRequest } from './request.models';
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response-cache.models';
@Injectable()
export class MappingCollectionsReponseParsingService implements ResponseParsingService {
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
const payload = data.payload;
if (payload._embedded && payload._embedded.mappingCollections) {
const mappingCollections = payload._embedded.mappingCollections;
return new GenericSuccessResponse(mappingCollections, data.statusCode);
} else {
return new ErrorResponse(
Object.assign(
new Error('Unexpected response from mappingCollections endpoint'),
{ statusText: data.statusCode }
)
);
}
}
}

View File

@@ -13,6 +13,7 @@ import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
import { HttpHeaders } from '@angular/common/http';
import { IntegrationResponseParsingService } from '../integration/integration-response-parsing.service';
import { BrowseItemsResponseParsingService } from './browse-items-response-parsing-service';
import { MappingCollectionsReponseParsingService } from './mapping-collections-reponse-parsing.service';
/* tslint:disable:max-classes-per-file */
@@ -191,6 +192,12 @@ export class BrowseItemsRequest extends GetRequest {
}
}
export class MappingCollectionsRequest extends GetRequest {
getResponseParser(): GenericConstructor<ResponseParsingService> {
return MappingCollectionsReponseParsingService;
}
}
export class ConfigRequest extends GetRequest {
constructor(uuid: string, href: string) {
super(uuid, href);