mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
search backend fixes #1
This commit is contained in:
@@ -8,13 +8,20 @@ module.exports = {
|
|||||||
nameSpace: '/'
|
nameSpace: '/'
|
||||||
},
|
},
|
||||||
// The REST API server settings.
|
// The REST API server settings.
|
||||||
rest: {
|
// rest: {
|
||||||
ssl: true,
|
// ssl: true,
|
||||||
host: 'dspace7.4science.it',
|
// host: 'dspace7.4science.it',
|
||||||
port: 443,
|
// port: 443,
|
||||||
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
// // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||||
nameSpace: '/dspace-spring-rest/api'
|
// nameSpace: '/dspace-spring-rest/api'
|
||||||
},
|
// },
|
||||||
|
rest: {
|
||||||
|
ssl: false,
|
||||||
|
host: 'dspace7-internal.atmire.com',
|
||||||
|
port: 80,
|
||||||
|
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||||
|
nameSpace: '/rest/api'
|
||||||
|
},
|
||||||
// Caching settings
|
// Caching settings
|
||||||
cache: {
|
cache: {
|
||||||
// NOTE: how long should objects be cached for by default
|
// NOTE: how long should objects be cached for by default
|
||||||
|
@@ -36,7 +36,7 @@ export class SearchPageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
query: string;
|
query: string;
|
||||||
scopeObjectRDObs: Observable<RemoteData<DSpaceObject>>;
|
scopeObjectRDObs: Observable<RemoteData<DSpaceObject>>;
|
||||||
resultsRDObs: Observable<RemoteData<Array<SearchResult<DSpaceObject>>>>;
|
resultsRDObs: Observable<RemoteData<Array<SearchResult<DSpaceObject>> | PaginatedList<SearchResult<DSpaceObject>>>>;
|
||||||
currentParams = {};
|
currentParams = {};
|
||||||
searchOptions: SearchOptions;
|
searchOptions: SearchOptions;
|
||||||
sortConfig: SortOptions;
|
sortConfig: SortOptions;
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
||||||
|
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||||
|
|
||||||
|
const searchResultMap = new Map();
|
||||||
|
|
||||||
|
export function searchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
|
||||||
|
return function decorator(searchResult: any) {
|
||||||
|
if (!searchResult) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
searchResultMap.set(domainConstructor, searchResult);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSearchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
|
||||||
|
return searchResultMap.get(domainConstructor);
|
||||||
|
}
|
@@ -1,35 +1,27 @@
|
|||||||
import { Inject, Injectable, OnDestroy } from '@angular/core';
|
import { Inject, Injectable, OnDestroy } from '@angular/core';
|
||||||
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { map, flatMap, tap, filter } from 'rxjs/operators';
|
import { flatMap, map, tap } from 'rxjs/operators';
|
||||||
import { ViewMode } from '../../+search-page/search-options.model';
|
import { ViewMode } from '../../+search-page/search-options.model';
|
||||||
import { GLOBAL_CONFIG } from '../../../config';
|
import { GLOBAL_CONFIG } from '../../../config';
|
||||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
|
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
|
||||||
import { NormalizedDSpaceObject } from '../../core/cache/models/normalized-dspace-object.model';
|
import { NormalizedDSpaceObject } from '../../core/cache/models/normalized-dspace-object.model';
|
||||||
import { SortOptions } from '../../core/cache/models/sort-options.model';
|
import { SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
import { RestResponse, SearchSuccessResponse } from '../../core/cache/response-cache.models';
|
import { SearchSuccessResponse } from '../../core/cache/response-cache.models';
|
||||||
import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer';
|
import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer';
|
||||||
import { ResponseCacheService } from '../../core/cache/response-cache.service';
|
import { ResponseCacheService } from '../../core/cache/response-cache.service';
|
||||||
import { DebugResponseParsingService } from '../../core/data/debug-response-parsing.service';
|
|
||||||
import { DSOResponseParsingService } from '../../core/data/dso-response-parsing.service';
|
|
||||||
import { ItemDataService } from '../../core/data/item-data.service';
|
import { ItemDataService } from '../../core/data/item-data.service';
|
||||||
import { PaginatedList } from '../../core/data/paginated-list';
|
import { PaginatedList } from '../../core/data/paginated-list';
|
||||||
import { ResponseParsingService } from '../../core/data/parsing.service';
|
import { ResponseParsingService } from '../../core/data/parsing.service';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { GetRequest, EndpointMapRequest, RestRequest } from '../../core/data/request.models';
|
import { GetRequest, RestRequest } from '../../core/data/request.models';
|
||||||
import { RequestEntry } from '../../core/data/request.reducer';
|
|
||||||
import { RequestService } from '../../core/data/request.service';
|
import { RequestService } from '../../core/data/request.service';
|
||||||
import { DSpaceRESTV2Response } from '../../core/dspace-rest-v2/dspace-rest-v2-response.model';
|
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
||||||
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
||||||
import { Item } from '../../core/shared/item.model';
|
|
||||||
import { Metadatum } from '../../core/shared/metadatum.model';
|
|
||||||
import { PageInfo } from '../../core/shared/page-info.model';
|
|
||||||
import { URLCombiner } from '../../core/url-combiner/url-combiner';
|
import { URLCombiner } from '../../core/url-combiner/url-combiner';
|
||||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { ItemSearchResult } from '../../shared/object-collection/shared/item-search-result.model';
|
|
||||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||||
import { RouteService } from '../../shared/route.service';
|
import { RouteService } from '../../shared/route.service';
|
||||||
import { NormalizedSearchResult } from '../normalized-search-result.model';
|
import { NormalizedSearchResult } from '../normalized-search-result.model';
|
||||||
@@ -40,6 +32,10 @@ import { FilterType } from './filter-type.model';
|
|||||||
import { SearchFilterConfig } from './search-filter-config.model';
|
import { SearchFilterConfig } from './search-filter-config.model';
|
||||||
import { SearchResponseParsingService } from '../../core/data/search-response-parsing.service';
|
import { SearchResponseParsingService } from '../../core/data/search-response-parsing.service';
|
||||||
import { SearchQueryResponse } from './search-query-response.model';
|
import { SearchQueryResponse } from './search-query-response.model';
|
||||||
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
|
import { getSearchResultFor } from './search-result-element-decorator';
|
||||||
|
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||||
|
import { NormalizedItem } from '../../core/cache/models/normalized-item.model';
|
||||||
|
|
||||||
function shuffle(array: any[]) {
|
function shuffle(array: any[]) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@@ -95,16 +91,14 @@ export class SearchService extends HALEndpointService implements OnDestroy {
|
|||||||
// searchOptions: BehaviorSubject<SearchOptions>;
|
// searchOptions: BehaviorSubject<SearchOptions>;
|
||||||
searchOptions: SearchOptions;
|
searchOptions: SearchOptions;
|
||||||
|
|
||||||
constructor(
|
constructor(protected responseCache: ResponseCacheService,
|
||||||
protected responseCache: ResponseCacheService,
|
protected requestService: RequestService,
|
||||||
protected requestService: RequestService,
|
private itemDataService: ItemDataService,
|
||||||
private itemDataService: ItemDataService,
|
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
private routeService: RouteService,
|
||||||
private routeService: RouteService,
|
private route: ActivatedRoute,
|
||||||
private route: ActivatedRoute,
|
private rdb: RemoteDataBuildService,
|
||||||
private rdb: RemoteDataBuildService,
|
private router: Router) {
|
||||||
private router: Router
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
||||||
pagination.id = 'search-results-pagination';
|
pagination.id = 'search-results-pagination';
|
||||||
@@ -115,7 +109,7 @@ export class SearchService extends HALEndpointService implements OnDestroy {
|
|||||||
// this.searchOptions = new BehaviorSubject<SearchOptions>(searchOptions);
|
// this.searchOptions = new BehaviorSubject<SearchOptions>(searchOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable<RemoteData<Array<SearchResult<DSpaceObject>>>> {
|
search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable<RemoteData<Array<SearchResult<DSpaceObject>> | PaginatedList<SearchResult<DSpaceObject>>>> {
|
||||||
const requestObs = this.getEndpoint().pipe(
|
const requestObs = this.getEndpoint().pipe(
|
||||||
map((url: string) => {
|
map((url: string) => {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
@@ -150,25 +144,57 @@ export class SearchService extends HALEndpointService implements OnDestroy {
|
|||||||
flatMap((request: RestRequest) => this.responseCache.get(request.href))
|
flatMap((request: RestRequest) => this.responseCache.get(request.href))
|
||||||
);
|
);
|
||||||
|
|
||||||
const sqrObs = responseCacheObs.pipe(
|
// get search results from response cache
|
||||||
|
const sqrObs: Observable<SearchQueryResponse> = responseCacheObs.pipe(
|
||||||
map((entry: ResponseCacheEntry) => entry.response),
|
map((entry: ResponseCacheEntry) => entry.response),
|
||||||
map((response: SearchSuccessResponse) => response.results)
|
map((response: SearchSuccessResponse) => response.results)
|
||||||
);
|
);
|
||||||
|
|
||||||
const dsoObs = sqrObs.pipe(
|
// turn dspace href from search results to effective list of DSpaceObjects
|
||||||
|
// Turn list of observable remote data DSO's into observable remote data object with list of DSO
|
||||||
|
const dsoObs: Observable<RemoteData<DSpaceObject[]>> = sqrObs.pipe(
|
||||||
map((sqr: SearchQueryResponse) => {
|
map((sqr: SearchQueryResponse) => {
|
||||||
return sqr.objects.map((nsr: NormalizedSearchResult) =>
|
return sqr.objects.map((nsr: NormalizedSearchResult) =>
|
||||||
this.rdb.buildSingle(nsr.dspaceObject, NormalizedDSpaceObject));
|
this.rdb.buildSingle(nsr.dspaceObject));
|
||||||
}),
|
}),
|
||||||
flatMap((input: Array<Observable<RemoteData<DSpaceObject>>>) => this.rdb.aggregate(input))
|
flatMap((input: Array<Observable<RemoteData<DSpaceObject>>>) => this.rdb.aggregate(input))
|
||||||
);
|
);
|
||||||
|
|
||||||
const payloadObs = Observable.combineLatest(sqrObs, dsoObs, (sqr: SearchQueryResponse, dsos: RemoteData<DSpaceObject[]>) => {
|
// Create search results again with the correct dso objects linked to each result
|
||||||
|
const tDomainListObs: Observable<Array<SearchResult<DSpaceObject>>> = Observable.combineLatest(sqrObs, dsoObs, (sqr: SearchQueryResponse, dsos: RemoteData<DSpaceObject[]>) => {
|
||||||
return sqr.objects.map((object: NormalizedSearchResult, index: number) => {
|
return sqr.objects.map((object: NormalizedSearchResult, index: number) => {
|
||||||
return Object.assign({}, object, {
|
let co = DSpaceObject;
|
||||||
dspaceObject: dsos.payload[index]
|
if (dsos.payload[index]) {
|
||||||
});
|
const constructor: GenericConstructor<ListableObject> = dsos.payload[index].constructor as GenericConstructor<ListableObject>;
|
||||||
})
|
co = getSearchResultFor(constructor);
|
||||||
|
return Object.assign(new co(), object, {
|
||||||
|
dspaceObject: dsos.payload[index]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageInfoObs: Observable<PageInfo> = responseCacheObs
|
||||||
|
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
|
.map((entry: ResponseCacheEntry) => {
|
||||||
|
if (hasValue((entry.response as SearchSuccessResponse).pageInfo)) {
|
||||||
|
const resPageInfo = (entry.response as SearchSuccessResponse).pageInfo;
|
||||||
|
if (isNotEmpty(resPageInfo) && resPageInfo.currentPage >= 0) {
|
||||||
|
return Object.assign({}, resPageInfo, { currentPage: resPageInfo.currentPage + 1 });
|
||||||
|
} else {
|
||||||
|
return resPageInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const payloadObs = Observable.combineLatest(tDomainListObs, pageInfoObs, (tDomainList, pageInfo) => {
|
||||||
|
if (hasValue(pageInfo)) {
|
||||||
|
return new PaginatedList(pageInfo, tDomainList);
|
||||||
|
} else {
|
||||||
|
return tDomainList;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
|
return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
|
||||||
|
@@ -22,24 +22,19 @@ import { DSOSuccessResponse, ErrorResponse, SearchSuccessResponse } from '../res
|
|||||||
import { ResponseCacheEntry } from '../response-cache.reducer';
|
import { ResponseCacheEntry } from '../response-cache.reducer';
|
||||||
import { ResponseCacheService } from '../response-cache.service';
|
import { ResponseCacheService } from '../response-cache.service';
|
||||||
import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators';
|
import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators';
|
||||||
|
import { NormalizedObject } from '../models/normalized-object.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RemoteDataBuildService {
|
export class RemoteDataBuildService {
|
||||||
constructor(
|
constructor(protected objectCache: ObjectCacheService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected responseCache: ResponseCacheService,
|
||||||
protected responseCache: ResponseCacheService,
|
protected requestService: RequestService) {
|
||||||
protected requestService: RequestService
|
|
||||||
) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSingle<TNormalized extends CacheableObject, TDomain>(
|
buildSingle<TNormalized extends NormalizedObject, TDomain>(hrefObs: string | Observable<string>): Observable<RemoteData<TDomain>> {
|
||||||
hrefObs: string | Observable<string>,
|
|
||||||
normalizedType: GenericConstructor<TNormalized>
|
|
||||||
): Observable<RemoteData<TDomain>> {
|
|
||||||
if (typeof hrefObs === 'string') {
|
if (typeof hrefObs === 'string') {
|
||||||
hrefObs = Observable.of(hrefObs);
|
hrefObs = Observable.of(hrefObs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestHrefObs = hrefObs.flatMap((href: string) =>
|
const requestHrefObs = hrefObs.flatMap((href: string) =>
|
||||||
this.objectCache.getRequestHrefBySelfLink(href));
|
this.objectCache.getRequestHrefBySelfLink(href));
|
||||||
|
|
||||||
@@ -59,14 +54,14 @@ export class RemoteDataBuildService {
|
|||||||
// always use self link if that is cached, only if it isn't, get it via the response.
|
// always use self link if that is cached, only if it isn't, get it via the response.
|
||||||
const payloadObs =
|
const payloadObs =
|
||||||
Observable.combineLatest(
|
Observable.combineLatest(
|
||||||
hrefObs.flatMap((href: string) => this.objectCache.getBySelfLink<TNormalized>(href, normalizedType))
|
hrefObs.flatMap((href: string) => this.objectCache.getBySelfLink<TNormalized>(href))
|
||||||
.startWith(undefined),
|
.startWith(undefined),
|
||||||
responseCacheObs
|
responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
.map((entry: ResponseCacheEntry) => (entry.response as DSOSuccessResponse).resourceSelfLinks)
|
.map((entry: ResponseCacheEntry) => (entry.response as DSOSuccessResponse).resourceSelfLinks)
|
||||||
.flatMap((resourceSelfLinks: string[]) => {
|
.flatMap((resourceSelfLinks: string[]) => {
|
||||||
if (isNotEmpty(resourceSelfLinks)) {
|
if (isNotEmpty(resourceSelfLinks)) {
|
||||||
return this.objectCache.getBySelfLink(resourceSelfLinks[0], normalizedType);
|
return this.objectCache.getBySelfLink(resourceSelfLinks[0]);
|
||||||
} else {
|
} else {
|
||||||
return Observable.of(undefined);
|
return Observable.of(undefined);
|
||||||
}
|
}
|
||||||
@@ -97,7 +92,7 @@ export class RemoteDataBuildService {
|
|||||||
let isSuccessful: boolean;
|
let isSuccessful: boolean;
|
||||||
let error: RemoteDataError;
|
let error: RemoteDataError;
|
||||||
if (hasValue(resEntry) && hasValue(resEntry.response)) {
|
if (hasValue(resEntry) && hasValue(resEntry.response)) {
|
||||||
isSuccessful = !responsePending && resEntry.response.isSuccessful;
|
isSuccessful = resEntry.response.isSuccessful;
|
||||||
const errorMessage = isSuccessful === false ? (resEntry.response as ErrorResponse).errorMessage : undefined;
|
const errorMessage = isSuccessful === false ? (resEntry.response as ErrorResponse).errorMessage : undefined;
|
||||||
if (hasValue(errorMessage)) {
|
if (hasValue(errorMessage)) {
|
||||||
error = new RemoteDataError(resEntry.response.statusCode, errorMessage);
|
error = new RemoteDataError(resEntry.response.statusCode, errorMessage);
|
||||||
@@ -114,10 +109,8 @@ export class RemoteDataBuildService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildList<TNormalized extends CacheableObject, TDomain>(
|
buildList<TNormalized extends NormalizedObject, TDomain>(hrefObs: string | Observable<string>,
|
||||||
hrefObs: string | Observable<string>,
|
normalizedType: GenericConstructor<TNormalized>): Observable<RemoteData<TDomain[] | PaginatedList<TDomain>>> {
|
||||||
normalizedType: GenericConstructor<TNormalized>
|
|
||||||
): Observable<RemoteData<TDomain[] | PaginatedList<TDomain>>> {
|
|
||||||
if (typeof hrefObs === 'string') {
|
if (typeof hrefObs === 'string') {
|
||||||
hrefObs = Observable.of(hrefObs);
|
hrefObs = Observable.of(hrefObs);
|
||||||
}
|
}
|
||||||
@@ -181,7 +174,7 @@ export class RemoteDataBuildService {
|
|||||||
|
|
||||||
const rdArr = [];
|
const rdArr = [];
|
||||||
normalized[relationship].forEach((href: string) => {
|
normalized[relationship].forEach((href: string) => {
|
||||||
rdArr.push(this.buildSingle(href, resourceConstructor));
|
rdArr.push(this.buildSingle(href));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isList) {
|
if (isList) {
|
||||||
@@ -198,7 +191,7 @@ export class RemoteDataBuildService {
|
|||||||
if (isList) {
|
if (isList) {
|
||||||
links[relationship] = this.buildList(normalized[relationship], resourceConstructor);
|
links[relationship] = this.buildList(normalized[relationship], resourceConstructor);
|
||||||
} else {
|
} else {
|
||||||
links[relationship] = this.buildSingle(normalized[relationship], resourceConstructor);
|
links[relationship] = this.buildSingle(normalized[relationship]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
import { inheritSerialization, autoserialize } from 'cerialize';
|
|
||||||
|
|
||||||
import { mapsTo } from '../builders/build-decorators';
|
|
||||||
|
|
||||||
import { BitstreamFormat } from '../../shared/bitstream-format.model';
|
|
||||||
import { NormalizedObject } from './normalized-object.model';
|
|
||||||
|
|
||||||
@mapsTo(BitstreamFormat)
|
|
||||||
@inheritSerialization(NormalizedObject)
|
|
||||||
export class NormalizedBitstreamFormat extends NormalizedObject {
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
shortDescription: string;
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
mimetype: string;
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
supportLevel: number;
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
internal: boolean;
|
|
||||||
|
|
||||||
@autoserialize
|
|
||||||
extensions: string;
|
|
||||||
|
|
||||||
}
|
|
@@ -1,4 +1,3 @@
|
|||||||
import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
|
|
||||||
import { NormalizedBitstream } from './normalized-bitstream.model';
|
import { NormalizedBitstream } from './normalized-bitstream.model';
|
||||||
import { NormalizedBundle } from './normalized-bundle.model';
|
import { NormalizedBundle } from './normalized-bundle.model';
|
||||||
import { NormalizedItem } from './normalized-item.model';
|
import { NormalizedItem } from './normalized-item.model';
|
||||||
@@ -7,7 +6,6 @@ import { GenericConstructor } from '../../shared/generic-constructor';
|
|||||||
import { NormalizedCommunity } from './normalized-community.model';
|
import { NormalizedCommunity } from './normalized-community.model';
|
||||||
import { ResourceType } from '../../shared/resource-type';
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
import { NormalizedObject } from './normalized-object.model';
|
import { NormalizedObject } from './normalized-object.model';
|
||||||
import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model';
|
|
||||||
|
|
||||||
export class NormalizedObjectFactory {
|
export class NormalizedObjectFactory {
|
||||||
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedObject> {
|
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedObject> {
|
||||||
@@ -15,9 +13,6 @@ export class NormalizedObjectFactory {
|
|||||||
case ResourceType.Bitstream: {
|
case ResourceType.Bitstream: {
|
||||||
return NormalizedBitstream
|
return NormalizedBitstream
|
||||||
}
|
}
|
||||||
case ResourceType.BitstreamFormat: {
|
|
||||||
return NormalizedBitstreamFormat
|
|
||||||
}
|
|
||||||
case ResourceType.Bundle: {
|
case ResourceType.Bundle: {
|
||||||
return NormalizedBundle
|
return NormalizedBundle
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { CacheableObject } from '../object-cache.reducer';
|
import { CacheableObject } from '../object-cache.reducer';
|
||||||
import { autoserialize } from 'cerialize';
|
import { autoserialize } from 'cerialize';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a NormalizedObject.
|
* An abstract model class for a NormalizedObject.
|
||||||
*/
|
*/
|
||||||
@@ -17,6 +18,9 @@ export abstract class NormalizedObject implements CacheableObject {
|
|||||||
@autoserialize
|
@autoserialize
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
_links: {
|
_links: {
|
||||||
[name: string]: string
|
[name: string]: string
|
||||||
|
2
src/app/core/cache/object-cache.reducer.ts
vendored
2
src/app/core/cache/object-cache.reducer.ts
vendored
@@ -4,6 +4,7 @@ import {
|
|||||||
} from './object-cache.actions';
|
} from './object-cache.actions';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import { CacheEntry } from './cache-entry';
|
import { CacheEntry } from './cache-entry';
|
||||||
|
import { ResourceType } from '../shared/resource-type';
|
||||||
|
|
||||||
export enum DirtyType {
|
export enum DirtyType {
|
||||||
Created = 'Created',
|
Created = 'Created',
|
||||||
@@ -19,6 +20,7 @@ export enum DirtyType {
|
|||||||
export interface CacheableObject {
|
export interface CacheableObject {
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
self: string;
|
self: string;
|
||||||
|
type: ResourceType;
|
||||||
// isNew: boolean;
|
// isNew: boolean;
|
||||||
// dirtyType: DirtyType;
|
// dirtyType: DirtyType;
|
||||||
// hasDirtyAttributes: boolean;
|
// hasDirtyAttributes: boolean;
|
||||||
|
23
src/app/core/cache/object-cache.service.ts
vendored
23
src/app/core/cache/object-cache.service.ts
vendored
@@ -10,6 +10,9 @@ import { hasNoValue } from '../../shared/empty.util';
|
|||||||
import { GenericConstructor } from '../shared/generic-constructor';
|
import { GenericConstructor } from '../shared/generic-constructor';
|
||||||
import { coreSelector, CoreState } from '../core.reducers';
|
import { coreSelector, CoreState } from '../core.reducers';
|
||||||
import { pathSelector } from '../shared/selectors';
|
import { pathSelector } from '../shared/selectors';
|
||||||
|
import { Item } from '../shared/item.model';
|
||||||
|
import { NormalizedObjectFactory } from './models/normalized-object-factory';
|
||||||
|
import { NormalizedObject } from './models/normalized-object.model';
|
||||||
|
|
||||||
function selfLinkFromUuidSelector(uuid: string): MemoizedSelector<CoreState, string> {
|
function selfLinkFromUuidSelector(uuid: string): MemoizedSelector<CoreState, string> {
|
||||||
return pathSelector<CoreState, string>(coreSelector, 'index', IndexName.OBJECT, uuid);
|
return pathSelector<CoreState, string>(coreSelector, 'index', IndexName.OBJECT, uuid);
|
||||||
@@ -24,9 +27,8 @@ function entryFromSelfLinkSelector(selfLink: string): MemoizedSelector<CoreState
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ObjectCacheService {
|
export class ObjectCacheService {
|
||||||
constructor(
|
constructor(private store: Store<CoreState>) {
|
||||||
private store: Store<CoreState>
|
}
|
||||||
) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an object to the cache
|
* Add an object to the cache
|
||||||
@@ -70,14 +72,17 @@ export class ObjectCacheService {
|
|||||||
* @return Observable<T>
|
* @return Observable<T>
|
||||||
* An observable of the requested object
|
* An observable of the requested object
|
||||||
*/
|
*/
|
||||||
getByUUID<T extends CacheableObject>(uuid: string, type: GenericConstructor<T>): Observable<T> {
|
getByUUID<T extends NormalizedObject>(uuid: string): Observable<T> {
|
||||||
return this.store.select(selfLinkFromUuidSelector(uuid))
|
return this.store.select(selfLinkFromUuidSelector(uuid))
|
||||||
.flatMap((selfLink: string) => this.getBySelfLink(selfLink, type))
|
.flatMap((selfLink: string) => this.getBySelfLink(selfLink))
|
||||||
}
|
}
|
||||||
|
|
||||||
getBySelfLink<T extends CacheableObject>(selfLink: string, type: GenericConstructor<T>): Observable<T> {
|
getBySelfLink<T extends NormalizedObject>(selfLink: string): Observable<T> {
|
||||||
return this.getEntry(selfLink)
|
return this.getEntry(selfLink)
|
||||||
.map((entry: ObjectCacheEntry) => Object.assign(new type(), entry.data) as T);
|
.map((entry: ObjectCacheEntry) => {
|
||||||
|
const type: GenericConstructor<NormalizedObject>= NormalizedObjectFactory.getConstructor(entry.data.type);
|
||||||
|
return Object.assign(new type(), entry.data) as T
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getEntry(selfLink: string): Observable<ObjectCacheEntry> {
|
private getEntry(selfLink: string): Observable<ObjectCacheEntry> {
|
||||||
@@ -116,9 +121,9 @@ export class ObjectCacheService {
|
|||||||
* The type of the objects to get
|
* The type of the objects to get
|
||||||
* @return Observable<Array<T>>
|
* @return Observable<Array<T>>
|
||||||
*/
|
*/
|
||||||
getList<T extends CacheableObject>(selfLinks: string[], type: GenericConstructor<T>): Observable<T[]> {
|
getList<T extends NormalizedObject>(selfLinks: string[], type: GenericConstructor<T>): Observable<T[]> {
|
||||||
return Observable.combineLatest(
|
return Observable.combineLatest(
|
||||||
selfLinks.map((selfLink: string) => this.getBySelfLink<T>(selfLink, type))
|
selfLinks.map((selfLink: string) => this.getBySelfLink<T>(selfLink))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,8 +9,9 @@ import { CommunityDataService } from './community-data.service';
|
|||||||
|
|
||||||
import { DataService } from './data.service';
|
import { DataService } from './data.service';
|
||||||
import { FindByIDRequest } from './request.models';
|
import { FindByIDRequest } from './request.models';
|
||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
|
||||||
export abstract class ComColDataService<TNormalized extends CacheableObject, TDomain> extends DataService<TNormalized, TDomain> {
|
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
|
||||||
protected abstract cds: CommunityDataService;
|
protected abstract cds: CommunityDataService;
|
||||||
protected abstract objectCache: ObjectCacheService;
|
protected abstract objectCache: ObjectCacheService;
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ export abstract class ComColDataService<TNormalized extends CacheableObject, TDo
|
|||||||
errorResponse.flatMap((response: ErrorResponse) =>
|
errorResponse.flatMap((response: ErrorResponse) =>
|
||||||
Observable.throw(new Error(`The Community with scope ${scopeID} couldn't be retrieved`))),
|
Observable.throw(new Error(`The Community with scope ${scopeID} couldn't be retrieved`))),
|
||||||
successResponse
|
successResponse
|
||||||
.flatMap((response: DSOSuccessResponse) => this.objectCache.getByUUID(scopeID, NormalizedCommunity))
|
.flatMap((response: DSOSuccessResponse) => this.objectCache.getByUUID(scopeID))
|
||||||
.map((nc: NormalizedCommunity) => nc._links[this.linkPath])
|
.map((nc: NormalizedCommunity) => nc._links[this.linkPath])
|
||||||
.filter((href) => isNotEmpty(href))
|
.filter((href) => isNotEmpty(href))
|
||||||
).distinctUntilChanged();
|
).distinctUntilChanged();
|
||||||
|
@@ -13,8 +13,9 @@ import { PaginatedList } from './paginated-list';
|
|||||||
import { RemoteData } from './remote-data';
|
import { RemoteData } from './remote-data';
|
||||||
import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './request.models';
|
import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './request.models';
|
||||||
import { RequestService } from './request.service';
|
import { RequestService } from './request.service';
|
||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
|
||||||
export abstract class DataService<TNormalized extends CacheableObject, TDomain> extends HALEndpointService {
|
export abstract class DataService<TNormalized extends NormalizedObject, TDomain> extends HALEndpointService {
|
||||||
protected abstract responseCache: ResponseCacheService;
|
protected abstract responseCache: ResponseCacheService;
|
||||||
protected abstract requestService: RequestService;
|
protected abstract requestService: RequestService;
|
||||||
protected abstract rdbService: RemoteDataBuildService;
|
protected abstract rdbService: RemoteDataBuildService;
|
||||||
@@ -22,9 +23,7 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
protected abstract linkPath: string;
|
protected abstract linkPath: string;
|
||||||
protected abstract EnvConfig: GlobalConfig;
|
protected abstract EnvConfig: GlobalConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(protected normalizedResourceType: GenericConstructor<TNormalized>,) {
|
||||||
protected normalizedResourceType: GenericConstructor<TNormalized>,
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,12 +94,12 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
this.requestService.configure(request);
|
this.requestService.configure(request);
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(hrefObs, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(hrefObs);
|
||||||
}
|
}
|
||||||
|
|
||||||
findByHref(href: string): Observable<RemoteData<TDomain>> {
|
findByHref(href: string): Observable<RemoteData<TDomain>> {
|
||||||
this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href));
|
this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href));
|
||||||
return this.rdbService.buildSingle<TNormalized, TDomain>(href, this.normalizedResourceType);
|
return this.rdbService.buildSingle<TNormalized, TDomain>(href);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO implement, after the structure of the REST server's POST response is finalized
|
// TODO implement, after the structure of the REST server's POST response is finalized
|
||||||
|
@@ -1,23 +1,35 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { RestResponse, SearchSuccessResponse } from '../cache/response-cache.models';
|
||||||
DSOSuccessResponse, RestResponse,
|
|
||||||
SearchSuccessResponse
|
|
||||||
} from '../cache/response-cache.models';
|
|
||||||
import { DSOResponseParsingService } from './dso-response-parsing.service';
|
import { DSOResponseParsingService } from './dso-response-parsing.service';
|
||||||
import { ResponseParsingService } from './parsing.service';
|
import { ResponseParsingService } from './parsing.service';
|
||||||
import { RestRequest } from './request.models';
|
import { RestRequest } from './request.models';
|
||||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
import { PageInfo } from '../shared/page-info.model';
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
||||||
|
import { Metadatum } from '../shared/metadatum.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchResponseParsingService implements ResponseParsingService {
|
export class SearchResponseParsingService implements ResponseParsingService {
|
||||||
constructor(private dsoParser: DSOResponseParsingService) {}
|
constructor(private dsoParser: DSOResponseParsingService) {
|
||||||
|
}
|
||||||
|
|
||||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
const payload = data.payload;
|
const payload = data.payload;
|
||||||
|
const hitHighlights = payload._embedded.objects
|
||||||
|
.map((object) => object.hitHighlights)
|
||||||
|
.map((hhObject) => {
|
||||||
|
if (hhObject) {
|
||||||
|
return Object.keys(hhObject).map((key) => Object.assign(new Metadatum(), {
|
||||||
|
key: key,
|
||||||
|
value: hhObject[key].join('...')
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const dsoSelfLinks = payload._embedded.objects
|
const dsoSelfLinks = payload._embedded.objects
|
||||||
.map((object) => object._embedded.dspaceObject)
|
.map((object) => object._embedded.dspaceObject)
|
||||||
// we don't need embedded collections, bitstreamformats, etc for search results.
|
// we don't need embedded collections, bitstreamformats, etc for search results.
|
||||||
@@ -32,11 +44,24 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
|||||||
.reduce((combined, thisElement) => [...combined, ...thisElement], []);
|
.reduce((combined, thisElement) => [...combined, ...thisElement], []);
|
||||||
|
|
||||||
const objects = payload._embedded.objects
|
const objects = payload._embedded.objects
|
||||||
.map((object, index) => Object.assign({}, object, { dspaceObject: dsoSelfLinks[index] }));
|
.map((object, index) => Object.assign({}, object, {
|
||||||
|
dspaceObject: dsoSelfLinks[index],
|
||||||
|
hitHighlights: hitHighlights[index],
|
||||||
|
// we don't need embedded collections, bitstreamformats, etc for search results.
|
||||||
|
// And parsing them all takes up a lot of time. Throw them away to improve performance
|
||||||
|
// until objs until partial results are supported by the rest api
|
||||||
|
_embedded: undefined
|
||||||
|
}));
|
||||||
payload.objects = objects;
|
payload.objects = objects;
|
||||||
const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
|
const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
|
||||||
return new SearchSuccessResponse(deserialized, data.statusCode, undefined);
|
return new SearchSuccessResponse(deserialized, data.statusCode, this.processPageInfo(data.payload.page));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected processPageInfo(pageObj: any): PageInfo {
|
||||||
|
if (isNotEmpty(pageObj)) {
|
||||||
|
return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,24 @@
|
|||||||
import { DSpaceObject } from './dspace-object.model';
|
|
||||||
|
|
||||||
export class BitstreamFormat extends DSpaceObject {
|
import { autoserialize } from 'cerialize';
|
||||||
|
|
||||||
|
export class BitstreamFormat {
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
shortDescription: string;
|
shortDescription: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
mimetype: string;
|
mimetype: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
supportLevel: number;
|
supportLevel: number;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
internal: boolean;
|
internal: boolean;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
extensions: string;
|
extensions: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import { Observable } from 'rxjs/Observable';
|
|||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
*/
|
*/
|
||||||
export class DSpaceObject implements CacheableObject, ListableObject {
|
export class DSpaceObject implements CacheableObject, ListableObject {
|
||||||
|
|
||||||
self: string;
|
self: string;
|
||||||
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { Collection } from '../../../core/shared/collection.model';
|
|
||||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
|
import { Collection } from '../../../core/shared/collection.model';
|
||||||
|
import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator';
|
||||||
|
|
||||||
|
@searchResultFor(Collection)
|
||||||
export class CollectionSearchResult extends SearchResult<Collection> {
|
export class CollectionSearchResult extends SearchResult<Collection> {
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
|
||||||
import { Community } from '../../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
|
import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator';
|
||||||
|
|
||||||
|
@searchResultFor(Community)
|
||||||
export class CommunitySearchResult extends SearchResult<Community> {
|
export class CommunitySearchResult extends SearchResult<Community> {
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
import { Item } from '../../../core/shared/item.model';
|
||||||
|
import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator';
|
||||||
|
|
||||||
|
@searchResultFor(Item)
|
||||||
export class ItemSearchResult extends SearchResult<Item> {
|
export class ItemSearchResult extends SearchResult<Item> {
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,11 @@ import { Component } from '@angular/core';
|
|||||||
|
|
||||||
import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator';
|
import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator';
|
||||||
|
|
||||||
import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
|
|
||||||
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
|
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
|
||||||
import { Collection } from '../../../../core/shared/collection.model';
|
import { Collection } from '../../../../core/shared/collection.model';
|
||||||
import { ViewMode } from '../../../../+search-page/search-options.model';
|
import { ViewMode } from '../../../../+search-page/search-options.model';
|
||||||
|
import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-collection-search-result-grid-element',
|
selector: 'ds-collection-search-result-grid-element',
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
import { Community } from '../../../../core/shared/community.model';
|
import { Community } from '../../../../core/shared/community.model';
|
||||||
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
||||||
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
|
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
||||||
|
|
||||||
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
||||||
import { Collection } from '../../../../core/shared/collection.model';
|
import { Collection } from '../../../../core/shared/collection.model';
|
||||||
import { ViewMode } from '../../../../+search-page/search-options.model';
|
import { ViewMode } from '../../../../+search-page/search-options.model';
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
|
||||||
import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
|
|
||||||
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
||||||
import { Community } from '../../../../core/shared/community.model';
|
import { Community } from '../../../../core/shared/community.model';
|
||||||
import { ViewMode } from '../../../../+search-page/search-options.model';
|
import { ViewMode } from '../../../../+search-page/search-options.model';
|
||||||
|
import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-search-result-list-element',
|
selector: 'ds-community-search-result-list-element',
|
||||||
|
@@ -3,7 +3,7 @@ import { Component, Inject } from '@angular/core';
|
|||||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||||
import { isEmpty, hasNoValue } from '../../empty.util';
|
import { isEmpty, hasNoValue, isNotEmpty } from '../../empty.util';
|
||||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||||
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
@@ -24,13 +24,15 @@ export class SearchResultListElementComponent<T extends SearchResult<K>, K exten
|
|||||||
|
|
||||||
getValues(keys: string[]): string[] {
|
getValues(keys: string[]): string[] {
|
||||||
const results: string[] = new Array<string>();
|
const results: string[] = new Array<string>();
|
||||||
this.object.hitHighlights.forEach(
|
if (isNotEmpty(this.object.hitHighlights)) {
|
||||||
(md: Metadatum) => {
|
this.object.hitHighlights.forEach(
|
||||||
if (keys.indexOf(md.key) > -1) {
|
(md: Metadatum) => {
|
||||||
results.push(md.value);
|
if (keys.indexOf(md.key) > -1) {
|
||||||
|
results.push(md.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
}
|
||||||
if (isEmpty(results)) {
|
if (isEmpty(results)) {
|
||||||
this.dso.filterMetadata(keys).forEach(
|
this.dso.filterMetadata(keys).forEach(
|
||||||
(md: Metadatum) => {
|
(md: Metadatum) => {
|
||||||
@@ -43,14 +45,16 @@ export class SearchResultListElementComponent<T extends SearchResult<K>, K exten
|
|||||||
|
|
||||||
getFirstValue(key: string): string {
|
getFirstValue(key: string): string {
|
||||||
let result: string;
|
let result: string;
|
||||||
this.object.hitHighlights.some(
|
if (isNotEmpty(this.object.hitHighlights)) {
|
||||||
(md: Metadatum) => {
|
this.object.hitHighlights.some(
|
||||||
if (key === md.key) {
|
(md: Metadatum) => {
|
||||||
result = md.value;
|
if (key === md.key) {
|
||||||
return true;
|
result = md.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
}
|
||||||
if (hasNoValue(result)) {
|
if (hasNoValue(result)) {
|
||||||
result = this.dso.findMetadata(key);
|
result = this.dso.findMetadata(key);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user