Unverified Commit 29393825 authored by Tamika Tannis's avatar Tamika Tannis Committed by GitHub

Improve granularity of logging search actions (#396)

* WIP: One approach

* Second approach

* Fix a few errors; Add tests

* Fix test

* Code cleanup

* Change value for when user selects inline result & searchAll is needed

* Update SearchType enum

* Use snake_case for consistency in backend until we have some auto-convert
parent 5aaec51b
This diff is collapsed.
...@@ -23,11 +23,11 @@ def map_table_result(result: Dict) -> Dict: ...@@ -23,11 +23,11 @@ def map_table_result(result: Dict) -> Dict:
} }
def generate_query_json(*, filters: Dict = {}, page_index: str, search_term: str) -> Dict: def generate_query_json(*, filters: Dict = {}, page_index: int, search_term: str) -> Dict:
""" """
Transforms the given paramaters to the query json for the search service according to Transforms the given paramaters to the query json for the search service according to
the api defined at: the api defined at:
TODO (ttannis): Add link when amundsensearch PR is complete https://github.com/lyft/amundsensearchlibrary/blob/master/search_service/api/swagger_doc/table/search_table_filter.yml
""" """
# Generate the filter payload # Generate the filter payload
filter_payload = {} filter_payload = {}
......
...@@ -4,7 +4,7 @@ import { DashboardSearchResults, TableSearchResults, UserSearchResults } from 'd ...@@ -4,7 +4,7 @@ import { DashboardSearchResults, TableSearchResults, UserSearchResults } from 'd
import globalState from 'fixtures/globalState'; import globalState from 'fixtures/globalState';
import { ResourceType } from 'interfaces'; import { ResourceType, SearchType } from 'interfaces';
import * as API from '../v0'; import * as API from '../v0';
...@@ -44,7 +44,7 @@ describe('searchResource', () => { ...@@ -44,7 +44,7 @@ describe('searchResource', () => {
const resourceType = ResourceType.dashboard; const resourceType = ResourceType.dashboard;
const term = 'test'; const term = 'test';
expect.assertions(3); expect.assertions(3);
await API.searchResource(pageIndex, resourceType, term).then(results => { await API.searchResource(pageIndex, resourceType, term, undefined, SearchType.FILTER).then(results => {
expect(results).toEqual({}); expect(results).toEqual({});
}); });
expect(axiosMockGet).not.toHaveBeenCalled(); expect(axiosMockGet).not.toHaveBeenCalled();
...@@ -59,7 +59,7 @@ describe('searchResource', () => { ...@@ -59,7 +59,7 @@ describe('searchResource', () => {
const resourceType = ResourceType.user; const resourceType = ResourceType.user;
const term = 'test'; const term = 'test';
expect.assertions(3); expect.assertions(3);
await API.searchResource(pageIndex, resourceType, term).then(results => { await API.searchResource(pageIndex, resourceType, term, undefined, SearchType.FILTER).then(results => {
expect(results).toEqual({}); expect(results).toEqual({});
}); });
expect(axiosMockGet).not.toHaveBeenCalled(); expect(axiosMockGet).not.toHaveBeenCalled();
...@@ -74,14 +74,15 @@ describe('searchResource', () => { ...@@ -74,14 +74,15 @@ describe('searchResource', () => {
const pageIndex = 0; const pageIndex = 0;
const resourceType = ResourceType.user; const resourceType = ResourceType.user;
const term = 'test'; const term = 'test';
await API.searchResource(pageIndex, resourceType, term); const searchType = SearchType.SUBMIT_TERM;
expect(axiosMockGet).toHaveBeenCalledWith(`${API.BASE_URL}/${resourceType}?query=${term}&page_index=${pageIndex}`); await API.searchResource(pageIndex, resourceType, term, undefined, searchType);
expect(axiosMockGet).toHaveBeenCalledWith(`${API.BASE_URL}/${resourceType}?query=${term}&page_index=${pageIndex}&search_type=${searchType}`);
expect(axiosMockPost).not.toHaveBeenCalled(); expect(axiosMockPost).not.toHaveBeenCalled();
}); });
it('calls searchResourceHelper with api call response', async () => { it('calls searchResourceHelper with api call response', async () => {
const searchResourceHelperSpy = jest.spyOn(API, 'searchResourceHelper'); const searchResourceHelperSpy = jest.spyOn(API, 'searchResourceHelper');
await API.searchResource(0, ResourceType.user, 'test'); await API.searchResource(0, ResourceType.user, 'test', undefined, SearchType.FILTER);
expect(searchResourceHelperSpy).toHaveBeenCalledWith(mockSearchResponse); expect(searchResourceHelperSpy).toHaveBeenCalledWith(mockSearchResponse);
}); });
}) })
...@@ -94,18 +95,20 @@ describe('searchResource', () => { ...@@ -94,18 +95,20 @@ describe('searchResource', () => {
const resourceType = ResourceType.table; const resourceType = ResourceType.table;
const term = 'test'; const term = 'test';
const filters = { 'schema': 'schema_name' } const filters = { 'schema': 'schema_name' }
await API.searchResource(pageIndex, resourceType, term, filters); const searchType = SearchType.SUBMIT_TERM;
await API.searchResource(pageIndex, resourceType, term, filters, searchType);
expect(axiosMockGet).not.toHaveBeenCalled(); expect(axiosMockGet).not.toHaveBeenCalled();
expect(axiosMockPost).toHaveBeenCalledWith(`${API.BASE_URL}/${resourceType}_qs`, { expect(axiosMockPost).toHaveBeenCalledWith(`${API.BASE_URL}/${resourceType}`, {
filters, filters,
pageIndex, pageIndex,
term, term,
searchType,
}); });
}); });
it('calls searchResourceHelper with api call response', async () => { it('calls searchResourceHelper with api call response', async () => {
const searchResourceHelperSpy = jest.spyOn(API, 'searchResourceHelper'); const searchResourceHelperSpy = jest.spyOn(API, 'searchResourceHelper');
await API.searchResource(0, ResourceType.table, 'test', { 'schema': 'schema_name' }); await API.searchResource(0, ResourceType.table, 'test', { 'schema': 'schema_name' }, SearchType.FILTER);
expect(searchResourceHelperSpy).toHaveBeenCalledWith(mockSearchResponse); expect(searchResourceHelperSpy).toHaveBeenCalledWith(mockSearchResponse);
}); });
}) })
......
import axios, { AxiosResponse } from 'axios'; import axios, { AxiosResponse } from 'axios';
import { indexUsersEnabled } from 'config/config-utils'; import { indexUsersEnabled } from 'config/config-utils';
import { ResourceType } from 'interfaces'; import { ResourceType, SearchType } from 'interfaces';
import { DashboardSearchResults, TableSearchResults, UserSearchResults } from '../types'; import { DashboardSearchResults, TableSearchResults, UserSearchResults } from '../types';
...@@ -29,7 +29,7 @@ export const searchResourceHelper = (response: AxiosResponse<SearchAPI>) => { ...@@ -29,7 +29,7 @@ export const searchResourceHelper = (response: AxiosResponse<SearchAPI>) => {
return ret; return ret;
}; };
export function searchResource(pageIndex: number, resource: ResourceType, term: string, filters: ResourceFilterReducerState = {}) { export function searchResource(pageIndex: number, resource: ResourceType, term: string, filters: ResourceFilterReducerState = {}, searchType: SearchType) {
if (resource === ResourceType.dashboard || if (resource === ResourceType.dashboard ||
(resource === ResourceType.user && !indexUsersEnabled())) { (resource === ResourceType.user && !indexUsersEnabled())) {
return Promise.resolve({}); return Promise.resolve({});
...@@ -37,12 +37,13 @@ export function searchResource(pageIndex: number, resource: ResourceType, term: ...@@ -37,12 +37,13 @@ export function searchResource(pageIndex: number, resource: ResourceType, term:
/* Note: This logic must exist until query string endpoints are created for all resources */ /* Note: This logic must exist until query string endpoints are created for all resources */
if (resource === ResourceType.table) { if (resource === ResourceType.table) {
return axios.post(`${BASE_URL}/${resource}_qs`, { return axios.post(`${BASE_URL}/${resource}`, {
filters, filters,
pageIndex, pageIndex,
term, term,
searchType,
}).then(searchResourceHelper); }).then(searchResourceHelper);
} }
return axios.get(`${BASE_URL}/${resource}?query=${term}&page_index=${pageIndex}`) return axios.get(`${BASE_URL}/${resource}?query=${term}&page_index=${pageIndex}&search_type=${searchType}`)
.then(searchResourceHelper); .then(searchResourceHelper);
}; };
import { ResourceType } from 'interfaces'; import { ResourceType, SearchType} from 'interfaces';
import { Search as UrlSearch } from 'history'; import { Search as UrlSearch } from 'history';
...@@ -49,13 +49,14 @@ export interface SearchReducerState { ...@@ -49,13 +49,14 @@ export interface SearchReducerState {
}; };
/* ACTIONS */ /* ACTIONS */
export function searchAll(term: string, resource?: ResourceType, pageIndex?: number, useFilters: boolean = false): SearchAllRequest { export function searchAll(searchType: SearchType, term: string, resource?: ResourceType, pageIndex?: number, useFilters: boolean = false): SearchAllRequest {
return { return {
payload: { payload: {
resource, resource,
pageIndex, pageIndex,
term, term,
useFilters, useFilters,
searchType,
}, },
type: SearchAll.REQUEST, type: SearchAll.REQUEST,
}; };
...@@ -67,12 +68,13 @@ export function searchAllFailure(): SearchAllResponse { ...@@ -67,12 +68,13 @@ export function searchAllFailure(): SearchAllResponse {
return { type: SearchAll.FAILURE }; return { type: SearchAll.FAILURE };
}; };
export function searchResource(term: string, resource: ResourceType, pageIndex: number): SearchResourceRequest { export function searchResource(searchType: SearchType, term: string, resource: ResourceType, pageIndex: number): SearchResourceRequest {
return { return {
payload: { payload: {
pageIndex, pageIndex,
term, term,
resource, resource,
searchType
}, },
type: SearchResource.REQUEST, type: SearchResource.REQUEST,
}; };
......
...@@ -3,7 +3,7 @@ import { all, call, debounce, put, select, takeEvery, takeLatest } from 'redux-s ...@@ -3,7 +3,7 @@ import { all, call, debounce, put, select, takeEvery, takeLatest } from 'redux-s
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as qs from 'simple-query-string'; import * as qs from 'simple-query-string';
import { ResourceType } from 'interfaces/Resources'; import { ResourceType, SearchType } from 'interfaces';
import * as API from './api/v0'; import * as API from './api/v0';
...@@ -68,7 +68,7 @@ export function* filterWorker(): SagaIterator { ...@@ -68,7 +68,7 @@ export function* filterWorker(): SagaIterator {
const state = yield select(getSearchState); const state = yield select(getSearchState);
const { search_term, selectedTab, filters } = state; const { search_term, selectedTab, filters } = state;
const pageIndex = getPageIndex(state) const pageIndex = getPageIndex(state)
yield put(searchResource(search_term, selectedTab, pageIndex)); yield put(searchResource(SearchType.FILTER, search_term, selectedTab, pageIndex));
updateSearchUrl({ filters, resource: selectedTab, term: search_term, index: pageIndex }, true); updateSearchUrl({ filters, resource: selectedTab, term: search_term, index: pageIndex }, true);
}; };
...@@ -90,7 +90,7 @@ export function* filterWatcher2(): SagaIterator { ...@@ -90,7 +90,7 @@ export function* filterWatcher2(): SagaIterator {
export function* filterWorker2(action: any): SagaIterator { export function* filterWorker2(action: any): SagaIterator {
const state = yield select(getSearchState); const state = yield select(getSearchState);
const { pageIndex = 0, resourceType, term = '' } = action.payload; const { pageIndex = 0, resourceType, term = '' } = action.payload;
yield put(searchResource(term, resourceType, pageIndex)); yield put(searchResource(SearchType.FILTER, term, resourceType, pageIndex));
updateSearchUrl({ term, filters: state.filters, resource: resourceType, index: pageIndex }, false); updateSearchUrl({ term, filters: state.filters, resource: resourceType, index: pageIndex }, false);
}; };
...@@ -98,8 +98,8 @@ export function* inlineSearchWorker(action: InlineSearchRequest): SagaIterator { ...@@ -98,8 +98,8 @@ export function* inlineSearchWorker(action: InlineSearchRequest): SagaIterator {
const { term } = action.payload; const { term } = action.payload;
try { try {
const [tableResponse, userResponse] = yield all([ const [tableResponse, userResponse] = yield all([
call(API.searchResource, 0, ResourceType.table, term), call(API.searchResource, 0, ResourceType.table, term, {}, SearchType.INLINE_SEARCH),
call(API.searchResource, 0, ResourceType.user, term), call(API.searchResource, 0, ResourceType.user, term, {}, SearchType.INLINE_SEARCH),
]); ]);
const inlineSearchResponse = { const inlineSearchResponse = {
tables: tableResponse.tables || initialInlineResultsState.tables, tables: tableResponse.tables || initialInlineResultsState.tables,
...@@ -124,7 +124,7 @@ export function* selectInlineResultWorker(action): SagaIterator { ...@@ -124,7 +124,7 @@ export function* selectInlineResultWorker(action): SagaIterator {
const state = yield select(); const state = yield select();
const { searchTerm, resourceType, updateUrl } = action.payload; const { searchTerm, resourceType, updateUrl } = action.payload;
if (state.search.inlineResults.isLoading) { if (state.search.inlineResults.isLoading) {
yield put(searchAll(searchTerm, resourceType, 0)) yield put(searchAll(SearchType.INLINE_SELECT, searchTerm, resourceType, 0, false))
updateSearchUrl({ term: searchTerm, filters: state.search.filters }); updateSearchUrl({ term: searchTerm, filters: state.search.filters });
} }
else { else {
...@@ -144,67 +144,10 @@ export function* selectInlineResultsWatcher(): SagaIterator { ...@@ -144,67 +144,10 @@ export function* selectInlineResultsWatcher(): SagaIterator {
yield takeEvery(InlineSearch.SELECT, selectInlineResultWorker); yield takeEvery(InlineSearch.SELECT, selectInlineResultWorker);
}; };
export function* searchAllWorker(action: SearchAllRequest): SagaIterator {
let { resource } = action.payload;
const { pageIndex, term, useFilters } = action.payload;
if (!useFilters) {
yield put(clearAllFilters())
}
const state = yield select(getSearchState);
const tableIndex = resource === ResourceType.table ? pageIndex : 0;
const userIndex = resource === ResourceType.user ? pageIndex : 0;
const dashboardIndex = resource === ResourceType.dashboard ? pageIndex : 0;
try {
const [tableResponse, userResponse, dashboardResponse] = yield all([
call(API.searchResource, tableIndex, ResourceType.table, term, state.filters[ResourceType.table]),
call(API.searchResource, userIndex, ResourceType.user, term, state.filters[ResourceType.user]),
call(API.searchResource, dashboardIndex, ResourceType.dashboard, term, state.filters[ResourceType.dashboard]),
]);
const searchAllResponse = {
search_term: term,
selectedTab: resource,
tables: tableResponse.tables || initialState.tables,
users: userResponse.users || initialState.users,
dashboards: dashboardResponse.dashboards || initialState.dashboards,
isLoading: false,
};
if (resource === undefined) {
resource = autoSelectResource(searchAllResponse);
searchAllResponse.selectedTab = resource;
}
const index = getPageIndex(searchAllResponse);
yield put(searchAllSuccess(searchAllResponse));
updateSearchUrl({ term, resource, index, filters: state.filters }, true);
} catch (e) {
yield put(searchAllFailure());
}
};
export function* searchAllWatcher(): SagaIterator {
yield takeEvery(SearchAll.REQUEST, searchAllWorker);
};
export function* searchResourceWorker(action: SearchResourceRequest): SagaIterator {
const { pageIndex, resource, term } = action.payload;
const state = yield select(getSearchState);
try {
const searchResults = yield call(API.searchResource, pageIndex, resource, term, state.filters[resource]);
yield put(searchResourceSuccess(searchResults));
} catch (e) {
yield put(searchResourceFailure());
}
};
export function* searchResourceWatcher(): SagaIterator {
yield takeEvery(SearchResource.REQUEST, searchResourceWorker);
};
export function* submitSearchWorker(action: SubmitSearchRequest): SagaIterator { export function* submitSearchWorker(action: SubmitSearchRequest): SagaIterator {
const state = yield select(getSearchState); const state = yield select(getSearchState);
const { searchTerm, useFilters } = action.payload; const { searchTerm, useFilters } = action.payload;
yield put(searchAll(searchTerm, undefined, undefined, useFilters)); yield put(searchAll(SearchType.SUBMIT_TERM, searchTerm, undefined, undefined, useFilters));
updateSearchUrl({ term: searchTerm, filters: state.filters }); updateSearchUrl({ term: searchTerm, filters: state.filters });
}; };
export function* submitSearchWatcher(): SagaIterator { export function* submitSearchWatcher(): SagaIterator {
...@@ -230,7 +173,7 @@ export function* setResourceWatcher(): SagaIterator { ...@@ -230,7 +173,7 @@ export function* setResourceWatcher(): SagaIterator {
export function* setPageIndexWorker(action: SetPageIndexRequest): SagaIterator { export function* setPageIndexWorker(action: SetPageIndexRequest): SagaIterator {
const { pageIndex, updateUrl } = action.payload; const { pageIndex, updateUrl } = action.payload;
const state = yield select(getSearchState); const state = yield select(getSearchState);
yield put(searchResource(state.search_term, state.selectedTab, pageIndex)); yield put(searchResource(SearchType.PAGINATION, state.search_term, state.selectedTab, pageIndex));
if (updateUrl) { if (updateUrl) {
updateSearchUrl({ updateSearchUrl({
...@@ -249,7 +192,7 @@ export function* clearSearchWorker(action: ClearSearchRequest): SagaIterator { ...@@ -249,7 +192,7 @@ export function* clearSearchWorker(action: ClearSearchRequest): SagaIterator {
/* If there was a previous search term, search each resource using filters */ /* If there was a previous search term, search each resource using filters */
const state = yield select(getSearchState); const state = yield select(getSearchState);
if (!!state.search_term) { if (!!state.search_term) {
yield put(searchAll('', undefined, undefined, true)); yield put(searchAll(SearchType.CLEAR_TERM, '', undefined, undefined, true));
} }
}; };
export function* clearSearchWatcher(): SagaIterator { export function* clearSearchWatcher(): SagaIterator {
...@@ -264,7 +207,7 @@ export function* urlDidUpdateWorker(action: UrlDidUpdateRequest): SagaIterator { ...@@ -264,7 +207,7 @@ export function* urlDidUpdateWorker(action: UrlDidUpdateRequest): SagaIterator {
const state = yield select(getSearchState); const state = yield select(getSearchState);
if (!!term && state.search_term !== term) { if (!!term && state.search_term !== term) {
yield put(searchAll(term, resource, parsedIndex)); yield put(searchAll(SearchType.LOAD_URL, term, resource, parsedIndex));
} else if (!!resource) { } else if (!!resource) {
if (resource !== state.selectedTab) { if (resource !== state.selectedTab) {
yield put(setResource(resource, false)) yield put(setResource(resource, false))
...@@ -302,3 +245,66 @@ export function* loadPreviousSearchWorker(action: LoadPreviousSearchRequest): Sa ...@@ -302,3 +245,66 @@ export function* loadPreviousSearchWorker(action: LoadPreviousSearchRequest): Sa
export function* loadPreviousSearchWatcher(): SagaIterator { export function* loadPreviousSearchWatcher(): SagaIterator {
yield takeEvery(LoadPreviousSearch.REQUEST, loadPreviousSearchWorker); yield takeEvery(LoadPreviousSearch.REQUEST, loadPreviousSearchWorker);
}; };
//////////////////////////////////////////////////////////////////////////////
// API/END SAGAS
// These sagas directly trigger axios search requests.
// The actions that trigger them should only be fired by other sagas,
// and these sagas should be considered the "end" of any saga chain.
//////////////////////////////////////////////////////////////////////////////
export function* searchResourceWorker(action: SearchResourceRequest): SagaIterator {
const { pageIndex, resource, term, searchType } = action.payload;
const state = yield select(getSearchState);
try {
const searchResults = yield call(API.searchResource, pageIndex, resource, term, state.filters[resource], searchType);
yield put(searchResourceSuccess(searchResults));
} catch (e) {
yield put(searchResourceFailure());
}
};
export function* searchResourceWatcher(): SagaIterator {
yield takeEvery(SearchResource.REQUEST, searchResourceWorker);
};
export function* searchAllWorker(action: SearchAllRequest): SagaIterator {
let { resource } = action.payload;
const { pageIndex, term, useFilters, searchType } = action.payload;
if (!useFilters) {
yield put(clearAllFilters())
}
const state = yield select(getSearchState);
const tableIndex = resource === ResourceType.table ? pageIndex : 0;
const userIndex = resource === ResourceType.user ? pageIndex : 0;
const dashboardIndex = resource === ResourceType.dashboard ? pageIndex : 0;
try {
const [tableResponse, userResponse, dashboardResponse] = yield all([
call(API.searchResource, tableIndex, ResourceType.table, term, state.filters[ResourceType.table], searchType),
call(API.searchResource, userIndex, ResourceType.user, term, state.filters[ResourceType.user], searchType),
call(API.searchResource, dashboardIndex, ResourceType.dashboard, term, state.filters[ResourceType.dashboard], searchType),
]);
const searchAllResponse = {
search_term: term,
selectedTab: resource,
tables: tableResponse.tables || initialState.tables,
users: userResponse.users || initialState.users,
dashboards: dashboardResponse.dashboards || initialState.dashboards,
isLoading: false,
};
if (resource === undefined) {
resource = autoSelectResource(searchAllResponse);
searchAllResponse.selectedTab = resource;
}
const index = getPageIndex(searchAllResponse);
yield put(searchAllSuccess(searchAllResponse));
updateSearchUrl({ term, resource, index, filters: state.filters }, true);
} catch (e) {
yield put(searchAllFailure());
}
};
export function* searchAllWatcher(): SagaIterator {
yield takeEvery(SearchAll.REQUEST, searchAllWorker);
};
import { testSaga } from 'redux-saga-test-plan'; import { testSaga } from 'redux-saga-test-plan';
import { debounce } from 'redux-saga/effects'; import { debounce } from 'redux-saga/effects';
import { DEFAULT_RESOURCE_TYPE, ResourceType } from 'interfaces'; import { DEFAULT_RESOURCE_TYPE, ResourceType, SearchType } from 'interfaces';
import * as NavigationUtils from 'utils/navigationUtils'; import * as NavigationUtils from 'utils/navigationUtils';
import * as SearchUtils from 'ducks/search/utils'; import * as SearchUtils from 'ducks/search/utils';
...@@ -146,26 +146,30 @@ describe('search ducks', () => { ...@@ -146,26 +146,30 @@ describe('search ducks', () => {
const term = 'test'; const term = 'test';
const resource = ResourceType.table; const resource = ResourceType.table;
const pageIndex = 0; const pageIndex = 0;
const action = searchAll(term, resource, pageIndex); const searchType = SearchType.SUBMIT_TERM;
const action = searchAll(searchType, term, resource, pageIndex);
const { payload } = action; const { payload } = action;
expect(action.type).toBe(SearchAll.REQUEST); expect(action.type).toBe(SearchAll.REQUEST);
expect(payload.resource).toBe(resource); expect(payload.resource).toBe(resource);
expect(payload.term).toBe(term); expect(payload.term).toBe(term);
expect(payload.pageIndex).toBe(pageIndex); expect(payload.pageIndex).toBe(pageIndex);
expect(payload.useFilters).toBe(false); expect(payload.useFilters).toBe(false);
expect(payload.searchType).toBe(searchType);
}); });
it('searchAll - returns the action to search all resources with useFilters', () => { it('searchAll - returns the action to search all resources with useFilters', () => {
const term = 'test'; const term = 'test';
const resource = ResourceType.table; const resource = ResourceType.table;
const pageIndex = 0; const pageIndex = 0;
const action = searchAll(term, resource, pageIndex, true); const searchType = SearchType.SUBMIT_TERM;
const action = searchAll(searchType, term, resource, pageIndex, true);
const { payload } = action; const { payload } = action;
expect(action.type).toBe(SearchAll.REQUEST); expect(action.type).toBe(SearchAll.REQUEST);
expect(payload.resource).toBe(resource); expect(payload.resource).toBe(resource);
expect(payload.term).toBe(term); expect(payload.term).toBe(term);
expect(payload.pageIndex).toBe(pageIndex); expect(payload.pageIndex).toBe(pageIndex);
expect(payload.useFilters).toBe(true); expect(payload.useFilters).toBe(true);
expect(payload.searchType).toBe(searchType);
}); });
it('searchAllSuccess - returns the action to process the success', () => { it('searchAllSuccess - returns the action to process the success', () => {
...@@ -184,12 +188,14 @@ describe('search ducks', () => { ...@@ -184,12 +188,14 @@ describe('search ducks', () => {
const term = 'test'; const term = 'test';
const resource = ResourceType.table; const resource = ResourceType.table;
const pageIndex = 0; const pageIndex = 0;
const action = searchResource(term, resource, pageIndex); const searchType = SearchType.SUBMIT_TERM;
const action = searchResource(searchType, term, resource, pageIndex);
const { payload } = action; const { payload } = action;
expect(action.type).toBe(SearchResource.REQUEST); expect(action.type).toBe(SearchResource.REQUEST);
expect(payload.resource).toBe(resource); expect(payload.resource).toBe(resource);
expect(payload.term).toBe(term); expect(payload.term).toBe(term);
expect(payload.pageIndex).toBe(pageIndex); expect(payload.pageIndex).toBe(pageIndex);
expect(payload.searchType).toBe(searchType);
}); });
it('searchResourceSuccess - returns the action to process the success', () => { it('searchResourceSuccess - returns the action to process the success', () => {
...@@ -311,9 +317,7 @@ describe('search ducks', () => { ...@@ -311,9 +317,7 @@ describe('search ducks', () => {
it('should handle SearchAll.REQUEST', () => { it('should handle SearchAll.REQUEST', () => {
const term = 'testSearch'; const term = 'testSearch';
const resource = ResourceType.table; expect(reducer(testState, searchAll(SearchType.SUBMIT_TERM, term, ResourceType.table, 0))).toEqual({
const pageIndex = 0;
expect(reducer(testState, searchAll(term, resource, pageIndex))).toEqual({
...testState, ...testState,
inlineResults: initialInlineResultsState, inlineResults: initialInlineResultsState,
search_term: term, search_term: term,
...@@ -346,7 +350,7 @@ describe('search ducks', () => { ...@@ -346,7 +350,7 @@ describe('search ducks', () => {
}); });
it('should handle SearchResource.REQUEST', () => { it('should handle SearchResource.REQUEST', () => {
expect(reducer(testState, searchResource('test', ResourceType.table, 0))).toEqual({ expect(reducer(testState, searchResource(SearchType.SUBMIT_TERM, 'test', ResourceType.table, 0))).toEqual({
...initialState, ...initialState,
isLoading: true, isLoading: true,
}); });
...@@ -498,7 +502,7 @@ describe('search ducks', () => { ...@@ -498,7 +502,7 @@ describe('search ducks', () => {
updateSearchUrlSpy.mockClear(); updateSearchUrlSpy.mockClear();
saga = saga.next().select(SearchUtils.getSearchState).next(mockSearchState); saga = saga.next().select(SearchUtils.getSearchState).next(mockSearchState);
expect(getPageIndexSpy).toHaveBeenCalledWith(mockSearchState); expect(getPageIndexSpy).toHaveBeenCalledWith(mockSearchState);
saga = saga.put(searchResource(mockSearchState.search_term, mockSearchState.selectedTab, mockIndex)).next(); saga = saga.put(searchResource(SearchType.FILTER, mockSearchState.search_term, mockSearchState.selectedTab, mockIndex)).next();
expect(updateSearchUrlSpy).toHaveBeenCalledWith({ expect(updateSearchUrlSpy).toHaveBeenCalledWith({
filters: mockSearchState.filters, filters: mockSearchState.filters,
resource: mockSearchState.selectedTab, resource: mockSearchState.selectedTab,
...@@ -530,7 +534,7 @@ describe('search ducks', () => { ...@@ -530,7 +534,7 @@ describe('search ducks', () => {
*/ */
it('handles request error', () => { it('handles request error', () => {
testSaga(Sagas.searchAllWorker, searchAll('test', ResourceType.table, 0, true)) testSaga(Sagas.searchAllWorker, searchAll(SearchType.SUBMIT_TERM, 'test', ResourceType.table, 0, true))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(globalState.search).throw(new Error()).put(searchAllFailure()) .next(globalState.search).throw(new Error()).put(searchAllFailure())
.next().isDone(); .next().isDone();
...@@ -551,15 +555,16 @@ describe('search ducks', () => { ...@@ -551,15 +555,16 @@ describe('search ducks', () => {
const resource = ResourceType.table; const resource = ResourceType.table;
const term = 'test'; const term = 'test';
const mockSearchState = globalState.search; const mockSearchState = globalState.search;
testSaga(Sagas.searchResourceWorker, searchResource(term, resource, pageIndex)) const searchType = SearchType.PAGINATION;
testSaga(Sagas.searchResourceWorker, searchResource(searchType, term, resource, pageIndex))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(mockSearchState).call(API.searchResource, pageIndex, resource, term, mockSearchState.filters[resource]) .next(mockSearchState).call(API.searchResource, pageIndex, resource, term, mockSearchState.filters[resource], searchType)
.next(expectedSearchResults).put(searchResourceSuccess(expectedSearchResults)) .next(expectedSearchResults).put(searchResourceSuccess(expectedSearchResults))
.next().isDone(); .next().isDone();
}); });
it('handles request error', () => { it('handles request error', () => {
testSaga(Sagas.searchResourceWorker, searchResource('test', ResourceType.table, 0)) testSaga(Sagas.searchResourceWorker, searchResource(SearchType.PAGINATION, 'test', ResourceType.table, 0))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(globalState.search).throw(new Error()).put(searchResourceFailure()) .next(globalState.search).throw(new Error()).put(searchResourceFailure())
.next().isDone(); .next().isDone();
...@@ -573,7 +578,7 @@ describe('search ducks', () => { ...@@ -573,7 +578,7 @@ describe('search ducks', () => {
updateSearchUrlSpy.mockClear(); updateSearchUrlSpy.mockClear();
testSaga(Sagas.submitSearchWorker, submitSearch(term, true)) testSaga(Sagas.submitSearchWorker, submitSearch(term, true))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(mockSearchState).put(searchAll(term, undefined, undefined, true)) .next(mockSearchState).put(searchAll(SearchType.SUBMIT_TERM, term, undefined, undefined, true))
.next().isDone(); .next().isDone();
expect(updateSearchUrlSpy).toHaveBeenCalledWith({ term, filters: mockSearchState.filters }); expect(updateSearchUrlSpy).toHaveBeenCalledWith({ term, filters: mockSearchState.filters });
...@@ -632,7 +637,7 @@ describe('search ducks', () => { ...@@ -632,7 +637,7 @@ describe('search ducks', () => {
testSaga(Sagas.setPageIndexWorker, setPageIndex(index, updateUrl)) testSaga(Sagas.setPageIndexWorker, setPageIndex(index, updateUrl))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(searchState).put(searchResource(searchState.search_term, searchState.selectedTab, index)) .next(searchState).put(searchResource(SearchType.PAGINATION, searchState.search_term, searchState.selectedTab, index))
.next().isDone(); .next().isDone();
expect(updateSearchUrlSpy).toHaveBeenCalled(); expect(updateSearchUrlSpy).toHaveBeenCalled();
}); });
...@@ -644,7 +649,7 @@ describe('search ducks', () => { ...@@ -644,7 +649,7 @@ describe('search ducks', () => {
testSaga(Sagas.setPageIndexWorker, setPageIndex(index, updateUrl)) testSaga(Sagas.setPageIndexWorker, setPageIndex(index, updateUrl))
.next().select(SearchUtils.getSearchState) .next().select(SearchUtils.getSearchState)
.next(searchState).put(searchResource(searchState.search_term, searchState.selectedTab, index)) .next(searchState).put(searchResource(SearchType.PAGINATION, searchState.search_term, searchState.selectedTab, index))
.next().isDone(); .next().isDone();
expect(updateSearchUrlSpy).not.toHaveBeenCalled(); expect(updateSearchUrlSpy).not.toHaveBeenCalled();
}); });
...@@ -679,7 +684,7 @@ describe('search ducks', () => { ...@@ -679,7 +684,7 @@ describe('search ducks', () => {
it('Calls searchAll when search term changes', () => { it('Calls searchAll when search term changes', () => {
term = 'new search'; term = 'new search';
sagaTest(urlDidUpdate(`term=${term}&resource=${resource}&index=${index}`)) sagaTest(urlDidUpdate(`term=${term}&resource=${resource}&index=${index}`))
.put(searchAll(term, resource, index)) .put(searchAll(SearchType.LOAD_URL, term, resource, index))
.next().isDone(); .next().isDone();
}); });
......
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
DashboardResource, DashboardResource,
Resource, Resource,
ResourceType, ResourceType,
SearchType,
TableResource, TableResource,
UserResource, UserResource,
} from 'interfaces'; } from 'interfaces';
...@@ -53,6 +54,7 @@ export interface SearchAllRequest { ...@@ -53,6 +54,7 @@ export interface SearchAllRequest {
pageIndex: number; pageIndex: number;
term: string; term: string;
useFilters?: boolean; useFilters?: boolean;
searchType: SearchType;
}; };
type: SearchAll.REQUEST; type: SearchAll.REQUEST;
}; };
...@@ -75,6 +77,7 @@ export interface SearchResourceRequest { ...@@ -75,6 +77,7 @@ export interface SearchResourceRequest {
pageIndex: number; pageIndex: number;
resource: ResourceType; resource: ResourceType;
term: string; term: string;
searchType: SearchType;
}; };
type: SearchResource.REQUEST; type: SearchResource.REQUEST;
}; };
......
...@@ -7,3 +7,13 @@ export enum FilterType { ...@@ -7,3 +7,13 @@ export enum FilterType {
CHECKBOX_SELECT = 'checkboxFilter', CHECKBOX_SELECT = 'checkboxFilter',
INPUT_SELECT = 'inputFilter' INPUT_SELECT = 'inputFilter'
} }
export enum SearchType {
CLEAR_TERM = 'clear_search_term',
FILTER = 'update_filter',
INLINE_SEARCH = 'inline_search',
INLINE_SELECT = 'inline_select',
LOAD_URL = 'load_url',
PAGINATION = 'update_page',
SUBMIT_TERM = 'submit_search_term',
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment