finished entity search endpoints

This commit is contained in:
lotte
2018-07-06 13:59:02 +02:00
parent d06e8d93dc
commit cef2ea827b
15 changed files with 97 additions and 13 deletions

View File

@@ -145,6 +145,24 @@
} }
}, },
"search": { "search": {
"journal": {
"title": "DSpace Angular :: Journal Search",
"results": {
"head": "Journal Search Results"
}
},
"person": {
"title": "DSpace Angular :: Person Search",
"results": {
"head": "Person Search Results"
}
},
"publication": {
"title": "DSpace Angular :: Publication Search",
"results": {
"head": "Publication Search Results"
}
},
"title": "DSpace Angular :: Search", "title": "DSpace Angular :: Search",
"description": "", "description": "",
"form": { "form": {

View File

@@ -0,0 +1,18 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class FilteredSearchPageGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
const filter = route.params.filter;
const newTitle = route.data.title + filter + '.title';
route.data = { title: newTitle };
return true;
}
}

View File

@@ -10,6 +10,7 @@ import {
import { SearchFiltersState } from './search-filter.reducer'; import { SearchFiltersState } from './search-filter.reducer';
import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
import { FilterType } from '../../search-service/filter-type.model'; import { FilterType } from '../../search-service/filter-type.model';
import { SearchFixedFilterService } from './search-fixed-filter.service';
describe('SearchFilterService', () => { describe('SearchFilterService', () => {
let service: SearchFilterService; let service: SearchFilterService;
@@ -21,6 +22,12 @@ describe('SearchFilterService', () => {
isOpenByDefault: false, isOpenByDefault: false,
pageSize: 2 pageSize: 2
}); });
const mockFixedFilterService: SearchFixedFilterService = {
getQueryByFilterName: (filter: string) => {
return Observable.of(undefined)
}
} as SearchFixedFilterService
const value1 = 'random value'; const value1 = 'random value';
// const value2 = 'another value'; // const value2 = 'another value';
const store: Store<SearchFiltersState> = jasmine.createSpyObj('store', { const store: Store<SearchFiltersState> = jasmine.createSpyObj('store', {
@@ -50,7 +57,7 @@ describe('SearchFilterService', () => {
}; };
beforeEach(() => { beforeEach(() => {
service = new SearchFilterService(store, routeServiceStub); service = new SearchFilterService(store, routeServiceStub, mockFixedFilterService);
}); });
describe('when the initialCollapse method is triggered', () => { describe('when the initialCollapse method is triggered', () => {

View File

@@ -12,6 +12,7 @@ import { ResponseParsingService } from '../../../core/data/parsing.service';
import { GenericConstructor } from '../../../core/shared/generic-constructor'; import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { FilteredDiscoveryPageResponseParsingService } from '../../../core/data/filtered-discovery-page-response-parsing.service'; import { FilteredDiscoveryPageResponseParsingService } from '../../../core/data/filtered-discovery-page-response-parsing.service';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { configureRequest } from '../../../core/shared/operators';
@Injectable() @Injectable()
export class SearchFixedFilterService { export class SearchFixedFilterService {
@@ -30,12 +31,14 @@ export class SearchFixedFilterService {
map((url: string) => { map((url: string) => {
url += ('/' + filterName); url += ('/' + filterName);
const request = new GetRequest(this.requestService.generateRequestId(), url); const request = new GetRequest(this.requestService.generateRequestId(), url);
console.log(url);
return Object.assign(request, { return Object.assign(request, {
getResponseParser(): GenericConstructor<ResponseParsingService> { getResponseParser(): GenericConstructor<ResponseParsingService> {
return FilteredDiscoveryPageResponseParsingService; return FilteredDiscoveryPageResponseParsingService;
} }
}); });
}), }),
configureRequest(this.requestService)
); );
const responseCacheObs = requestObs.pipe( const responseCacheObs = requestObs.pipe(

View File

@@ -3,12 +3,13 @@ import { RouterModule } from '@angular/router';
import { SearchPageComponent } from './search-page.component'; import { SearchPageComponent } from './search-page.component';
import { FilteredSearchPageComponent } from './filtered-search-page.component'; import { FilteredSearchPageComponent } from './filtered-search-page.component';
import { FilteredSearchPageGuard } from './filtered-search-page.guard';
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild([ RouterModule.forChild([
{ path: '', component: SearchPageComponent, data: { title: 'search.title' } }, { path: '', component: SearchPageComponent, data: { title: 'search.title' } },
{ path: ':filter', component: FilteredSearchPageComponent, data: { title: 'search.title.:filter' } } { path: ':filter', component: FilteredSearchPageComponent, canActivate: [FilteredSearchPageGuard], data: { title: 'search.' }}
]) ])
] ]
}) })

View File

@@ -30,7 +30,7 @@
</button> </button>
</div> </div>
<ds-search-results [searchResults]="resultsRD$ | async" <ds-search-results [searchResults]="resultsRD$ | async"
[searchConfig]="searchOptions$ | async" [sortConfig]="sortConfig"></ds-search-results> [searchConfig]="searchOptions$ | async" [sortConfig]="sortConfig" [fixedFilter]="fixedFilter | async"></ds-search-results>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -47,7 +47,7 @@ export class SearchPageComponent implements OnInit {
query: '', query: '',
scope: '' scope: ''
}; };
title; fixedFilter;
constructor(protected service: SearchService, constructor(protected service: SearchService,
protected communityService: CommunityDataService, protected communityService: CommunityDataService,
@@ -68,6 +68,7 @@ export class SearchPageComponent implements OnInit {
this.resultsRD$ = this.searchOptions$.pipe( this.resultsRD$ = this.searchOptions$.pipe(
flatMap((searchOptions) => this.service.search(searchOptions)) flatMap((searchOptions) => this.service.search(searchOptions))
); );
this.fixedFilter = this.routeService.getRouteParameterValue('filter');
} }
public closeSidebar(): void { public closeSidebar(): void {

View File

@@ -23,6 +23,7 @@ import { SearchFacetFilterComponent } from './search-filters/search-filter/searc
import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; import { SearchFilterService } from './search-filters/search-filter/search-filter.service';
import { FilteredSearchPageComponent } from './filtered-search-page.component'; import { FilteredSearchPageComponent } from './filtered-search-page.component';
import { SearchFixedFilterService } from './search-filters/search-filter/search-fixed-filter.service'; import { SearchFixedFilterService } from './search-filters/search-filter/search-fixed-filter.service';
import { FilteredSearchPageGuard } from './filtered-search-page.guard';
const effects = [ const effects = [
SearchSidebarEffects SearchSidebarEffects
@@ -57,7 +58,8 @@ const effects = [
SearchService, SearchService,
SearchSidebarService, SearchSidebarService,
SearchFilterService, SearchFilterService,
SearchFixedFilterService SearchFixedFilterService,
FilteredSearchPageGuard
], ],
entryComponents: [ entryComponents: [
ItemSearchResultListElementComponent, ItemSearchResultListElementComponent,

View File

@@ -1,6 +1,5 @@
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 { hasNoValue, isEmpty } from '../shared/empty.util';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
export class SearchResult<T extends DSpaceObject> implements ListableObject { export class SearchResult<T extends DSpaceObject> implements ListableObject {

View File

@@ -1,4 +1,4 @@
<h2>{{ 'search.results.head' | translate }}</h2> <h2>{{ getTitleKey() | translate }}</h2>
<div *ngIf="searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn> <div *ngIf="searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn>
<ds-viewable-collection <ds-viewable-collection
[config]="searchConfig.pagination" [config]="searchConfig.pagination"

View File

@@ -3,10 +3,11 @@ import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { fadeIn, fadeInOut } from '../../shared/animations/fade'; import { fadeIn, fadeInOut } from '../../shared/animations/fade';
import { SetViewMode } from '../../shared/view-mode'; import { SetViewMode } from '../../shared/view-mode';
import { SearchOptions} from '../search-options.model'; import { SearchOptions } from '../search-options.model';
import { SortOptions } from '../../core/cache/models/sort-options.model'; import { SortOptions } from '../../core/cache/models/sort-options.model';
import { SearchResult } from '../search-result.model'; import { SearchResult } from '../search-result.model';
import { PaginatedList } from '../../core/data/paginated-list'; import { PaginatedList } from '../../core/data/paginated-list';
import { hasValue, isNotEmpty } from '../../shared/empty.util';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -26,4 +27,13 @@ export class SearchResultsComponent {
@Input() searchConfig: SearchOptions; @Input() searchConfig: SearchOptions;
@Input() sortConfig: SortOptions; @Input() sortConfig: SortOptions;
@Input() viewMode: SetViewMode; @Input() viewMode: SetViewMode;
@Input() fixedFilter: string;
getTitleKey() {
if (isNotEmpty(this.fixedFilter)) {
return 'search.' + this.fixedFilter + '.results.head'
} else {
return 'search.results.head';
}
}
} }

View File

@@ -46,6 +46,7 @@ import { FacetValueResponseParsingService } from './data/facet-value-response-pa
import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service'; import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service';
import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service'; import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service';
import { NotificationsService } from '../shared/notifications/notifications.service'; import { NotificationsService } from '../shared/notifications/notifications.service';
import { FilteredDiscoveryPageResponseParsingService } from './data/filtered-discovery-page-response-parsing.service';
const IMPORTS = [ const IMPORTS = [
CommonModule, CommonModule,
@@ -93,6 +94,7 @@ const PROVIDERS = [
SubmissionSectionsConfigService, SubmissionSectionsConfigService,
UUIDService, UUIDService,
NotificationsService, NotificationsService,
FilteredDiscoveryPageResponseParsingService,
{ provide: NativeWindowService, useFactory: NativeWindowFactory } { provide: NativeWindowService, useFactory: NativeWindowFactory }
]; ];

View File

@@ -18,6 +18,8 @@ export class FilteredDiscoveryPageResponseParsingService extends BaseResponsePar
) { super(); ) { super();
} }
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
console.log('test');
const query = data.payload['discovery-query']; const query = data.payload['discovery-query'];
return new FilteredDiscoveryQueryResponse(query, data.statusCode); return new FilteredDiscoveryQueryResponse(query, data.statusCode);
} }

View File

@@ -1,7 +1,9 @@
import { RouteService } from './route.service'; import { RouteService } from './route.service';
import { async, TestBed } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { ActivatedRoute, convertToParamMap, Params } from '@angular/router'; import { ActivatedRoute, convertToParamMap, Params, Router } from '@angular/router';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { MockRouter } from './mocks/mock-router';
import { RouterStub } from './testing/router-stub';
describe('RouteService', () => { describe('RouteService', () => {
let service: RouteService; let service: RouteService;
@@ -28,12 +30,15 @@ describe('RouteService', () => {
queryParamMap: Observable.of(convertToParamMap(paramObject)) queryParamMap: Observable.of(convertToParamMap(paramObject))
}, },
}, },
{
provide: Router, useClass: RouterStub
}
] ]
}); });
})); }));
beforeEach(() => { beforeEach(() => {
service = new RouteService(TestBed.get(ActivatedRoute)); service = new RouteService(TestBed.get(ActivatedRoute), TestBed.get(Router));
}); });
describe('hasQueryParam', () => { describe('hasQueryParam', () => {

View File

@@ -1,11 +1,15 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { ActivatedRoute, Params, } from '@angular/router'; import { ActivatedRoute, NavigationEnd, Params, Router, } from '@angular/router';
import { filter } from 'rxjs/operators';
@Injectable() @Injectable()
export class RouteService { export class RouteService {
params: Observable<Params>;
constructor(private route: ActivatedRoute, private router: Router) {
this.subscribeToRouterParams();
constructor(private route: ActivatedRoute) {
} }
getQueryParameterValues(paramName: string): Observable<string[]> { getQueryParameterValues(paramName: string): Observable<string[]> {
@@ -25,7 +29,7 @@ export class RouteService {
} }
getRouteParameterValue(paramName: string): Observable<string> { getRouteParameterValue(paramName: string): Observable<string> {
return this.route.params.map((params) => params[paramName]).distinctUntilChanged(); return this.params.map((params) => params[paramName]).distinctUntilChanged();
} }
getRouteDataValue(datafield: string): Observable<any> { getRouteDataValue(datafield: string): Observable<any> {
@@ -44,4 +48,16 @@ export class RouteService {
return params; return params;
}).distinctUntilChanged(); }).distinctUntilChanged();
} }
subscribeToRouterParams() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd))
.subscribe(() => {
let active = this.route;
while (active.firstChild) {
active = active.firstChild;
}
this.params = active.params;
});
}
} }