Skip to content

Commit

Permalink
Split useSavedQuery and restore capability of changing saved query in…
Browse files Browse the repository at this point in the history
… URL
  • Loading branch information
Liza K committed Feb 4, 2020
1 parent 3e6af5e commit 0f4ec5f
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 135 deletions.
173 changes: 38 additions & 135 deletions src/plugins/data/public/ui/search_bar/create_search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/

import React, { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { CoreStart } from 'src/core/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
import { KibanaContextProvider } from '../../../../kibana_react/public';
Expand All @@ -27,6 +26,7 @@ import { QueryStart } from '../../query';
import { SearchBarOwnProps, SearchBar } from './search_bar';
import { useFilterManager } from './lib/use_filter_manager';
import { useTimefilter } from './lib/use_timefilter';
import { useSavedQuery } from './lib/use_saved_query';

interface StatefulSearchBarDeps {
core: CoreStart;
Expand All @@ -41,12 +41,14 @@ export type StatefulSearchBarProps = SearchBarOwnProps & {
onSavedQueryIdChange?: (savedQueryId?: string) => void;
};

// Respond to user changing the filters
const defaultFiltersUpdated = (queryService: QueryStart) => {
return (filters: esFilters.Filter[]) => {
queryService.filterManager.setFilters(filters);
};
};

// Respond to user changing the refresh settings
const defaultOnRefreshChange = (queryService: QueryStart) => {
const { timefilter } = queryService.timefilter;
return (options: { isPaused: boolean; refreshInterval: number }) => {
Expand All @@ -57,6 +59,7 @@ const defaultOnRefreshChange = (queryService: QueryStart) => {
};
};

// Respond to user changing the query string or time settings
const defaultOnQuerySubmit = (
props: StatefulSearchBarProps,
queryService: QueryStart,
Expand All @@ -75,7 +78,7 @@ const defaultOnQuerySubmit = (
timefilter.setTime(payload.dateRange);
setQueryStringState(payload.query);
} else {
// If no change was detected, fire onQuerySubmit with current state
// Refresh button triggered for an update
if (props.onQuerySubmit)
props.onQuerySubmit(
{
Expand All @@ -88,91 +91,20 @@ const defaultOnQuerySubmit = (
};
};

const defaultOnClearSavedQuery = (
props: StatefulSearchBarProps,
uiSettings: CoreStart['uiSettings'],
queryService: QueryStart,
setQueryStringState: Function,
setSavedQueryState: Function
) => {
// Respond to user clearing a saved query
const defaultOnClearSavedQuery = (props: StatefulSearchBarProps, setSavedQuery: Function) => {
if (!props.useDefaultBehaviors) return props.onClearSavedQuery;
return () => {
queryService.filterManager.removeAll();
setQueryStringState({
query: '',
language: uiSettings.get('search:queryLanguage'),
});
setSavedQueryState(undefined);
setSavedQuery(undefined);
if (props.onSavedQueryIdChange) props.onSavedQueryIdChange();
};
};

const populateStateFromSavedQuery = (
props: StatefulSearchBarProps,
queryService: QueryStart,
savedQuery: SavedQuery,
setQueryStringState: Function,
setSavedQueryState: Function
) => {
const { timefilter } = queryService.timefilter;
// timefilter
if (savedQuery.attributes.timefilter) {
timefilter.setTime({
from: savedQuery.attributes.timefilter.from,
to: savedQuery.attributes.timefilter.to,
});
if (savedQuery.attributes.timefilter.refreshInterval) {
timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval);
}
}

// query string
setQueryStringState(savedQuery.attributes.query);
if (props.onQuerySubmit)
props.onQuerySubmit({ dateRange: timefilter.getTime(), query: savedQuery.attributes.query });

// filters
const savedQueryFilters = savedQuery.attributes.filters || [];
const globalFilters = queryService.filterManager.getGlobalFilters();
queryService.filterManager.setFilters([...globalFilters, ...savedQueryFilters]);

setSavedQueryState(savedQuery);
};

const defaultOnSavedQueryUpdated = (
props: StatefulSearchBarProps,
queryService: QueryStart,
setQueryStringState: Function,
setSavedQueryState: Function
) => {
// Respond to user saving or updating a saved query
const defaultOnSavedQueryUpdated = (props: StatefulSearchBarProps, setSavedQuery: Function) => {
if (!props.useDefaultBehaviors) return props.onSavedQueryUpdated;
return (savedQuery: SavedQuery) => {
populateStateFromSavedQuery(
props,
queryService,
savedQuery,
setQueryStringState,
setSavedQueryState
);
if (props.onSavedQueryIdChange) props.onSavedQueryIdChange(savedQuery.id);
};
};

const defaultOnQuerySaved = (
props: StatefulSearchBarProps,
queryService: QueryStart,
setQueryStringState: Function,
setSavedQueryState: Function
) => {
if (!props.useDefaultBehaviors) return props.onSaved;
return (savedQuery: SavedQuery) => {
populateStateFromSavedQuery(
props,
queryService,
savedQuery,
setQueryStringState,
setSavedQueryState
);
setSavedQuery(savedQuery);
if (props.onSavedQueryIdChange) props.onSavedQueryIdChange(savedQuery.id);
};
};
Expand All @@ -185,14 +117,6 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)
// App name should come from the core application service.
// Until it's available, we'll ask the user to provide it for the pre-wired component.
return (props: StatefulSearchBarProps) => {
const { appName, savedQueryId, onQuerySubmit } = props;
const { filterManager, timefilter, savedQueries } = data.query;

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

// Handle queries
const [query, setQuery] = useState<Query>(
props.query || {
Expand All @@ -201,52 +125,42 @@ 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 { timeRange, refreshInterval } = useTimefilter({
timefilter: data.query.timefilter.timefilter,
});

// Fetch and update UI from saved query
const [savedQuery, setSavedQuery] = useSavedQuery(
{
queryService: data.query,
setQuery,
savedQueryId: props.savedQueryId,
notifications: core.notifications,
uiSettings: core.uiSettings,
},
[props.savedQueryId]
);

// Fire onQuerySubmit on query or timerange change
useEffect(() => {
if (!props.useDefaultBehaviors) return;
if (onQuerySubmit)
onQuerySubmit(
if (props.onQuerySubmit)
props.onQuerySubmit(
{
dateRange: timeRange,
query,
},
true
);
}, [onQuerySubmit, props.useDefaultBehaviors, query, timeRange]);

// Handle saved queries
const [savedQuery, setSavedQuery] = useState<SavedQuery>();
useEffect(() => {
const fetchSavedQuery = async () => {
if (savedQueryId) {
try {
const newSavedQuery = await savedQueries.getSavedQuery(savedQueryId);
// Make sure we set the saved query to the most recent one
if (newSavedQuery && newSavedQuery.id === savedQueryId) {
setSavedQuery(newSavedQuery);
}
} catch (error) {
// Clear saved query
setSavedQuery(undefined);
core.notifications.toasts.addWarning({
title: i18n.translate('data.search.unableToGetSavedQueryToastTitle', {
defaultMessage: 'Unable to load saved query {savedQueryId}',
values: { savedQueryId },
}),
text: `${error.message}`,
});
}
} else {
setSavedQuery(undefined);
}
};
fetchSavedQuery();
}, [savedQueryId, savedQueries]);
}, [props, props.onQuerySubmit, props.useDefaultBehaviors, query, timeRange]);

return (
<KibanaContextProvider
services={{
appName,
appName: props.appName,
data,
storage,
...core,
Expand All @@ -261,7 +175,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)
showSaveQuery={props.showSaveQuery}
screenTitle={props.screenTitle}
indexPatterns={props.indexPatterns}
timeHistory={timefilter.history}
timeHistory={data.query.timefilter.history}
dateRangeFrom={timeRange.from}
dateRangeTo={timeRange.to}
refreshInterval={refreshInterval.value}
Expand All @@ -272,20 +186,9 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps)
onRefreshChange={defaultOnRefreshChange(data.query)}
savedQuery={savedQuery}
onQuerySubmit={defaultOnQuerySubmit(props, data.query, query, setQuery)}
onClearSavedQuery={defaultOnClearSavedQuery(
props,
core.uiSettings,
data.query,
setQuery,
setSavedQuery
)}
onSavedQueryUpdated={defaultOnSavedQueryUpdated(
props,
data.query,
setQuery,
setSavedQuery
)}
onSaved={defaultOnQuerySaved(props, data.query, setQuery, setSavedQuery)}
onClearSavedQuery={defaultOnClearSavedQuery(props, setSavedQuery)}
onSavedQueryUpdated={defaultOnSavedQueryUpdated(props, setSavedQuery)}
onSaved={defaultOnSavedQueryUpdated(props, setSavedQuery)}
{...overrideDefaultBehaviors(props)}
/>
</KibanaContextProvider>
Expand Down
33 changes: 33 additions & 0 deletions src/plugins/data/public/ui/search_bar/lib/clear_saved_query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* 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']
) => {
queryService.filterManager.removeAll();
setQueryStringState({
query: '',
language: uiSettings.get('search:queryLanguage'),
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { QueryStart, SavedQuery } from '../../..';

export const populateStateFromSavedQuery = (
queryService: QueryStart,
savedQuery: SavedQuery,
setQueryStringState: Function
) => {
const {
timefilter: { timefilter },
filterManager,
} = queryService;
// timefilter
if (savedQuery.attributes.timefilter) {
timefilter.setTime({
from: savedQuery.attributes.timefilter.from,
to: savedQuery.attributes.timefilter.to,
});
if (savedQuery.attributes.timefilter.refreshInterval) {
timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval);
}
}

// query string
setQueryStringState(savedQuery.attributes.query);

// filters
const savedQueryFilters = savedQuery.attributes.filters || [];
const globalFilters = filterManager.getGlobalFilters();
filterManager.setFilters([...globalFilters, ...savedQueryFilters]);
};
Loading

0 comments on commit 0f4ec5f

Please sign in to comment.