diff --git a/config/environment.default.js b/config/environment.default.js
index ad7be69b9e..b44da0e248 100644
--- a/config/environment.default.js
+++ b/config/environment.default.js
@@ -18,7 +18,8 @@ module.exports = {
// Caching settings
cache: {
// NOTE: how long should objects be cached for by default
- msToLive: 15 * 60 * 1000, // 15 minute
+ msToLive: 15 * 60 * 1000, // 15 minutes
+ // msToLive: 1000, // 15 minutes
control: 'max-age=60' // revalidate browser
},
// Angular Universal settings
diff --git a/package.json b/package.json
index 710f62a257..ab875fd95e 100644
--- a/package.json
+++ b/package.json
@@ -116,6 +116,7 @@
"@angular/compiler-cli": "^5.2.5",
"@ngrx/store-devtools": "^5.1.0",
"@ngtools/webpack": "^1.10.0",
+ "@types/acorn": "^4.0.3",
"@types/cookie-parser": "1.4.1",
"@types/deep-freeze": "0.1.1",
"@types/express": "^4.11.1",
diff --git a/resources/i18n/en.json b/resources/i18n/en.json
index 07f770825d..68dfcbe147 100644
--- a/resources/i18n/en.json
+++ b/resources/i18n/en.json
@@ -120,6 +120,10 @@
"dateIssued": {
"placeholder": "Date",
"head": "Date"
+ },
+ "has_content_in_original_bundle": {
+ "placeholder": "Has files",
+ "head": "Has files"
}
}
}
diff --git a/src/app/+search-page/paginated-search-options.model.ts b/src/app/+search-page/paginated-search-options.model.ts
new file mode 100644
index 0000000000..0c403af827
--- /dev/null
+++ b/src/app/+search-page/paginated-search-options.model.ts
@@ -0,0 +1,20 @@
+import { SortOptions } from '../core/cache/models/sort-options.model';
+import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
+import { isNotEmpty } from '../shared/empty.util';
+import { URLCombiner } from '../core/url-combiner/url-combiner';
+import { SearchOptions } from './search-options.model';
+
+export class PaginatedSearchOptions extends SearchOptions {
+ pagination?: PaginationComponentOptions;
+ sort?: SortOptions;
+ toRestUrl(url: string, args: string[] = []): string {
+ if (isNotEmpty(this.sort)) {
+ args.push(`sort=${this.sort.field},${this.sort.direction}`);
+ }
+ if (isNotEmpty(this.pagination)) {
+ args.push(`page=${this.pagination.currentPage - 1}`);
+ args.push(`size=${this.pagination.pageSize}`);
+ }
+ return super.toRestUrl(url, args);
+ }
+}
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html
index 114837ce65..aa71c5c24c 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html
@@ -2,26 +2,29 @@
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
index 99501f346a..c7941ec5dc 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
@@ -1,10 +1,16 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FacetValue } from '../../../search-service/facet-value.model';
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
-import { Params, Router } from '@angular/router';
+import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { SearchFilterService } from '../search-filter.service';
-import { isNotEmpty } from '../../../../shared/empty.util';
+import { hasValue, isNotEmpty } from '../../../../shared/empty.util';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { SearchService } from '../../../search-service/search.service';
+import { SearchOptions } from '../../../search-options.model';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { Subscription } from 'rxjs/Subscription';
/**
* This component renders a simple item page.
@@ -15,21 +21,43 @@ import { isNotEmpty } from '../../../../shared/empty.util';
@Component({
selector: 'ds-search-facet-filter',
styleUrls: ['./search-facet-filter.component.scss'],
- templateUrl: './search-facet-filter.component.html',
+ templateUrl: './search-facet-filter.component.html'
})
-export class SearchFacetFilterComponent implements OnInit {
- @Input() filterValues: FacetValue[];
+export class SearchFacetFilterComponent implements OnInit, OnDestroy {
@Input() filterConfig: SearchFilterConfig;
@Input() selectedValues: string[];
+ filterValues: Array>>> = [];
+ filterValues$: BehaviorSubject = new BehaviorSubject(this.filterValues);
currentPage: Observable;
filter: string;
+ pageChange = false;
+ sub: Subscription;
- constructor(private filterService: SearchFilterService, private router: Router) {
+ constructor(private searchService: SearchService, private filterService: SearchFilterService, private router: Router) {
}
ngOnInit(): void {
- this.currentPage = this.filterService.getPage(this.filterConfig.name);
+ this.currentPage = this.getCurrentPage();
+ this.currentPage.distinctUntilChanged().subscribe((page) => this.pageChange = true);
+ this.filterService.getSearchOptions().distinctUntilChanged().subscribe((options) => this.updateFilterValueList(options));
+ }
+
+ updateFilterValueList(options: SearchOptions) {
+ if (!this.pageChange) {
+ this.showFirstPageOnly();
+ }
+ this.pageChange = false;
+
+ this.unsubscribe();
+
+ this.sub = this.currentPage.distinctUntilChanged().map((page) => {
+ return this.searchService.getFacetValuesFor(this.filterConfig, page, options);
+ }).subscribe((newValues$) => {
+ this.filterValues = [...this.filterValues, newValues$];
+ this.filterValues$.next(this.filterValues);
+ });
+ // this.filterValues.subscribe((c) => c.map((a) => a.subscribe((b) => console.log(b))));
}
isChecked(value: FacetValue): Observable {
@@ -37,23 +65,7 @@ export class SearchFacetFilterComponent implements OnInit {
}
getSearchLink() {
- return this.filterService.searchLink;
- }
-
- getQueryParamsWith(value: string): Observable {
- return this.filterService.getQueryParamsWith(this.filterConfig, value);
- }
-
- getQueryParamsWithout(value: string): Observable {
- return this.filterService.getQueryParamsWithout(this.filterConfig, value);
- }
-
- get facetCount(): Observable {
- const resultCount = this.filterValues.length;
- return this.currentPage.map((page: number) => {
- const max = page * this.filterConfig.pageSize;
- return max > resultCount ? resultCount : max;
- });
+ return this.searchService.getSearchLink();
}
showMore() {
@@ -61,6 +73,7 @@ export class SearchFacetFilterComponent implements OnInit {
}
showFirstPageOnly() {
+ this.filterValues = [];
this.filterService.resetPage(this.filterConfig.name);
}
@@ -74,13 +87,39 @@ export class SearchFacetFilterComponent implements OnInit {
onSubmit(data: any) {
if (isNotEmpty(data)) {
- const sub = this.getQueryParamsWith(data[this.filterConfig.paramName]).first().subscribe((params) => {
- this.router.navigate([this.getSearchLink()], { queryParams: params }
- );
- }
- );
+ this.router.navigate([this.getSearchLink()], {
+ queryParams:
+ { [this.filterConfig.paramName]: [...this.selectedValues, data[this.filterConfig.paramName]] },
+ queryParamsHandling: 'merge'
+ });
this.filter = '';
- sub.unsubscribe();
+ }
+ }
+
+ hasValue(o: any): boolean {
+ return hasValue(o);
+ }
+
+ isLastPage(): Observable {
+ return Observable.of(false);
+ // return this.filterValues.flatMap((map) => map.pop().map((rd: RemoteData>) => rd.payload.currentPage >= rd.payload.totalPages));
+ }
+
+ getRemoveParams(value: string) {
+ return { [this.filterConfig.paramName]: this.selectedValues.filter((v) => v !== value) };
+ }
+
+ getAddParams(value: string) {
+ return { [this.filterConfig.paramName]: [...this.selectedValues, value] };
+ }
+
+ ngOnDestroy(): void {
+ this.unsubscribe();
+ }
+
+ unsubscribe(): void {
+ if (this.sub !== undefined) {
+ this.sub.unsubscribe();
}
}
}
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html
index f5acb42b6d..6cf9df9b05 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html
@@ -2,7 +2,6 @@
{{'search.filters.filter.' + filter.name + '.head'| translate}}
-
+
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
index b51a2d70fa..90d3b50786 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
@@ -23,13 +23,11 @@ import { PaginatedList } from '../../../core/data/paginated-list';
export class SearchFilterComponent implements OnInit {
@Input() filter: SearchFilterConfig;
- filterValues: Observable>>;
- constructor(private searchService: SearchService, private filterService: SearchFilterService) {
+ constructor(private filterService: SearchFilterService) {
}
ngOnInit() {
- this.filterValues = this.searchService.getFacetValuesFor(this.filter.name, '', '');
const sub = this.filterService.isFilterActive(this.filter.paramName).first().subscribe((isActive) => {
if (this.filter.isOpenByDefault || isActive) {
this.initialExpand();
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
index 8a909b6fa7..9c5e406a78 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
@@ -14,6 +14,11 @@ import { hasValue, } from '../../../shared/empty.util';
import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
import { SearchService } from '../../search-service/search.service';
import { RouteService } from '../../../shared/route.service';
+import ObjectExpression from 'rollup/dist/typings/ast/nodes/ObjectExpression';
+import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
+import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
+import { SearchOptions } from '../../search-options.model';
+import { PaginatedSearchOptions } from '../../paginated-search-options.model';
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
@@ -21,8 +26,7 @@ const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
export class SearchFilterService {
constructor(private store: Store,
- private routeService: RouteService,
- private searchService: SearchService) {
+ private routeService: RouteService) {
}
isFilterActiveWithValue(paramName: string, filterValue: string): Observable {
@@ -33,22 +37,85 @@ export class SearchFilterService {
return this.routeService.hasQueryParam(paramName);
}
- getQueryParamsWithout(filterConfig: SearchFilterConfig, value: string) {
- return this.routeService.removeQueryParameterValue(filterConfig.paramName, value);
+ getCurrentScope() {
+ return this.routeService.getQueryParameterValue('scope');
}
- getQueryParamsWith(filterConfig: SearchFilterConfig, value: string) {
- return this.routeService.addQueryParameterValue(filterConfig.paramName, value);
+ getCurrentQuery() {
+ return this.routeService.getQueryParameterValue('query');
+ }
+
+ getCurrentPagination(pagination: any = {}): Observable {
+ const page$ = this.routeService.getQueryParameterValue('page');
+ const size$ = this.routeService.getQueryParameterValue('pageSize');
+ return Observable.combineLatest(page$, size$, (page, size) => {
+ return Object.assign(new PaginationComponentOptions(), pagination, {
+ currentPage: page || 1,
+ pageSize: size || pagination.pageSize
+ });
+ });
+ }
+
+ getCurrentSort(): Observable {
+ const sortDirection$ = this.routeService.getQueryParameterValue('sortDirection');
+ const sortField$ = this.routeService.getQueryParameterValue('sortField');
+ return Observable.combineLatest(sortDirection$, sortField$, (sortDirection, sortField) => new SortOptions(sortField || undefined, SortDirection[sortDirection]));
+ }
+
+ getCurrentFilters() {
+ return this.routeService.getQueryParamsWithPrefix('f.');
+ }
+
+ getCurrentView() {
+ return this.routeService.getQueryParameterValue('view');
+ }
+
+ getPaginatedSearchOptions(defaults: any = {}): Observable {
+ return Observable.combineLatest(
+ this.getCurrentPagination(defaults.pagination),
+ this.getCurrentSort(),
+ this.getCurrentView(),
+ this.getCurrentScope(),
+ this.getCurrentQuery(),
+ this.getCurrentFilters(),
+ (pagination, sort, view, scope, query, filters) => {
+ return Object.assign(new SearchOptions(),
+ defaults,
+ {
+ pagination: pagination,
+ sort: sort,
+ view: view,
+ scope: scope,
+ query: query,
+ filters: filters
+ })
+ }
+ )
+ }
+
+ getSearchOptions(defaults: any = {}): Observable {
+ return Observable.combineLatest(
+ this.getCurrentView(),
+ this.getCurrentScope(),
+ this.getCurrentQuery(),
+ this.getCurrentFilters(),
+ (view, scope, query, filters) => {
+ return Object.assign(new SearchOptions(),
+ defaults,
+ {
+ view: view,
+ scope: scope,
+ query: query,
+ filters: filters
+ })
+ }
+ )
}
getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable {
return this.routeService.getQueryParameterValues(filterConfig.paramName);
}
- get searchLink() {
- return this.searchService.uiSearchRoute;
- }
-
isCollapsed(filterName: string): Observable {
return this.store.select(filterByNameSelector(filterName))
.map((object: SearchFilterState) => {
diff --git a/src/app/+search-page/search-filters/search-filters.component.html b/src/app/+search-page/search-filters/search-filters.component.html
index 7f375b1238..09782b68d4 100644
--- a/src/app/+search-page/search-filters/search-filters.component.html
+++ b/src/app/+search-page/search-filters/search-filters.component.html
@@ -1,5 +1,5 @@
{{"search.filters.head" | translate}}
-
+
diff --git a/src/app/+search-page/search-options.model.ts b/src/app/+search-page/search-options.model.ts
index 7f93c3ace1..4164321680 100644
--- a/src/app/+search-page/search-options.model.ts
+++ b/src/app/+search-page/search-options.model.ts
@@ -1,5 +1,5 @@
-import { SortOptions } from '../core/cache/models/sort-options.model';
-import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
+import { isNotEmpty } from '../shared/empty.util';
+import { URLCombiner } from '../core/url-combiner/url-combiner';
export enum ViewMode {
List = 'list',
@@ -7,7 +7,28 @@ export enum ViewMode {
}
export class SearchOptions {
- pagination?: PaginationComponentOptions;
- sort?: SortOptions;
view?: ViewMode = ViewMode.List;
+ scope?: string;
+ query?: string;
+ filters?: any;
+
+ toRestUrl(url: string, args: string[] = []): string {
+
+ if (isNotEmpty(this.query)) {
+ args.push(`query=${this.query}`);
+ }
+
+ if (isNotEmpty(this.scope)) {
+ args.push(`scope=${this.scope}`);
+ }
+ if (isNotEmpty(this.filters)) {
+ Object.entries(this.filters).forEach(([key, values]) => {
+ values.forEach((value) => args.push(`${key}=${value},equals`));
+ });
+ }
+ if (isNotEmpty(args)) {
+ url = new URLCombiner(url, `?${args.join('&')}`).toString();
+ }
+ return url;
+ }
}
diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts
index 9c5c9a7462..57fb02b730 100644
--- a/src/app/+search-page/search-page.component.ts
+++ b/src/app/+search-page/search-page.component.ts
@@ -15,6 +15,7 @@ import { SearchOptions, ViewMode } from './search-options.model';
import { SearchResult } from './search-result.model';
import { SearchService } from './search-service/search.service';
import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
+import { SearchFilterService } from './search-filters/search-filter/search-filter.service';
/**
* This component renders a simple item page.
@@ -36,85 +37,43 @@ export class SearchPageComponent implements OnInit, OnDestroy {
query: string;
scopeObjectRDObs: Observable
>;
- resultsRDObs: Observable> | PaginatedList>>>;
+ resultsRDObs: Observable>>>;
currentParams = {};
searchOptions: SearchOptions;
sortConfig: SortOptions;
scopeListRDObs: Observable>>;
isMobileView: Observable;
+ pageSize;
+ pageSizeOptions;
+ defaults = {
+ pagination: {
+ id: 'search-results-pagination',
+ pageSize: 10
+ },
+ query: ''
+ };
constructor(private service: SearchService,
- private route: ActivatedRoute,
private communityService: CommunityDataService,
private sidebarService: SearchSidebarService,
- private windowService: HostWindowService) {
- this.isMobileView = Observable.combineLatest(
+ private windowService: HostWindowService,
+ private filterService: SearchFilterService) {
+ this.isMobileView = Observable.combineLatest(
this.windowService.isXs(),
this.windowService.isSm(),
((isXs, isSm) => isXs || isSm)
);
this.scopeListRDObs = communityService.findAll();
- // Initial pagination config
- const pagination: PaginationComponentOptions = new PaginationComponentOptions();
- pagination.id = 'search-results-pagination';
- pagination.currentPage = 1;
- pagination.pageSize = 10;
-
- const sort: SortOptions = new SortOptions();
- this.sortConfig = sort;
- this.searchOptions = this.service.searchOptions;
}
ngOnInit(): void {
- this.sub = this.route
- .queryParams
- .subscribe((params) => {
- // Save current parameters
- this.currentParams = params;
- this.query = params.query || '';
- this.scope = params.scope;
- const page = +params.page || this.searchOptions.pagination.currentPage;
- let pageSize = +params.pageSize || this.searchOptions.pagination.pageSize;
- let pageSizeOptions: number[] = [5, 10, 20, 40, 60, 80, 100];
-
- if (isNotEmpty(params.view) && params.view === ViewMode.Grid) {
- pageSizeOptions = [12, 24, 36, 48 , 50, 62, 74, 84];
- if (pageSizeOptions.indexOf(pageSize) === -1) {
- pageSize = 12;
- }
- }
- if (isNotEmpty(params.view) && params.view === ViewMode.List) {
- if (pageSizeOptions.indexOf(pageSize) === -1) {
- pageSize = 10;
- }
- }
-
- const sortDirection = params.sortDirection || this.searchOptions.sort.direction;
- const sortField = params.sortField || this.searchOptions.sort.field;
- const pagination = Object.assign({},
- this.searchOptions.pagination,
- { currentPage: page, pageSize: pageSize, pageSizeOptions: pageSizeOptions}
- );
- const sort = Object.assign({},
- this.searchOptions.sort,
- { direction: sortDirection, field: sortField }
- );
-
- this.updateSearchResults({
- pagination: pagination,
- sort: sort
- });
- if (isNotEmpty(this.scope)) {
- this.scopeObjectRDObs = this.communityService.findById(this.scope);
- } else {
- this.scopeObjectRDObs = Observable.of(undefined);
- }
- }
- );
+ this.sub = this.filterService.getPaginatedSearchOptions(this.defaults).subscribe((options) => {
+ this.updateSearchResults(options);
+ });
}
private updateSearchResults(searchOptions) {
- this.resultsRDObs = this.service.search(this.query, this.scope, searchOptions);
+ this.resultsRDObs = this.service.search(searchOptions);
this.searchOptions = searchOptions;
}
diff --git a/src/app/+search-page/search-service/filter-type.model.ts b/src/app/+search-page/search-service/filter-type.model.ts
index fba0edfac4..354ca87f98 100644
--- a/src/app/+search-page/search-service/filter-type.model.ts
+++ b/src/app/+search-page/search-service/filter-type.model.ts
@@ -1,5 +1,6 @@
export enum FilterType {
text,
- range,
- hierarchy
+ date,
+ hierarchical,
+ standard
}
diff --git a/src/app/+search-page/search-service/search-filter-config.model.ts b/src/app/+search-page/search-service/search-filter-config.model.ts
index 1464300daa..2b77ef6768 100644
--- a/src/app/+search-page/search-service/search-filter-config.model.ts
+++ b/src/app/+search-page/search-service/search-filter-config.model.ts
@@ -1,17 +1,27 @@
-import { FilterType } from './filter-type.model';
+ import { FilterType } from './filter-type.model';
+ import { autoserialize, autoserializeAs } from 'cerialize';
-export class SearchFilterConfig {
+ export class SearchFilterConfig {
- name: string;
- type: FilterType;
- hasFacets: boolean;
- pageSize = 5;
- isOpenByDefault: boolean;
- /**
- * Name of this configuration that can be used in a url
- * @returns Parameter name
- */
- get paramName(): string {
- return 'f.' + this.name;
+ @autoserialize
+ name: string;
+
+ @autoserializeAs(String, 'facetType')
+ type: FilterType;
+
+ @autoserialize
+ hasFacets: boolean;
+
+ // @autoserializeAs(String, 'facetLimit') - uncomment when fixed in rest
+ pageSize = 5;
+
+ @autoserialize
+ isOpenByDefault: boolean;
+ /**
+ * Name of this configuration that can be used in a url
+ * @returns Parameter name
+ */
+ get paramName(): string {
+ return 'f.' + this.name;
+ }
}
-}
diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts
index b20d65cf53..2ef69e8578 100644
--- a/src/app/+search-page/search-service/search.service.ts
+++ b/src/app/+search-page/search-service/search.service.ts
@@ -6,7 +6,8 @@ import { ViewMode } from '../../+search-page/search-options.model';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import { SortOptions } from '../../core/cache/models/sort-options.model';
import {
- FacetValueMapSuccessResponse, FacetValueSuccessResponse,
+ FacetConfigSuccessResponse,
+ FacetValueSuccessResponse,
SearchSuccessResponse
} from '../../core/cache/response-cache.models';
import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer';
@@ -34,26 +35,17 @@ 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 { FacetResponseParsingService } from '../../core/data/facet-response-parsing.service';
-
-function shuffle(array: any[]) {
- let i = 0;
- let j = 0;
- let temp = null;
-
- for (i = array.length - 1; i > 0; i -= 1) {
- j = Math.floor(Math.random() * (i + 1));
- temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- }
- return array;
-}
+import { FacetValueResponseParsingService } from '../../core/data/facet-value-response-parsing.service';
+import { FacetConfigResponseParsingService } from '../../core/data/facet-config-response-parsing.service';
+import { SearchFilterService } from '../search-filters/search-filter/search-filter.service';
+import { PaginatedSearchOptions } from '../paginated-search-options.model';
@Injectable()
export class SearchService implements OnDestroy {
private searchLinkPath = 'discover/search/objects';
- private facetLinkPath = 'discover/search/facets';
+ private facetValueLinkPath = 'discover/search/facets';
+ private facetValueLinkPathPrefix = 'discover/facets/';
+ private facetConfigLinkPath = 'discover/facets';
private sub;
uiSearchRoute = '/search';
@@ -62,7 +54,7 @@ export class SearchService implements OnDestroy {
// Object.assign(new SearchFilterConfig(),
// {
// name: 'scope',
- // type: FilterType.hierarchy,
+ // type: FilterType.hierarchical,
// hasFacets: true,
// isOpenByDefault: true
// }),
@@ -76,7 +68,7 @@ export class SearchService implements OnDestroy {
Object.assign(new SearchFilterConfig(),
{
name: 'dateIssued',
- type: FilterType.range,
+ type: FilterType.date,
hasFacets: true,
isOpenByDefault: false
}),
@@ -95,7 +87,6 @@ export class SearchService implements OnDestroy {
private route: ActivatedRoute,
protected responseCache: ResponseCacheService,
protected requestService: RequestService,
- private routeService: RouteService,
private rdb: RemoteDataBuildService,
private halService: HALEndpointService) {
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
@@ -103,36 +94,15 @@ export class SearchService implements OnDestroy {
pagination.currentPage = 1;
pagination.pageSize = 10;
const sort: SortOptions = new SortOptions();
- this.searchOptions = { pagination: pagination, sort: sort };
- // this.searchOptions = new BehaviorSubject(searchOptions);
+ this.searchOptions = Object.assign(new SearchOptions(), { pagination: pagination, sort: sort });
}
- search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable> | PaginatedList>>> {
+ search(searchOptions?: PaginatedSearchOptions): Observable>>> {
const requestObs = this.halService.getEndpoint(this.searchLinkPath).pipe(
map((url: string) => {
- const args: string[] = [];
-
- if (isNotEmpty(query)) {
- args.push(`query=${query}`);
+ if (hasValue(searchOptions)) {
+ url = searchOptions.toRestUrl(url);
}
-
- if (isNotEmpty(scopeId)) {
- args.push(`scope=${scopeId}`);
- }
-
- if (isNotEmpty(searchOptions)) {
- if (isNotEmpty(searchOptions.sort)) {
- args.push(`sort=${searchOptions.sort.field},${searchOptions.sort.direction}`);
- }
- if (isNotEmpty(searchOptions.pagination)) {
- args.push(`page=${searchOptions.pagination.currentPage - 1}`);
- args.push(`size=${searchOptions.pagination.pageSize}`);
- }
- }
- if (isNotEmpty(args)) {
- url = new URLCombiner(url, `?${args.join('&')}`).toString();
- }
-
const request = new GetRequest(this.requestService.generateRequestId(), url);
return Object.assign(request, {
getResponseParser(): GenericConstructor {
@@ -183,55 +153,25 @@ export class SearchService implements OnDestroy {
});
});
- const pageInfoObs: Observable = 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 pageInfoObs: Observable = responseCacheObs.pipe(
+ map((entry: ResponseCacheEntry) => entry.response),
+ map((response: FacetValueSuccessResponse) => response.pageInfo)
+ );
const payloadObs = Observable.combineLatest(tDomainListObs, pageInfoObs, (tDomainList, pageInfo) => {
- if (hasValue(pageInfo)) {
- return new PaginatedList(pageInfo, tDomainList);
- } else {
- return tDomainList;
- }
+ return new PaginatedList(pageInfo, tDomainList);
});
return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
}
- getConfig(): Observable> {
- const requestPending = false;
- const responsePending = false;
- const isSuccessful = true;
- const error = undefined;
- return Observable.of(new RemoteData(
- requestPending,
- responsePending,
- isSuccessful,
- error,
- this.config
- ));
- }
-
- getFacetValuesFor(searchFilterConfigName: string, query: string, scopeId: string): Observable>> {
- const requestObs = this.halService.getEndpoint(this.facetLinkPath).pipe(
+ getConfig(scope?: string): Observable> {
+ const requestObs = this.halService.getEndpoint(this.facetConfigLinkPath).pipe(
map((url: string) => {
const args: string[] = [];
- if (isNotEmpty(query)) {
- args.push(`query=${query}`);
- }
-
- if (isNotEmpty(scopeId)) {
- args.push(`scope=${scopeId}`);
+ if (isNotEmpty(scope)) {
+ args.push(`scope=${scope}`);
}
if (isNotEmpty(args)) {
@@ -241,7 +181,7 @@ export class SearchService implements OnDestroy {
const request = new GetRequest(this.requestService.generateRequestId(), url);
return Object.assign(request, {
getResponseParser(): GenericConstructor {
- return FacetResponseParsingService;
+ return FacetConfigResponseParsingService;
}
});
}),
@@ -257,56 +197,56 @@ export class SearchService implements OnDestroy {
);
// get search results from response cache
- const facetValueResponseObs: Observable = responseCacheObs.pipe(
+ const facetConfigObs: Observable = responseCacheObs.pipe(
map((entry: ResponseCacheEntry) => entry.response),
- map((response: FacetValueMapSuccessResponse) => response.results[searchFilterConfigName])
+ map((response: FacetConfigSuccessResponse) => response.results)
+ );
+
+ return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, facetConfigObs);
+ }
+
+ getFacetValuesFor(filterConfig: SearchFilterConfig, valuePage: number, searchOptions?: SearchOptions): Observable>> {
+ console.log('facetvalues');
+ const requestObs = this.halService.getEndpoint(this.facetValueLinkPathPrefix + filterConfig.name).pipe(
+ map((url: string) => {
+ const args: string[] = [`page=${valuePage - 1}`, `size=${filterConfig.pageSize}`];
+ if (hasValue(searchOptions)) {
+ url = searchOptions.toRestUrl(url, args);
+ }
+ const request = new GetRequest(this.requestService.generateRequestId(), url);
+ return Object.assign(request, {
+ getResponseParser(): GenericConstructor {
+ return FacetValueResponseParsingService;
+ }
+ });
+ }),
+ tap((request: RestRequest) => this.requestService.configure(request)),
+ );
+
+ const requestEntryObs = requestObs.pipe(
+ flatMap((request: RestRequest) => this.requestService.getByHref(request.href))
+ );
+
+ const responseCacheObs = requestObs.pipe(
+ flatMap((request: RestRequest) => this.responseCache.get(request.href))
);
// get search results from response cache
- const facetValueObs: Observable = facetValueResponseObs.pipe(
+ const facetValueObs: Observable = responseCacheObs.pipe(
+ map((entry: ResponseCacheEntry) => entry.response),
map((response: FacetValueSuccessResponse) => response.results)
);
- const pageInfoObs: Observable = facetValueResponseObs.pipe(
- map((response: FacetValueSuccessResponse) => { console.log(response); return response.pageInfo})
+ const pageInfoObs: Observable = responseCacheObs.pipe(
+ map((entry: ResponseCacheEntry) => entry.response),
+ map((response: FacetValueSuccessResponse) => response.pageInfo)
);
- const payloadObs = Observable.combineLatest(facetValueObs, pageInfoObs, (facetValue, pageInfo) => {
- if (hasValue(pageInfo)) {
- return new PaginatedList(pageInfo, facetValue);
- } else {
- return facetValue;
- }
- });
- return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
- // const filterConfig = this.config.find((config: SearchFilterConfig) => config.name === searchFilterConfigName);
- // return this.routeService.getQueryParameterValues(filterConfig.paramName).map((selectedValues: string[]) => {
- // const payload: FacetValue[] = [];
- // const totalFilters = 13;
- // for (let i = 0; i < totalFilters; i++) {
- // const value = searchFilterConfigName + ' ' + (i + 1);
- // if (!selectedValues.includes(value)) {
- // payload.push({
- // value: value,
- // count: Math.floor(Math.random() * 20) + 20 * (totalFilters - i), // make sure first results have the highest (random) count
- // search: (decodeURI(this.router.url) + (this.router.url.includes('?') ? '&' : '?') + filterConfig.paramName + '=' + value)
- // }
- // );
- // }
- // }
- // const requestPending = false;
- // const responsePending = false;
- // const isSuccessful = true;
- // const error = undefined;
- // return new RemoteData(
- // requestPending,
- // responsePending,
- // isSuccessful,
- // error,
- // payload
- // )
- // }
- // )
+ const payloadObs = Observable.combineLatest(facetValueObs, pageInfoObs, (facetValue, pageInfo) => {
+ return new PaginatedList(pageInfo, facetValue);
+ });
+
+ return this.rdb.toRemoteDataObservable(requestEntryObs, responseCacheObs, payloadObs);
}
getViewMode(): Observable {
diff --git a/src/app/+search-page/search-settings/search-settings.component.ts b/src/app/+search-page/search-settings/search-settings.component.ts
index bc1fb096fd..cc22da7176 100644
--- a/src/app/+search-page/search-settings/search-settings.component.ts
+++ b/src/app/+search-page/search-settings/search-settings.component.ts
@@ -3,6 +3,7 @@ import { SearchService } from '../search-service/search.service';
import { SearchOptions, ViewMode } from '../search-options.model';
import { SortDirection } from '../../core/cache/models/sort-options.model';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
+import { PaginatedSearchOptions } from '../paginated-search-options.model';
@Component({
selector: 'ds-search-settings',
@@ -11,7 +12,7 @@ import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
})
export class SearchSettingsComponent implements OnInit {
- @Input() searchOptions: SearchOptions;
+ @Input() searchOptions: PaginatedSearchOptions;
/**
* Declare SortDirection enumeration to use it in the template
*/
diff --git a/src/app/core/cache/response-cache.models.ts b/src/app/core/cache/response-cache.models.ts
index 5da328931b..f061e78e6c 100644
--- a/src/app/core/cache/response-cache.models.ts
+++ b/src/app/core/cache/response-cache.models.ts
@@ -4,6 +4,7 @@ import { PageInfo } from '../shared/page-info.model';
import { BrowseDefinition } from '../shared/browse-definition.model';
import { ConfigObject } from '../shared/config/config.model';
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
+import { SearchFilterConfig } from '../../+search-page/search-service/search-filter-config.model';
/* tslint:disable:max-classes-per-file */
export class RestResponse {
@@ -33,6 +34,15 @@ export class SearchSuccessResponse extends RestResponse {
}
}
+export class FacetConfigSuccessResponse extends RestResponse {
+ constructor(
+ public results: SearchFilterConfig[],
+ public statusCode: string
+ ) {
+ super(true, statusCode);
+ }
+}
+
export class FacetValueMap {
[name: string]: FacetValueSuccessResponse
}
diff --git a/src/app/core/core.effects.ts b/src/app/core/core.effects.ts
index 7cda10b4ae..ebb87bf1ee 100644
--- a/src/app/core/core.effects.ts
+++ b/src/app/core/core.effects.ts
@@ -8,5 +8,5 @@ export const coreEffects = [
ResponseCacheEffects,
RequestEffects,
ObjectCacheEffects,
- UUIDIndexEffects,
+ UUIDIndexEffects
];
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 764e21efba..86abf87d62 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -41,7 +41,9 @@ import { SubmissionFormsConfigService } from './config/submission-forms-config.s
import { SubmissionSectionsConfigService } from './config/submission-sections-config.service';
import { UUIDService } from './shared/uuid.service';
import { HALEndpointService } from './shared/hal-endpoint.service';
-import { FacetResponseParsingService } from './data/facet-response-parsing.service';
+import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service';
+import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service';
+import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service';
const IMPORTS = [
CommonModule,
@@ -73,7 +75,9 @@ const PROVIDERS = [
RequestService,
ResponseCacheService,
EndpointMapResponseParsingService,
- FacetResponseParsingService,
+ FacetValueResponseParsingService,
+ FacetValueMapResponseParsingService,
+ FacetConfigResponseParsingService,
DebugResponseParsingService,
SearchResponseParsingService,
ServerResponseService,
diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts
index d8a4221420..9d6a5851e5 100644
--- a/src/app/core/data/base-response-parsing.service.ts
+++ b/src/app/core/data/base-response-parsing.service.ts
@@ -117,9 +117,13 @@ export abstract class BaseResponseParsingService {
this.objectCache.add(co, this.EnvConfig.cache.msToLive, requestHref);
}
- protected processPageInfo(pageObj: any): PageInfo {
+ processPageInfo(pageObj: any): PageInfo {
if (isNotEmpty(pageObj)) {
- return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
+ const pageInfoObject = new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
+ if (pageInfoObject.currentPage >= 0) {
+ Object.assign(pageInfoObject, { currentPage: pageInfoObject.currentPage + 1 });
+ }
+ return pageInfoObject
} else {
return undefined;
}
diff --git a/src/app/core/data/facet-config-response-parsing.service.ts b/src/app/core/data/facet-config-response-parsing.service.ts
new file mode 100644
index 0000000000..b0d89fb03e
--- /dev/null
+++ b/src/app/core/data/facet-config-response-parsing.service.ts
@@ -0,0 +1,32 @@
+import { Inject, Injectable } from '@angular/core';
+import {
+ FacetConfigSuccessResponse,
+ RestResponse
+} from '../cache/response-cache.models';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { SearchFilterConfig } from '../../+search-page/search-service/search-filter-config.model';
+import { BaseResponseParsingService } from './base-response-parsing.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { GLOBAL_CONFIG } from '../../../config';
+
+@Injectable()
+export class FacetConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
+ objectFactory = {};
+ toCache = false;
+ constructor(
+ @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
+ protected objectCache: ObjectCacheService,
+ ) { super();
+ }
+ parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
+
+ const config = data.payload._embedded.facets;
+ const serializer = new DSpaceRESTv2Serializer(SearchFilterConfig);
+ const facetConfig = serializer.deserializeArray(config);
+ return new FacetConfigSuccessResponse(facetConfig, data.statusCode);
+ }
+}
diff --git a/src/app/core/data/facet-response-parsing.service.ts b/src/app/core/data/facet-value-map-response-parsing.service.ts
similarity index 68%
rename from src/app/core/data/facet-response-parsing.service.ts
rename to src/app/core/data/facet-value-map-response-parsing.service.ts
index 8295d026a3..dfd72c0cc5 100644
--- a/src/app/core/data/facet-response-parsing.service.ts
+++ b/src/app/core/data/facet-value-map-response-parsing.service.ts
@@ -1,4 +1,4 @@
-import { Injectable } from '@angular/core';
+import { Inject, Injectable } from '@angular/core';
import {
FacetValueMap,
FacetValueMapSuccessResponse,
@@ -12,9 +12,22 @@ import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.seriali
import { PageInfo } from '../shared/page-info.model';
import { isNotEmpty } from '../../shared/empty.util';
import { FacetValue } from '../../+search-page/search-service/facet-value.model';
+import { BaseResponseParsingService } from './base-response-parsing.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { GLOBAL_CONFIG } from '../../../config';
@Injectable()
-export class FacetResponseParsingService implements ResponseParsingService {
+export class FacetValueMapResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
+ objectFactory = {};
+ toCache = false;
+
+ constructor(
+ @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
+ protected objectCache: ObjectCacheService,
+ ) { super();
+ }
+
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
const payload = data.payload;
@@ -30,12 +43,4 @@ export class FacetResponseParsingService implements ResponseParsingService {
return new FacetValueMapSuccessResponse(facetMap, data.statusCode);
}
-
- protected processPageInfo(pageObj: any): PageInfo {
- if (isNotEmpty(pageObj)) {
- return new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
- } else {
- return undefined;
- }
- }
}
diff --git a/src/app/core/data/facet-value-response-parsing.service.ts b/src/app/core/data/facet-value-response-parsing.service.ts
new file mode 100644
index 0000000000..17f0730566
--- /dev/null
+++ b/src/app/core/data/facet-value-response-parsing.service.ts
@@ -0,0 +1,38 @@
+import { Inject, Injectable } from '@angular/core';
+import {
+ FacetValueMap,
+ FacetValueMapSuccessResponse,
+ FacetValueSuccessResponse,
+ RestResponse
+} from '../cache/response-cache.models';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { PageInfo } from '../shared/page-info.model';
+import { isNotEmpty } from '../../shared/empty.util';
+import { FacetValue } from '../../+search-page/search-service/facet-value.model';
+import { BaseResponseParsingService } from './base-response-parsing.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { GLOBAL_CONFIG } from '../../../config';
+import { GlobalConfig } from '../../../config/global-config.interface';
+
+@Injectable()
+export class FacetValueResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
+ objectFactory = {};
+ toCache = false;
+ constructor(
+ @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
+ protected objectCache: ObjectCacheService,
+ ) { super();
+ }
+ parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
+ const payload = data.payload;
+
+ const serializer = new DSpaceRESTv2Serializer(FacetValue);
+ const values = payload._embedded.values.map((value) => {value.search = value._links.search.href; return value;});
+
+ const facetValues = serializer.deserializeArray(values);
+ return new FacetValueSuccessResponse(facetValues, data.statusCode, this.processPageInfo(data.payload.page));
+ }
+}
diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts
index f1d076927d..7e4a57f84e 100644
--- a/src/app/core/data/paginated-list.ts
+++ b/src/app/core/data/paginated-list.ts
@@ -1,15 +1,17 @@
import { PageInfo } from '../shared/page-info.model';
+import { hasValue } from '../../shared/empty.util';
export class PaginatedList {
- constructor(
- private pageInfo: PageInfo,
- public page: T[]
- ) {
+ constructor(private pageInfo: PageInfo,
+ public page: T[]) {
}
get elementsPerPage(): number {
- return this.pageInfo.elementsPerPage;
+ if (hasValue(this.pageInfo)) {
+ return this.pageInfo.elementsPerPage;
+ }
+ return this.page.length;
}
set elementsPerPage(value: number) {
@@ -17,7 +19,10 @@ export class PaginatedList {
}
get totalElements(): number {
- return this.pageInfo.totalElements;
+ if (hasValue(this.pageInfo)) {
+ return this.pageInfo.totalElements;
+ }
+ return this.page.length;
}
set totalElements(value: number) {
@@ -25,7 +30,10 @@ export class PaginatedList {
}
get totalPages(): number {
- return this.pageInfo.totalPages;
+ if (hasValue(this.pageInfo)) {
+ return this.pageInfo.totalPages;
+ }
+ return 1;
}
set totalPages(value: number) {
@@ -33,7 +41,11 @@ export class PaginatedList {
}
get currentPage(): number {
- return this.pageInfo.currentPage;
+ if (hasValue(this.pageInfo)) {
+ return this.pageInfo.currentPage;
+ }
+ return 1;
+
}
set currentPage(value: number) {
diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts
index 583d63ec9d..927c5ff010 100644
--- a/src/app/core/data/search-response-parsing.service.ts
+++ b/src/app/core/data/search-response-parsing.service.ts
@@ -56,14 +56,6 @@ export class SearchResponseParsingService implements ResponseParsingService {
}));
payload.objects = objects;
const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
- 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;
- }
+ return new SearchSuccessResponse(deserialized, data.statusCode, this.dsoParser.processPageInfo(data.payload.page));
}
}
diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts
index b9bb1d587c..c81c3c792d 100644
--- a/src/app/core/shared/hal-endpoint.service.ts
+++ b/src/app/core/shared/hal-endpoint.service.ts
@@ -1,12 +1,12 @@
import { Observable } from 'rxjs/Observable';
-import { distinctUntilChanged, map, flatMap, startWith } from 'rxjs/operators';
+import { distinctUntilChanged, map, flatMap, startWith, tap } from 'rxjs/operators';
import { RequestService } from '../data/request.service';
import { ResponseCacheService } from '../cache/response-cache.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { EndpointMap, EndpointMapSuccessResponse } from '../cache/response-cache.models';
import { EndpointMapRequest } from '../data/request.models';
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
-import { isEmpty, isNotEmpty } from '../../shared/empty.util';
+import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
import { Inject, Injectable } from '@angular/core';
import { GLOBAL_CONFIG } from '../../../config';
@@ -21,6 +21,7 @@ export class HALEndpointService {
@Inject(GLOBAL_CONFIG) private EnvConfig: GlobalConfig) {
}
+
protected getRootHref(): string {
return new RESTURLCombiner(this.EnvConfig, '/').toString();
}
@@ -34,23 +35,35 @@ export class HALEndpointService {
this.requestService.configure(request);
return this.responseCache.get(request.href)
.map((entry: ResponseCacheEntry) => entry.response)
- .filter((response: EndpointMapSuccessResponse) => isNotEmpty(response) && isNotEmpty(response.endpointMap))
+ .filter((response: EndpointMapSuccessResponse) => isNotEmpty(response))
.map((response: EndpointMapSuccessResponse) => response.endpointMap)
.distinctUntilChanged();
}
public getEndpoint(linkPath: string): Observable {
- return this.getEndpointAt(...linkPath.split('/'));
+ const test = this.getEndpointAt(...linkPath.split('/'));
+ // test.subscribe((test) => console.log(linkPath, test));
+ return test;
}
private getEndpointAt(...path: string[]): Observable {
if (isEmpty(path)) {
path = ['/'];
}
+ let currentPath;
const pipeArguments = path
- .map((subPath: string) => [
+ .map((subPath: string, index: number) => [
flatMap((href: string) => this.getEndpointMapAt(href)),
- map((endpointMap: EndpointMap) => endpointMap[subPath]),
+ map((endpointMap: EndpointMap) => {
+ if (hasValue(endpointMap) && hasValue(endpointMap[subPath])) {
+ currentPath = endpointMap[subPath];
+ return endpointMap[subPath];
+ } else {
+ /*TODO remove if/else block once the rest response contains _links for facets*/
+ currentPath += '/' + subPath;
+ return currentPath;
+ }
+ }),
])
.reduce((combined, thisElement) => [...combined, ...thisElement], []);
return Observable.of(this.getRootHref()).pipe(...pipeArguments, distinctUntilChanged());
diff --git a/src/app/shared/route.service.spec.ts b/src/app/shared/route.service.spec.ts
index 10bd147e1d..00b7d78be6 100644
--- a/src/app/shared/route.service.spec.ts
+++ b/src/app/shared/route.service.spec.ts
@@ -69,12 +69,12 @@ describe('RouteService', () => {
describe('addQueryParameterValue', () => {
it('should return a list of values that contains the added value when a new value is added and the parameter did not exist yet', () => {
- service.addQueryParameterValue(nonExistingParamName, nonExistingParamValue).subscribe((params) => {
+ service.resolveRouteWithParameterValue(nonExistingParamName, nonExistingParamValue).subscribe((params) => {
expect(params[nonExistingParamName]).toContain(nonExistingParamValue);
});
});
it('should return a list of values that contains the existing values and the added value when a new value is added and the parameter already has values', () => {
- service.addQueryParameterValue(paramName1, nonExistingParamValue).subscribe((params) => {
+ service.resolveRouteWithParameterValue(paramName1, nonExistingParamValue).subscribe((params) => {
const values = params[paramName1];
expect(values).toContain(paramValue1);
expect(values).toContain(nonExistingParamValue);
@@ -84,7 +84,7 @@ describe('RouteService', () => {
describe('removeQueryParameterValue', () => {
it('should return a list of values that does not contain the removed value when the parameter value exists', () => {
- service.removeQueryParameterValue(paramName2, paramValue2a).subscribe((params) => {
+ service.resolveRouteWithoutParameterValue(paramName2, paramValue2a).subscribe((params) => {
const values = params[paramName2];
expect(values).toContain(paramValue2b);
expect(values).not.toContain(paramValue2a);
@@ -92,7 +92,7 @@ describe('RouteService', () => {
});
it('should return a list of values that does contain all existing values when the removed parameter does not exist', () => {
- service.removeQueryParameterValue(paramName2, nonExistingParamValue).subscribe((params) => {
+ service.resolveRouteWithoutParameterValue(paramName2, nonExistingParamValue).subscribe((params) => {
const values = params[paramName2];
expect(values).toContain(paramValue2a);
expect(values).toContain(paramValue2b);
@@ -100,15 +100,15 @@ describe('RouteService', () => {
});
});
- describe('removeQueryParameter', () => {
+ describe('getWithoutParameter', () => {
it('should return a list of values that does not contain any values for the parameter anymore when the parameter exists', () => {
- service.removeQueryParameter(paramName2).subscribe((params) => {
+ service.resolveRouteWithoutParameter(paramName2).subscribe((params) => {
const values = params[paramName2];
expect(values).toEqual({});
});
});
it('should return a list of values that does not contain any values for the parameter when the parameter does not exist', () => {
- service.removeQueryParameter(nonExistingParamName).subscribe((params) => {
+ service.resolveRouteWithoutParameter(nonExistingParamName).subscribe((params) => {
const values = params[nonExistingParamName];
expect(values).toEqual({});
});
diff --git a/src/app/shared/route.service.ts b/src/app/shared/route.service.ts
index f24fa0d00d..10a7eaecb9 100644
--- a/src/app/shared/route.service.ts
+++ b/src/app/shared/route.service.ts
@@ -1,6 +1,9 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, convertToParamMap, Params, } from '@angular/router';
+import {
+ ActivatedRoute, convertToParamMap, NavigationExtras, Params,
+ Router,
+} from '@angular/router';
import { isNotEmpty } from './empty.util';
@Injectable()
@@ -10,7 +13,7 @@ export class RouteService {
}
getQueryParameterValues(paramName: string): Observable {
- return this.route.queryParamMap.map((map) => map.getAll(paramName));
+ return this.route.queryParamMap.map((map) => [...map.getAll(paramName)]);
}
getQueryParameterValue(paramName: string): Observable {
@@ -25,31 +28,16 @@ export class RouteService {
return this.route.queryParamMap.map((map) => map.getAll(paramName).indexOf(paramValue) > -1);
}
- addQueryParameterValue(paramName: string, paramValue: string): Observable {
- return this.route.queryParams.map((currentParams) => {
- const newParam = {};
- newParam[paramName] = [...convertToParamMap(currentParams).getAll(paramName), paramValue];
- return Object.assign({}, currentParams, newParam);
- });
- }
-
- removeQueryParameterValue(paramName: string, paramValue: string): Observable {
- return this.route.queryParams.map((currentParams) => {
- const newParam = {};
- const currentFilterParams = convertToParamMap(currentParams).getAll(paramName);
- if (isNotEmpty(currentFilterParams)) {
- newParam[paramName] = currentFilterParams.filter((param) => (param !== paramValue));
- }
- return Object.assign({}, currentParams, newParam);
- });
- }
-
- removeQueryParameter(paramName: string): Observable {
- return this.route.queryParams.map((currentParams) => {
- const newParam = {};
- newParam[paramName] = {};
- return Object.assign({}, currentParams, newParam);
- });
-
+ getQueryParamsWithPrefix(prefix: string): Observable {
+ return this.route.queryParamMap
+ .map((map) => {
+ const params = {};
+ map.keys
+ .filter((key) => key.startsWith(prefix))
+ .forEach((key) => {
+ params[key] = [...map.getAll(key)];
+ });
+ return params;
+ });
}
}
diff --git a/src/tsconfig.test.json b/src/tsconfig.test.json
index 712ad1ab1c..079eabc561 100644
--- a/src/tsconfig.test.json
+++ b/src/tsconfig.test.json
@@ -1,4 +1,4 @@
-{
+yarn add{
"extends": "../tsconfig.json",
"compilerOptions": {
"sourceMap": true
diff --git a/yarn.lock b/yarn.lock
index b6e461e9b6..e6e0aedf55 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -122,6 +122,12 @@
version "2.0.1"
resolved "https://registry.yarnpkg.com/@ngx-translate/http-loader/-/http-loader-2.0.1.tgz#aa67788e64bfa8652691a77b022b3b4031209113"
+"@types/acorn@^4.0.3":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd"
+ dependencies:
+ "@types/estree" "*"
+
"@types/body-parser@*":
version "1.16.8"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.16.8.tgz#687ec34140624a3bec2b1a8ea9268478ae8f3be3"
@@ -139,6 +145,10 @@
version "0.1.1"
resolved "https://registry.yarnpkg.com/@types/deep-freeze/-/deep-freeze-0.1.1.tgz#0e1ee6ceee06f51baeb663deec0bb7780bd72827"
+"@types/estree@*":
+ version "0.0.38"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2"
+
"@types/events@*":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-1.1.0.tgz#93b1be91f63c184450385272c47b6496fd028e02"