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

[Data] Query Input String manager #72093

Merged
merged 47 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
6f46c7a
improve test stability
Jul 9, 2020
b824176
Merge branch 'master' of github.com:elastic/kibana
Jul 9, 2020
995da7d
Merge branch 'master' of github.com:elastic/kibana
Jul 14, 2020
7b2a45c
Merge branch 'master' of github.com:elastic/kibana
Jul 15, 2020
c3a3822
Merge branch 'master' of github.com:elastic/kibana
Jul 16, 2020
a558b34
query string input manager (needed for search demo)
Jul 16, 2020
2aed579
docs
Jul 16, 2020
4e3b824
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 19, 2020
f2ecb4b
dashboard
Jul 19, 2020
dfdf2eb
Fix jest
Jul 19, 2020
903b89b
mock fix
Jul 20, 2020
90f94b6
Allow restoring a saved query
Jul 20, 2020
60e8758
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 20, 2020
bfe2723
sync url
Jul 20, 2020
dd1413a
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 22, 2020
dac36cb
Luke's fix to test
Jul 22, 2020
1d93750
cleanup
Jul 22, 2020
b657a5b
lens jest tests
Jul 22, 2020
82bc73d
docs
Jul 22, 2020
d5e9cf4
use queryStringManager.getDefaultQuery
Jul 22, 2020
a77fb01
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 22, 2020
2a9415e
Update app.test.tsx
lizozom Jul 22, 2020
f387415
jest fix
Jul 22, 2020
12e2195
jest
Jul 22, 2020
2c872de
use new api in the example
Dosant Jul 23, 2020
a7c834c
Rename state param to query to match url state
Jul 23, 2020
5c79c3b
Apply changes to discover
Jul 23, 2020
cf1e956
Merge branch 'data/queryinput-manager' of github.com:lizozom/kibana i…
Jul 23, 2020
6dcfe95
Update src/plugins/data/public/query/query_string/index.ts
lizozom Jul 23, 2020
9532ca9
Improve query string state manager
Jul 23, 2020
41cc06b
Cleanup dashboard code
Jul 23, 2020
783ea70
Merge branch 'data/queryinput-manager' of github.com:lizozom/kibana i…
Jul 23, 2020
07721a6
Handle refresh button
Jul 23, 2020
acd4708
Merge branch 'master' into data/queryinput-manager
elasticmachine Jul 23, 2020
3dc3bee
Merge branch 'data/queryinput-manager' of github.com:lizozom/kibana i…
Jul 23, 2020
9256ae7
Set initial dashboard state
Jul 23, 2020
71d0541
visualize state
Jul 23, 2020
8b29596
remove unused
Jul 23, 2020
723b8fc
docs
Jul 23, 2020
b0dc470
fix example
Jul 26, 2020
5f04c15
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 26, 2020
ae8d844
fix jest
Jul 27, 2020
08246fa
fix filter app state in discover
Jul 27, 2020
921c5a5
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 27, 2020
7b9211f
fix maps test
Jul 27, 2020
e13545b
jest
Jul 27, 2020
5c12dc2
Merge branch 'master' of github.com:elastic/kibana into data/queryinp…
Jul 28, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ Helper to setup two-way syncing of global data and a state container
<b>Signature:</b>

```typescript
connectToQueryState: <S extends QueryState>({ timefilter: { timefilter }, filterManager, state$, }: Pick<QueryStart | QuerySetup, 'timefilter' | 'filterManager' | 'state$'>, stateContainer: BaseStateContainer<S>, syncConfig: {
connectToQueryState: <S extends QueryState>({ timefilter: { timefilter }, filterManager, queryString, state$, }: Pick<QueryStart | QuerySetup, 'timefilter' | 'filterManager' | 'queryString' | 'state$'>, stateContainer: BaseStateContainer<S>, syncConfig: {
time?: boolean;
refreshInterval?: boolean;
filters?: FilterStateStore | boolean;
query?: boolean;
}) => () => void
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface QueryState
| Property | Type | Description |
| --- | --- | --- |
| [filters](./kibana-plugin-plugins-data-public.querystate.filters.md) | <code>Filter[]</code> | |
| [query](./kibana-plugin-plugins-data-public.querystate.query.md) | <code>Query</code> | |
| [refreshInterval](./kibana-plugin-plugins-data-public.querystate.refreshinterval.md) | <code>RefreshInterval</code> | |
| [time](./kibana-plugin-plugins-data-public.querystate.time.md) | <code>TimeRange</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [QueryState](./kibana-plugin-plugins-data-public.querystate.md) &gt; [query](./kibana-plugin-plugins-data-public.querystate.query.md)

## QueryState.query property

<b>Signature:</b>

```typescript
query?: Query;
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Helper to setup syncing of global data with the URL
<b>Signature:</b>

```typescript
syncQueryStateWithUrl: (query: Pick<QueryStart | QuerySetup, 'filterManager' | 'timefilter' | 'state$'>, kbnUrlStateStorage: IKbnUrlStateStorage) => {
syncQueryStateWithUrl: (query: Pick<QueryStart | QuerySetup, 'filterManager' | 'timefilter' | 'queryString' | 'state$'>, kbnUrlStateStorage: IKbnUrlStateStorage) => {
stop: () => void;
hasInheritedQueryFromUrl: boolean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import React, { useEffect, useRef, useState, useCallback } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { History } from 'history';
import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
import { Router } from 'react-router-dom';
Expand Down Expand Up @@ -85,16 +85,9 @@ const App = ({ navigation, data, history, kbnUrlStateStorage }: StateDemoAppDeps
useGlobalStateSyncing(data.query, kbnUrlStateStorage);
useAppStateSyncing(appStateContainer, data.query, kbnUrlStateStorage);

const onQuerySubmit = useCallback(
({ query }) => {
appStateContainer.set({ ...appState, query });
},
[appStateContainer, appState]
);

const indexPattern = useIndexPattern(data);
if (!indexPattern)
return <div>No index pattern found. Please create an intex patter before loading...</div>;
return <div>No index pattern found. Please create an index patter before loading...</div>;

// Render the application DOM.
// Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.
Expand All @@ -107,8 +100,6 @@ const App = ({ navigation, data, history, kbnUrlStateStorage }: StateDemoAppDeps
showSearchBar={true}
indexPatterns={[indexPattern]}
useDefaultBehaviors={true}
onQuerySubmit={onQuerySubmit}
query={appState.query}
showSaveQuery={true}
/>
<EuiPage restrictWidth="1000px">
Expand Down Expand Up @@ -200,7 +191,7 @@ function useAppStateSyncing<AppState extends QueryState>(
const stopSyncingQueryAppStateWithStateContainer = connectToQueryState(
query,
appStateContainer,
{ filters: esFilters.FilterStateStore.APP_STATE }
{ filters: esFilters.FilterStateStore.APP_STATE, query: true }
);

// sets up syncing app state container with url
Expand Down
5 changes: 4 additions & 1 deletion src/plugins/dashboard/public/application/dashboard_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export interface DashboardAppScope extends ng.IScope {
expandedPanel?: string;
getShouldShowEditHelp: () => boolean;
getShouldShowViewHelp: () => boolean;
updateQueryAndFetch: ({ query, dateRange }: { query: Query; dateRange?: TimeRange }) => void;
handleRefresh: (
{ query, dateRange }: { query?: Query; dateRange: TimeRange },
isUpdate?: boolean
) => void;
topNavMenu: any;
showAddPanel: any;
showSaveQuery: boolean;
Expand Down
103 changes: 39 additions & 64 deletions src/plugins/dashboard/public/application/dashboard_app_controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,21 @@ import React, { useState, ReactElement } from 'react';
import ReactDOM from 'react-dom';
import angular from 'angular';

import { Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { Subscription, merge } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
import { History } from 'history';
import { SavedObjectSaveOpts } from 'src/plugins/saved_objects/public';
import { NavigationPublicPluginStart as NavigationStart } from 'src/plugins/navigation/public';
import { TimeRange } from 'src/plugins/data/public';
import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen';

import {
connectToQueryState,
esFilters,
IndexPattern,
IndexPatternsContract,
Query,
QueryState,
SavedQuery,
syncQueryStateWithUrl,
UI_SETTINGS,
} from '../../../data/public';
import { getSavedObjectFinder, SaveResult, showSaveModal } from '../../../saved_objects/public';

Expand Down Expand Up @@ -81,8 +78,8 @@ import {
addFatalError,
AngularHttpError,
KibanaLegacyStart,
migrateLegacyQuery,
subscribeWithScope,
migrateLegacyQuery,
} from '../../../kibana_legacy/public';

export interface DashboardAppControllerDependencies extends RenderDeps {
Expand Down Expand Up @@ -127,7 +124,6 @@ export class DashboardAppController {
$route,
$routeParams,
dashboardConfig,
localStorage,
indexPatterns,
savedQueryService,
embeddable,
Expand All @@ -153,8 +149,8 @@ export class DashboardAppController {
navigation,
}: DashboardAppControllerDependencies) {
const filterManager = queryService.filterManager;
const queryFilter = filterManager;
const timefilter = queryService.timefilter.timefilter;
const queryStringManager = queryService.queryString;
const isEmbeddedExternally = Boolean($routeParams.embed);

// url param rules should only apply when embedded (e.g. url?embed=true)
Expand Down Expand Up @@ -184,20 +180,30 @@ export class DashboardAppController {
// sync initial app filters from state to filterManager
// if there is an existing similar global filter, then leave it as global
filterManager.setAppFilters(_.cloneDeep(dashboardStateManager.appState.filters));
queryStringManager.setQuery(migrateLegacyQuery(dashboardStateManager.appState.query));

// setup syncing of app filters between appState and filterManager
const stopSyncingAppFilters = connectToQueryState(
queryService,
{
set: ({ filters }) => dashboardStateManager.setFilters(filters || []),
get: () => ({ filters: dashboardStateManager.appState.filters }),
set: ({ filters, query }) => {
dashboardStateManager.setFilters(filters || []);
dashboardStateManager.setQuery(query || queryStringManager.getDefaultQuery());
},
get: () => ({
filters: dashboardStateManager.appState.filters,
query: dashboardStateManager.getQuery(),
}),
state$: dashboardStateManager.appState$.pipe(
map((state) => ({
filters: state.filters,
query: queryStringManager.formatQuery(state.query),
}))
),
},
{
filters: esFilters.FilterStateStore.APP_STATE,
query: true,
}
);

Expand Down Expand Up @@ -316,7 +322,7 @@ export class DashboardAppController {
const isEmptyInReadonlyMode = shouldShowUnauthorizedEmptyState();
return {
id: dashboardStateManager.savedDashboard.id || '',
filters: queryFilter.getFilters(),
filters: filterManager.getFilters(),
hidePanelTitles: dashboardStateManager.getHidePanelTitles(),
query: $scope.model.query,
timeRange: {
Expand All @@ -341,7 +347,7 @@ export class DashboardAppController {
// https://github.com/angular/angular.js/wiki/Understanding-Scopes
$scope.model = {
query: dashboardStateManager.getQuery(),
filters: queryFilter.getFilters(),
filters: filterManager.getFilters(),
timeRestore: dashboardStateManager.getTimeRestore(),
title: dashboardStateManager.getTitle(),
description: dashboardStateManager.getDescription(),
Expand Down Expand Up @@ -399,12 +405,12 @@ export class DashboardAppController {
if (
!esFilters.compareFilters(
container.getInput().filters,
queryFilter.getFilters(),
filterManager.getFilters(),
esFilters.COMPARE_ALL_OPTIONS
)
) {
// Add filters modifies the object passed to it, hence the clone deep.
queryFilter.addFilters(_.cloneDeep(container.getInput().filters));
filterManager.addFilters(_.cloneDeep(container.getInput().filters));

dashboardStateManager.applyFilters(
$scope.model.query,
Expand Down Expand Up @@ -463,13 +469,8 @@ export class DashboardAppController {
});

dashboardStateManager.applyFilters(
dashboardStateManager.getQuery() || {
query: '',
language:
localStorage.get('kibana.userQueryLanguage') ||
uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE),
},
queryFilter.getFilters()
dashboardStateManager.getQuery() || queryStringManager.getDefaultQuery(),
filterManager.getFilters()
);

timefilter.disableTimeRangeSelector();
Expand Down Expand Up @@ -543,21 +544,13 @@ export class DashboardAppController {
}
};

$scope.updateQueryAndFetch = function ({ query, dateRange }) {
if (dateRange) {
timefilter.setTime(dateRange);
}

const oldQuery = $scope.model.query;
if (_.isEqual(oldQuery, query)) {
$scope.handleRefresh = function (_payload, isUpdate) {
if (isUpdate === false) {
// The user can still request a reload in the query bar, even if the
// query is the same, and in that case, we have to explicitly ask for
// a reload, since no state changes will cause it.
lastReloadRequestTime = new Date().getTime();
refreshDashboardContainer();
} else {
$scope.model.query = query;
dashboardStateManager.applyFilters($scope.model.query, $scope.model.filters);
}
};

Expand All @@ -576,7 +569,7 @@ export class DashboardAppController {
// Making this method sync broke the updates.
// Temporary fix, until we fix the complex state in this file.
setTimeout(() => {
queryFilter.setFilters(allFilters);
filterManager.setFilters(allFilters);
}, 0);
};

Expand Down Expand Up @@ -609,11 +602,6 @@ export class DashboardAppController {

$scope.indexPatterns = [];

$scope.$watch('model.query', (newQuery: Query) => {
const query = migrateLegacyQuery(newQuery) as Query;
$scope.updateQueryAndFetch({ query });
});

$scope.$watch(
() => dashboardCapabilities.saveQuery,
(newCapability) => {
Expand Down Expand Up @@ -654,18 +642,11 @@ export class DashboardAppController {
showFilterBar,
indexPatterns: $scope.indexPatterns,
showSaveQuery: $scope.showSaveQuery,
query: $scope.model.query,
savedQuery: $scope.savedQuery,
onSavedQueryIdChange,
savedQueryId: dashboardStateManager.getSavedQueryId(),
useDefaultBehaviors: true,
onQuerySubmit: (payload: { dateRange: TimeRange; query?: Query }): void => {
if (!payload.query) {
$scope.updateQueryAndFetch({ query: $scope.model.query, dateRange: payload.dateRange });
} else {
$scope.updateQueryAndFetch({ query: payload.query, dateRange: payload.dateRange });
}
},
onQuerySubmit: $scope.handleRefresh,
};
};
const dashboardNavBar = document.getElementById('dashboardChrome');
Expand All @@ -680,25 +661,11 @@ export class DashboardAppController {
};

$scope.timefilterSubscriptions$ = new Subscription();

const timeChanges$ = merge(timefilter.getRefreshIntervalUpdate$(), timefilter.getTimeUpdate$());
$scope.timefilterSubscriptions$.add(
subscribeWithScope(
$scope,
timefilter.getRefreshIntervalUpdate$(),
{
next: () => {
updateState();
refreshDashboardContainer();
},
},
(error: AngularHttpError | Error | string) => addFatalError(fatalErrors, error)
)
);

$scope.timefilterSubscriptions$.add(
subscribeWithScope(
$scope,
timefilter.getTimeUpdate$(),
timeChanges$,
{
next: () => {
updateState();
Expand Down Expand Up @@ -1071,13 +1038,21 @@ export class DashboardAppController {

updateViewMode(dashboardStateManager.getViewMode());

const filterChanges = merge(filterManager.getUpdates$(), queryStringManager.getUpdates$()).pipe(
debounceTime(100)
);

// update root source when filters update
const updateSubscription = queryFilter.getUpdates$().subscribe({
const updateSubscription = filterChanges.subscribe({
next: () => {
$scope.model.filters = queryFilter.getFilters();
$scope.model.filters = filterManager.getFilters();
$scope.model.query = queryStringManager.getQuery();
dashboardStateManager.applyFilters($scope.model.query, $scope.model.filters);
if (dashboardContainer) {
dashboardContainer.updateInput({ filters: $scope.model.filters });
dashboardContainer.updateInput({
filters: $scope.model.filters,
query: $scope.model.query,
});
}
},
});
Expand Down
9 changes: 6 additions & 3 deletions src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,11 @@ export const castEsToKbnFieldTypeName: (esType: ES_FIELD_TYPES | string) => KBN_
// Warning: (ae-missing-release-tag) "connectToQueryState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export const connectToQueryState: <S extends QueryState>({ timefilter: { timefilter }, filterManager, state$, }: Pick<QueryStart | QuerySetup, 'timefilter' | 'filterManager' | 'state$'>, stateContainer: BaseStateContainer<S>, syncConfig: {
export const connectToQueryState: <S extends QueryState>({ timefilter: { timefilter }, filterManager, queryString, state$, }: Pick<QueryStart | QuerySetup, 'timefilter' | 'filterManager' | 'queryString' | 'state$'>, stateContainer: BaseStateContainer<S>, syncConfig: {
time?: boolean;
refreshInterval?: boolean;
filters?: FilterStateStore | boolean;
query?: boolean;
}) => () => void;

// Warning: (ae-missing-release-tag) "createSavedQueryService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down Expand Up @@ -1497,6 +1498,8 @@ export interface QueryState {
// (undocumented)
filters?: Filter[];
// (undocumented)
query?: Query;
// (undocumented)
refreshInterval?: RefreshInterval;
// (undocumented)
time?: TimeRange;
Expand Down Expand Up @@ -1871,7 +1874,7 @@ export type StatefulSearchBarProps = SearchBarOwnProps & {
// Warning: (ae-missing-release-tag) "syncQueryStateWithUrl" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export const syncQueryStateWithUrl: (query: Pick<QueryStart | QuerySetup, 'filterManager' | 'timefilter' | 'state$'>, kbnUrlStateStorage: IKbnUrlStateStorage) => {
export const syncQueryStateWithUrl: (query: Pick<QueryStart | QuerySetup, 'filterManager' | 'timefilter' | 'queryString' | 'state$'>, kbnUrlStateStorage: IKbnUrlStateStorage) => {
stop: () => void;
hasInheritedQueryFromUrl: boolean;
};
Expand Down Expand Up @@ -2019,7 +2022,7 @@ export const UI_SETTINGS: {
// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:41:60 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:45:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:54:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:55:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:63:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts
Expand Down
Loading