mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-09 19:13:08 +00:00
finished entity search endpoints
This commit is contained in:
@@ -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": {
|
||||||
|
18
src/app/+search-page/filtered-search-page.guard.ts
Normal file
18
src/app/+search-page/filtered-search-page.guard.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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', () => {
|
||||||
|
@@ -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(
|
||||||
|
@@ -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.' }}
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -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>
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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,
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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"
|
||||||
|
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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', () => {
|
||||||
|
@@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user