Skip to content

Commit

Permalink
Support filter intial values
Browse files Browse the repository at this point in the history
Improve useSavedQuery hook in terface
  • Loading branch information
Liza K committed Feb 4, 2020
1 parent 782a857 commit 48527de
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
app-name="'context'"
show-search-bar="true"
show-filter-bar="true"
show-query-bar="false"
show-save-query="false"
show-date-picker="false"

filters="contextApp.state.queryParameters.filters"
on-filters-updated="contextApp.actions.updateFilters"

index-patterns="[contextApp.indexPattern]"
use-default-behaviors="true"
>
</kbn-top-nav>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import _ from 'lodash';
import { getServices, callAfterBindingsWorkaround, getAngularModule } from '../../kibana_services';
import { callAfterBindingsWorkaround, getAngularModule } from '../../kibana_services';
import contextAppTemplate from './context_app.html';
import './context/components/action_bar';
import { getFirstSortableField } from './context/api/utils/sorting';
Expand All @@ -34,8 +34,6 @@ import {
QueryActionsProvider,
} from './context/query';

const { timefilter } = getServices();

const module = getAngularModule();

module.directive('contextApp', function ContextApp() {
Expand All @@ -61,10 +59,6 @@ module.directive('contextApp', function ContextApp() {
function ContextAppController($scope, config, Private) {
const queryParameterActions = getQueryParameterActions();
const queryActions = Private(QueryActionsProvider);

timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();

this.state = createInitialState(
parseInt(config.get('context:step'), 10),
getFirstSortableField(this.indexPattern, config.get('context:tieBreakerFields')),
Expand Down
13 changes: 8 additions & 5 deletions src/plugins/data/public/ui/search_bar/create_search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ const defaultOnQuerySubmit = (
};

// Respond to user clearing a saved query
const defaultOnClearSavedQuery = (props: StatefulSearchBarProps, setSavedQuery: Function) => {
const defaultOnClearSavedQuery = (props: StatefulSearchBarProps, clearSavedQuery: Function) => {
if (!props.useDefaultBehaviors) return props.onClearSavedQuery;
return () => {
setSavedQuery(undefined);
clearSavedQuery();
if (props.onSavedQueryIdChange) props.onSavedQueryIdChange();
};
};
Expand Down Expand Up @@ -127,13 +127,16 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)

// handle service state updates.
// i.e. filters being added from a visualization directly to filterManager.
const { filters } = useFilterManager({ filterManager: data.query.filterManager });
const { filters } = useFilterManager({
filters: props.filters,
filterManager: data.query.filterManager,
});
const { timeRange, refreshInterval } = useTimefilter({
timefilter: data.query.timefilter.timefilter,
});

// Fetch and update UI from saved query
const [savedQuery, setSavedQuery] = useSavedQuery({
const { savedQuery, setSavedQuery, clearSavedQuery } = useSavedQuery({
queryService: data.query,
setQuery,
savedQueryId: props.savedQueryId,
Expand Down Expand Up @@ -183,7 +186,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)
onRefreshChange={defaultOnRefreshChange(data.query)}
savedQuery={savedQuery}
onQuerySubmit={defaultOnQuerySubmit(props, data.query, query, setQuery)}
onClearSavedQuery={defaultOnClearSavedQuery(props, setSavedQuery)}
onClearSavedQuery={defaultOnClearSavedQuery(props, clearSavedQuery)}
onSavedQueryUpdated={defaultOnSavedQueryUpdated(props, setSavedQuery)}
onSaved={defaultOnSavedQueryUpdated(props, setSavedQuery)}
{...overrideDefaultBehaviors(props)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@
import { clearStateFromSavedQuery } from './clear_saved_query';

import { dataPluginMock } from '../../../mocks';
import { coreMock } from '../../../../../../core/public/mocks';
import { DataPublicPluginStart } from '../../../types';
import { Query } from '../../..';

describe('clearStateFromSavedQuery', () => {
const DEFAULT_LANGUAGE = 'banana';
let dataMock: jest.Mocked<DataPublicPluginStart>;
const core = coreMock.createStart();

beforeEach(() => {
dataMock = dataPluginMock.createStartContract();
Expand All @@ -35,21 +34,17 @@ describe('clearStateFromSavedQuery', () => {
it('should clear filters and query', async () => {
const setQueryState = jest.fn();
dataMock.query.filterManager.removeAll = jest.fn();
clearStateFromSavedQuery(dataMock.query, setQueryState, core.uiSettings);
clearStateFromSavedQuery(dataMock.query, setQueryState, DEFAULT_LANGUAGE);
expect(setQueryState).toHaveBeenCalled();
expect(dataMock.query.filterManager.removeAll).toHaveBeenCalled();
});

it('should use search:queryLanguage', async () => {
const LANGUAGE = 'banana';
const setQueryState = jest.fn();
dataMock.query.filterManager.removeAll = jest.fn();
core.uiSettings.get.mockImplementation((key: string) => {
return key === 'search:queryLanguage' ? LANGUAGE : undefined;
});
clearStateFromSavedQuery(dataMock.query, setQueryState, core.uiSettings);
clearStateFromSavedQuery(dataMock.query, setQueryState, DEFAULT_LANGUAGE);
expect(setQueryState).toHaveBeenCalled();
expect((setQueryState.mock.calls[0][0] as Query).language).toBe(LANGUAGE);
expect((setQueryState.mock.calls[0][0] as Query).language).toBe(DEFAULT_LANGUAGE);
expect(dataMock.query.filterManager.removeAll).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/

import { CoreStart } from 'kibana/public';
import { QueryStart } from '../../../query';

export const clearStateFromSavedQuery = (
queryService: QueryStart,
setQueryStringState: Function,
uiSettings: CoreStart['uiSettings']
defaultLanguage: string
) => {
queryService.filterManager.removeAll();
setQueryStringState({
query: '',
language: uiSettings.get('search:queryLanguage'),
language: defaultLanguage,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { populateStateFromSavedQuery } from './populate_state_from_saved_query';

import { dataPluginMock } from '../../../mocks';
import { DataPublicPluginStart } from '../../../types';
import { SavedQuery, Query, esFilters } from '../../..';
import { SavedQuery, esFilters } from '../../..';
import { getFilter } from '../../../query/filter_manager/test_helpers/get_stub_filter';

describe('populateStateFromSavedQuery', () => {
Expand Down Expand Up @@ -50,7 +50,7 @@ describe('populateStateFromSavedQuery', () => {
const savedQuery: SavedQuery = {
...baseSavedQuery,
};
populateStateFromSavedQuery(dataMock.query, savedQuery, setQueryState);
populateStateFromSavedQuery(dataMock.query, setQueryState, savedQuery);
expect(setQueryState).toHaveBeenCalled();
});

Expand All @@ -61,7 +61,7 @@ describe('populateStateFromSavedQuery', () => {
};
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
savedQuery.attributes.filters = [f1];
populateStateFromSavedQuery(dataMock.query, savedQuery, setQueryState);
populateStateFromSavedQuery(dataMock.query, setQueryState, savedQuery);
expect(setQueryState).toHaveBeenCalled();
expect(dataMock.query.filterManager.setFilters).toHaveBeenCalledWith([f1]);
});
Expand All @@ -81,7 +81,7 @@ describe('populateStateFromSavedQuery', () => {
};
const f1 = getFilter(esFilters.FilterStateStore.APP_STATE, false, false, 'age', 34);
savedQuery.attributes.filters = [f1];
populateStateFromSavedQuery(dataMock.query, savedQuery, setQueryState);
populateStateFromSavedQuery(dataMock.query, setQueryState, savedQuery);
expect(setQueryState).toHaveBeenCalled();
expect(dataMock.query.filterManager.setFilters).toHaveBeenCalledWith([globalFilter, f1]);
});
Expand All @@ -102,7 +102,7 @@ describe('populateStateFromSavedQuery', () => {
dataMock.query.timefilter.timefilter.setTime = jest.fn();
dataMock.query.timefilter.timefilter.setRefreshInterval = jest.fn();

populateStateFromSavedQuery(dataMock.query, savedQuery, jest.fn());
populateStateFromSavedQuery(dataMock.query, jest.fn(), savedQuery);

expect(dataMock.query.timefilter.timefilter.setTime).toHaveBeenCalledWith({
from: savedQuery.attributes.timefilter.from,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { QueryStart, SavedQuery } from '../../..';

export const populateStateFromSavedQuery = (
queryService: QueryStart,
savedQuery: SavedQuery,
setQueryStringState: Function
setQueryStringState: Function,
savedQuery: SavedQuery
) => {
const {
timefilter: { timefilter },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@

import { useState, useEffect } from 'react';
import { Subscription } from 'rxjs';
import { DataPublicPluginStart } from 'src/plugins/data/public';
import { DataPublicPluginStart, esFilters } from '../../..';

interface UseFilterManagerProps {
filters?: esFilters.Filter[];
filterManager: DataPublicPluginStart['query']['filterManager'];
}

export const useFilterManager = (props: UseFilterManagerProps) => {
const [filters, setFilters] = useState(props.filterManager.getFilters());
// Filters should be either what's passed in the initial state or the current state of the filter manager
const [filters, setFilters] = useState(props.filters || props.filterManager.getFilters());
useEffect(() => {
const subscriptions = new Subscription();

Expand Down
89 changes: 48 additions & 41 deletions src/plugins/data/public/ui/search_bar/lib/use_saved_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import { useState, useEffect, SetStateAction, Dispatch } from 'react';
import { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { CoreStart } from 'kibana/public';
import { SavedQuery } from '../../../query';
Expand All @@ -33,55 +33,62 @@ interface UseSavedQueriesProps {
savedQueryId?: string;
}

type UseSavedQueriesRet = [
SavedQuery | undefined,
Dispatch<SetStateAction<SavedQuery | undefined>>
];
interface UseSavedQueriesReturn {
savedQuery?: SavedQuery;
setSavedQuery: (savedQuery: SavedQuery) => void;
clearSavedQuery: () => void;
}

export const useSavedQuery = (props: UseSavedQueriesProps): UseSavedQueriesRet => {
export const useSavedQuery = (props: UseSavedQueriesProps): UseSavedQueriesReturn => {
// Handle saved queries
const [savedQuery, setSavedQuery] = useState<SavedQuery>();
const defaultLanguage = props.uiSettings.get('search:queryLanguage');
const [savedQuery, setSavedQuery] = useState<SavedQuery | undefined>();

// Effect is used to convert a saved query id into an object
useEffect(() => {
const fetchSavedQuery = async () => {
if (props.savedQueryId) {
try {
// fetch saved query
const newSavedQuery = await props.queryService.savedQueries.getSavedQuery(
props.savedQueryId
);
// Make sure we set the saved query to the most recent one
if (newSavedQuery && newSavedQuery.id === props.savedQueryId) {
setSavedQuery(newSavedQuery);
}
} catch (error) {
// Clear saved query
setSavedQuery(undefined);
// notify of saving error
props.notifications.toasts.addWarning({
title: i18n.translate('data.search.unableToGetSavedQueryToastTitle', {
defaultMessage: 'Unable to load saved query {savedQueryId}',
values: { savedQueryId: props.savedQueryId },
}),
text: `${error.message}`,
});
const fetchSavedQuery = async (savedQueryId: string) => {
try {
// fetch saved query
const newSavedQuery = await props.queryService.savedQueries.getSavedQuery(savedQueryId);
// Make sure we set the saved query to the most recent one
if (newSavedQuery && newSavedQuery.id === savedQueryId) {
setSavedQuery(newSavedQuery);
populateStateFromSavedQuery(props.queryService, props.setQuery, newSavedQuery);
}
} else {
} catch (error) {
// Clear saved query
setSavedQuery(undefined);
clearStateFromSavedQuery(props.queryService, props.setQuery, defaultLanguage);
// notify of saving error
props.notifications.toasts.addWarning({
title: i18n.translate('data.search.unableToGetSavedQueryToastTitle', {
defaultMessage: 'Unable to load saved query {savedQueryId}',
values: { savedQueryId },
}),
text: `${error.message}`,
});
}
};

fetchSavedQuery();
}, [props.notifications.toasts, props.queryService.savedQueries, props.savedQueryId]);

useEffect(() => {
if (savedQuery) {
populateStateFromSavedQuery(props.queryService, savedQuery, props.setQuery);
} else {
clearStateFromSavedQuery(props.queryService, props.setQuery, props.uiSettings);
}
}, [savedQuery, props.queryService, props.setQuery, props.uiSettings]);
if (props.savedQueryId) fetchSavedQuery(props.savedQueryId);
}, [
defaultLanguage,
props.notifications.toasts,
props.queryService,
props.queryService.savedQueries,
props.savedQueryId,
props.setQuery,
]);

return [savedQuery, setSavedQuery];
return {
savedQuery,
setSavedQuery: (q: SavedQuery) => {
setSavedQuery(q);
populateStateFromSavedQuery(props.queryService, props.setQuery, q);
},
clearSavedQuery: () => {
setSavedQuery(undefined);
clearStateFromSavedQuery(props.queryService, props.setQuery, defaultLanguage);
},
};
};
2 changes: 1 addition & 1 deletion src/plugins/data/public/ui/search_bar/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ interface SearchBarInjectedDeps {
timeHistory: TimeHistoryContract;
// Filter bar
onFiltersUpdated?: (filters: esFilters.Filter[]) => void;
filters?: esFilters.Filter[];
// Date picker
dateRangeFrom?: string;
dateRangeTo?: string;
Expand All @@ -69,6 +68,7 @@ export interface SearchBarOwnProps {
showFilterBar?: boolean;
showDatePicker?: boolean;
showAutoRefreshOnly?: boolean;
filters?: esFilters.Filter[];
// Query bar - should be in SearchBarInjectedDeps
query?: Query;
// Show when user has privileges to save
Expand Down

0 comments on commit 48527de

Please sign in to comment.