Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use short ngrx approach to get request value rendered #1

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ rest:
host: demo.dspace.org
port: 443
nameSpace: /server
languages:
- code: en
label: English
active: true
4 changes: 3 additions & 1 deletion src/app/app.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { NavbarEffects } from './navbar/navbar.effects';
import { SidebarEffects } from './shared/sidebar/sidebar-effects.service';
import { RelationshipEffects } from './shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects';
import { ThemeEffects } from './shared/theme-support/theme.effects';
import {SearchEffects} from './shared/search/@ngrx/search.effects';

export const appEffects = [
StoreEffects,
NavbarEffects,
NotificationsEffects,
SidebarEffects,
ThemeEffects,
RelationshipEffects
RelationshipEffects,
SearchEffects,
];
4 changes: 4 additions & 0 deletions src/app/app.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import { ThemeState, themeReducer } from './shared/theme-support/theme.reducer';
import { MenusState } from './shared/menu/menus-state.model';
import { correlationIdReducer } from './correlation-id/correlation-id.reducer';
import { contextHelpReducer, ContextHelpState } from './shared/context-help.reducer';
import {SearchModel} from './shared/search/@ngrx/search.initial';
import {searchReducers} from './shared/search/@ngrx/search.reducers';

export interface AppState {
router: RouterReducerState;
Expand All @@ -57,6 +59,7 @@ export interface AppState {
notifications: NotificationsState;
sidebar: SidebarState;
searchFilter: SearchFiltersState;
search: SearchModel;
truncatable: TruncatablesState;
cssVariables: CSSVariablesState;
theme: ThemeState;
Expand All @@ -79,6 +82,7 @@ export const appReducers: ActionReducerMap<AppState> = {
notifications: notificationsReducer,
sidebar: sidebarReducer,
searchFilter: filterReducer,
search: searchReducers,
truncatable: truncatableReducer,
cssVariables: cssVariablesReducer,
theme: themeReducer,
Expand Down
14 changes: 12 additions & 2 deletions src/app/core/shared/search/search.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable max-classes-per-file */
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
import {combineLatest as observableCombineLatest, Observable, throwError} from 'rxjs';
import { Injectable, OnDestroy } from '@angular/core';
import { map, switchMap, take } from 'rxjs/operators';
import {catchError, map, switchMap, take} from 'rxjs/operators';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { ResponseParsingService } from '../../data/parsing.service';
import { RemoteData } from '../../data/remote-data';
Expand Down Expand Up @@ -32,6 +32,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
import { RestRequest } from '../../data/rest-request.model';
import { BaseDataService } from '../../data/base/base-data.service';
import { Angulartics2 } from 'angulartics2';
import {HttpClient} from '@angular/common/http';

/**
* A limited data service implementation for the 'discover' endpoint
Expand Down Expand Up @@ -96,6 +97,7 @@ export class SearchService implements OnDestroy {
private paginationService: PaginationService,
private searchConfigurationService: SearchConfigurationService,
private angulartics2: Angulartics2,
private httpClient: HttpClient,
) {
this.searchDataService = new SearchDataService();
}
Expand Down Expand Up @@ -173,6 +175,14 @@ export class SearchService implements OnDestroy {
return this.directlyAttachIndexableObjects(sqr$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
}

pcgSearch(searchOptions: PaginatedSearchOptions): Observable<any> {
const urlLocation = `https://demo.dspace.org/server/api/discover/search/objects?sort=${searchOptions.sort.field},${searchOptions.sort.direction}&page=${searchOptions.pagination.currentPage - 1}&size=${searchOptions.pagination.pageSize}&query=${searchOptions.query}`;

return this.httpClient
.get(urlLocation)
.pipe(catchError((error) => throwError(error)));
}

/**
* Method to retrieve request entries for search results from the server
* @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search
Expand Down
7 changes: 5 additions & 2 deletions src/app/search-page/configuration-search-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { SearchConfigurationService } from '../core/shared/search/search-configu
import { RouteService } from '../core/services/route.service';
import { SearchService } from '../core/shared/search/search.service';
import { Router } from '@angular/router';
import {Store} from '@ngrx/store';
import {SearchModel} from '../shared/search/@ngrx/search.initial';

/**
* This component renders a search page using a configuration as input.
Expand All @@ -32,7 +34,8 @@ export class ConfigurationSearchPageComponent extends SearchComponent {
protected windowService: HostWindowService,
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService,
protected routeService: RouteService,
protected router: Router) {
super(service, sidebarService, windowService, searchConfigService, routeService, router);
protected router: Router,
protected store: Store<SearchModel>,) {
super(service, sidebarService, windowService, searchConfigService, routeService, router, store);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class PaginationComponentOptions extends NgbPaginationConfig {
/**
* A number array that represents options for a context pagination limit.
*/
pageSizeOptions: number[] = [1, 5, 10, 20, 40, 60, 80, 100];
pageSizeOptions: number[] = [1, 5, 10, 20, 40, 60, 80, 100, 200, 500];

/**
* Number of items per page.
Expand Down
9 changes: 9 additions & 0 deletions src/app/shared/search/@ngrx/search.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {createAction, props} from '@ngrx/store';
import {PaginatedSearchOptions} from '../models/paginated-search-options.model';

export const startSearch = createAction('[Search] new query', props<{ searchOptions: PaginatedSearchOptions }>());

export const pendingSearch = createAction('[Search] pending search');
export const successSearch = createAction('[Search] success search', props<{ searchResults: any }>());
export const errorLocation = createAction('[Search] error search', props<{ error: any }>());

30 changes: 30 additions & 0 deletions src/app/shared/search/@ngrx/search.effects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {errorLocation, pendingSearch, startSearch, successSearch} from './search.actions';
import {concatMap, of} from 'rxjs';
import {SearchService} from '../../../core/shared/search/search.service';
import {catchError, map, tap} from 'rxjs/operators';
import {Store} from '@ngrx/store';

@Injectable()
export class SearchEffects {

searchRequest$ = createEffect(() => {
return this.actions$.pipe(
ofType(startSearch),
concatMap((props) =>
this.searchService.pcgSearch(props.searchOptions).pipe(
tap(() => this.store$.dispatch(pendingSearch())),
map((searchResults) => successSearch({ searchResults })),
catchError((error) => of(errorLocation({ error }))),
),
),
);
});

constructor(
private actions$: Actions,
private store$: Store,
private searchService: SearchService
) {}
}
15 changes: 15 additions & 0 deletions src/app/shared/search/@ngrx/search.initial.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {PaginatedSearchOptions} from '../models/paginated-search-options.model';

export interface SearchModel {
searchOptions: PaginatedSearchOptions;
searchResults: any;
searchError: any;
searchStatus: 'initial' | 'pending' | 'success' | 'error';
}

export const searchInitial: SearchModel = {
searchOptions: undefined,
searchResults: undefined,
searchError: undefined,
searchStatus: 'initial',
};
40 changes: 40 additions & 0 deletions src/app/shared/search/@ngrx/search.reducers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {createReducer, on} from '@ngrx/store';
import {searchInitial, SearchModel} from './search.initial';
import { startSearch, pendingSearch, successSearch, errorLocation } from './search.actions';


export const searchReducers = createReducer<SearchModel>(
searchInitial,
on(startSearch, (state: SearchModel, { searchOptions }): SearchModel => {
console.log('SERACH START!');
return {
...state,
searchOptions,
searchStatus: 'initial',
searchResults: undefined,
};
}),
on(pendingSearch, (state: SearchModel): SearchModel => {
console.log('SERACH PENDING');
return {
...state,
searchStatus: 'pending',
};
}),
on(successSearch, (state: SearchModel, { searchResults }): SearchModel => {
console.log('SERACH SUCCESS');
return {
...state,
searchResults,
searchStatus: 'success',
};
}),
on(errorLocation, (state: SearchModel, { error }): SearchModel => {
console.log('SERACH ERROR');
return {
...state,
searchError: error,
searchStatus: 'error',
};
}),
);
13 changes: 13 additions & 0 deletions src/app/shared/search/@ngrx/search.selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Returns the user state.
* @function getUserState
* @param {AppState} state Top level state.
* @return {AuthState}
*/
import {SearchModel} from './search.initial';
import {createFeatureSelector, createSelector} from '@ngrx/store';

export const searchStateSelector = createFeatureSelector('search');

export const searchStatus = createSelector(searchStateSelector, (searchState: SearchModel) => searchState.searchStatus);
export const searchResults = createSelector(searchStateSelector, (searchState: SearchModel) => searchState.searchResults);
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<h2 *ngIf="!disableHeader">{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}</h2>
<ds-search-export-csv *ngIf="showCsvExport" [searchConfig]="searchConfig"></ds-search-export-csv>
</div>
<div *ngIf="searchResults && searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn>
<div *ngIf="results$ | async as searchResults; " @fadeIn>
<ds-viewable-collection
[config]="searchConfig.pagination"
[sortConfig]="searchConfig.sort"
Expand All @@ -19,8 +19,9 @@ <h2 *ngIf="!disableHeader">{{ (configuration ? configuration + '.search.results.
(selectObject)="selectObject.emit($event)">
</ds-viewable-collection>
</div>
<ds-themed-loading *ngIf="isLoading()" message="{{'loading.search-results' | translate}}"></ds-themed-loading>
<ds-error *ngIf="showError()"

<ds-themed-loading *ngIf="isLoading$ | async" message="{{'loading.search-results' | translate}}"></ds-themed-loading>
<ds-error *ngIf="isError$ | async"
message="{{errorMessageLabel() | translate}}"></ds-error>
<div *ngIf="searchResults?.payload?.page.length == 0 || searchResults?.statusCode == 400">
{{ 'search.results.no-results' | translate }}
Expand Down
70 changes: 70 additions & 0 deletions src/app/shared/search/search-results/search-results.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import { CollectionElementLinkType } from '../../object-collection/collection-el
import { ViewMode } from '../../../core/shared/view-mode.model';
import { Context } from '../../../core/shared/context.model';
import { PaginatedSearchOptions } from '../models/paginated-search-options.model';
import {Store} from '@ngrx/store';
import {SearchModel} from '../@ngrx/search.initial';
import {searchResults, searchStatus} from '../@ngrx/search.selectors';
import {map, tap} from 'rxjs/operators';
import {Observable} from 'rxjs';
import {Item} from '../../../core/shared/item.model';
import {ItemSearchResult} from '../../object-collection/shared/item-search-result.model';

export interface SelectionConfig {
repeatable: boolean;
Expand Down Expand Up @@ -104,6 +111,12 @@ export class SearchResultsComponent {

@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();

public isLoading$: Observable<boolean> = this.store.select(searchStatus).pipe(tap(console.log), map((el) => el === 'pending'));
public isError$: Observable<boolean> = this.store.select(searchStatus).pipe(map((el) => el === 'error'));
public results$ = this.store.select(searchResults).pipe(map((el) => mapSourceToTarget(el)));

constructor(protected store: Store<SearchModel>) {}

/**
* Check if search results are loading
*/
Expand Down Expand Up @@ -132,3 +145,60 @@ export class SearchResultsComponent {
return result;
}
}

export function mapSourceToTarget(source: any): any {
if (!source) {
return source;
}
const page = source._embedded.searchResult._embedded.objects.map((obj: any) => {
return Object.assign(new ItemSearchResult(), {
hitHighlights: obj.hitHighlights || {},
_links: {
indexableObject: obj._links.indexableObject
},
indexableObject: Object.assign(new Item(), {
handle: obj._embedded.indexableObject.handle,
lastModified: obj._embedded.indexableObject.lastModified,
isArchived: obj._embedded.indexableObject.inArchive,
isDiscoverable: obj._embedded.indexableObject.discoverable,
isWithdrawn: obj._embedded.indexableObject.withdrawn,
_links: obj._embedded.indexableObject._links,
_name: obj._embedded.indexableObject.name || 'IMPOSSIBLE_TO_MAP',
id: obj._embedded.indexableObject.id,
uuid: obj._embedded.indexableObject.uuid,
type: obj._embedded.indexableObject.type,
metadata: obj._embedded.indexableObject.metadata,
thumbnail: obj._embedded.indexableObject.thumbnail || { source: { source: { source: { source: {} } } } },
accessStatus: obj._embedded.indexableObject.accessStatus || { source: { source: { source: { source: {} } } } },
item: obj._embedded.indexableObject.item || {}
})
});
});

return {
timeCompleted: Date.now(),
msToLive: 900000,
lastUpdated: Date.now(),
state: 'Success',
errorMessage: null,
hasSucceeded: true,
payload: {
type: {
value: 'discovery-objects'
},
page,
scope: source.scope,
appliedFilters: source.appliedFilters,
sort: source.sort,
configuration: source.configuration,
_links: source._embedded.searchResult._links,
pageInfo: {
elementsPerPage: source._embedded.searchResult.page.size,
totalElements: source._embedded.searchResult.page.totalElements,
totalPages: source._embedded.searchResult.page.totalPages,
currentPage: source._embedded.searchResult.page.number + 1
}
},
statusCode: 200
};
}
Loading