From ba2c456ddf4a320cd024d14572b675a0dbc13570 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 9 Dec 2019 17:24:16 -0600 Subject: [PATCH 01/16] [Logs UI] Refactor query bar state to hooks --- .../containers/logs/log_filter/index.ts | 113 ++++++++++++++++-- .../logs/log_highlights/redux_bridges.tsx | 16 +-- .../logs/log_summary/with_summary.ts | 6 +- .../containers/logs/with_log_filter.tsx | 79 ++++++------ .../infra/public/store/local/actions.ts | 1 - .../public/store/local/log_filter/actions.ts | 15 --- .../public/store/local/log_filter/index.ts | 11 -- .../public/store/local/log_filter/reducer.ts | 43 ------- .../store/local/log_filter/selectors.ts | 32 ----- .../infra/public/store/local/reducer.ts | 4 - .../infra/public/store/local/selectors.ts | 6 - 11 files changed, 143 insertions(+), 183 deletions(-) delete mode 100644 x-pack/legacy/plugins/infra/public/store/local/log_filter/actions.ts delete mode 100644 x-pack/legacy/plugins/infra/public/store/local/log_filter/index.ts delete mode 100644 x-pack/legacy/plugins/infra/public/store/local/log_filter/reducer.ts delete mode 100644 x-pack/legacy/plugins/infra/public/store/local/log_filter/selectors.ts diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts index a737d19a5923..8bcd3265b643 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts @@ -4,23 +4,114 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useContext } from 'react'; +import { useReducer, useMemo } from 'react'; import createContainer from 'constate'; -import { ReduxStateContext } from '../../../utils/redux_context'; -import { logFilterSelectors as logFilterReduxSelectors } from '../../../store/local/selectors'; +import { esKuery } from '../../../../../../../../src/plugins/data/public'; -export const useLogFilterState = () => { - const { local: state } = useContext(ReduxStateContext); - const filterQuery = logFilterReduxSelectors.selectLogFilterQueryAsJson(state); - return { filterQuery }; -}; +enum Action { + SetDraftFilterQuery, + ApplyFilterQuery, +} + +interface SetDraftQueryAction { + type: Action.SetDraftFilterQuery; + payload: FilterQuery | null; +} + +interface ApplyFilterQueryAction { + type: Action.ApplyFilterQuery; + payload: SerializedFilterQuery; +} + +type ActionObj = SetDraftQueryAction | ApplyFilterQueryAction; -export interface LogFilterStateParams { - filterQuery: string | null; +export interface KueryFilterQuery { + kind: 'kuery'; + expression: string; } -export const logFilterInitialState = { +export type FilterQuery = KueryFilterQuery; + +export interface SerializedFilterQuery { + query: FilterQuery; + serializedQuery: string; +} + +interface LogFilterBaseStateParams { + filterQuery: SerializedFilterQuery | null; + filterQueryDraft: KueryFilterQuery | null; +} + +export const logFilterInitialState: LogFilterBaseStateParams = { filterQuery: null, + filterQueryDraft: null, +}; + +interface LogFilterDerivatives { + isFilterQueryDraftValid: boolean; + filterQueryAsJson: SerializedFilterQuery['serializedQuery'] | null; + filterQuery: FilterQuery | null; +} + +export type LogFilterStateParams = Omit & + LogFilterDerivatives; + +export interface LogFilterCallbacks { + setLogFilterQueryDraft: (payload: FilterQuery) => void; + applyLogFilterQuery: (payload: SerializedFilterQuery) => void; +} + +const getDerivatives = (state: LogFilterBaseStateParams) => ({ + get isFilterQueryDraftValid() { + const { filterQueryDraft } = state; + if (filterQueryDraft && filterQueryDraft.kind === 'kuery') { + try { + esKuery.fromKueryExpression(filterQueryDraft.expression); + } catch (err) { + return false; + } + } + + return true; + }, + get filterQueryAsJson() { + const { filterQuery } = state; + return filterQuery ? filterQuery.serializedQuery : null; + }, + get filterQuery() { + const { filterQuery } = state; + return filterQuery ? filterQuery.query : null; + }, +}); + +export const useLogFilterState: () => [LogFilterStateParams, LogFilterCallbacks] = () => { + const [state, dispatch] = useReducer(logFilterStateReducer, logFilterInitialState); + + const callbacks = useMemo( + () => ({ + setLogFilterQueryDraft: (payload: FilterQuery) => + dispatch({ type: Action.SetDraftFilterQuery, payload }), + + applyLogFilterQuery: (payload: SerializedFilterQuery) => + dispatch({ type: Action.ApplyFilterQuery, payload }), + }), + [] + ); + + const derivatives = useMemo(() => getDerivatives(state), [state]); + + return [{ ...state, ...derivatives }, callbacks]; +}; + +const logFilterStateReducer = (prevState: LogFilterBaseStateParams, action: ActionObj) => { + switch (action.type) { + case Action.SetDraftFilterQuery: + return { ...prevState, filterQueryDraft: action.payload }; + case Action.ApplyFilterQuery: + return { ...prevState, filterQueryDraft: action.payload.query, filterQuery: action.payload }; + default: + throw new Error(); + } }; export const LogFilterState = createContainer(useLogFilterState); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx index 2b60c6edd97a..87b9edf891f8 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_highlights/redux_bridges.tsx @@ -7,7 +7,6 @@ import React, { useEffect, useContext } from 'react'; import { TimeKey } from '../../../../common/time'; -import { withLogFilter } from '../with_log_filter'; import { withLogPosition } from '../with_log_position'; import { LogHighlightsState } from './log_highlights'; @@ -35,21 +34,8 @@ export const LogHighlightsPositionBridge = withLogPosition( } ); -export const LogHighlightsFilterQueryBridge = withLogFilter( - ({ serializedFilterQuery }: { serializedFilterQuery: string | null }) => { - const { setFilterQuery } = useContext(LogHighlightsState.Context); - - useEffect(() => { - setFilterQuery(serializedFilterQuery); - }, [serializedFilterQuery]); - - return null; - } -); - -export const LogHighlightsBridge = ({ indexPattern }: { indexPattern: any }) => ( +export const LogHighlightsBridge = () => ( <> - ); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts index 61c603130df5..71cc36cd97bf 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts @@ -7,19 +7,18 @@ import { useContext } from 'react'; import { connect } from 'react-redux'; -import { logFilterSelectors, logPositionSelectors, State } from '../../../store'; +import { logPositionSelectors, State } from '../../../store'; import { RendererFunction } from '../../../utils/typed_react'; import { Source } from '../../source'; import { LogViewConfiguration } from '../log_view_configuration'; import { LogSummaryBuckets, useLogSummary } from './log_summary'; +import { LogFilterState } from '../log_filter'; export const WithSummary = connect((state: State) => ({ visibleMidpointTime: logPositionSelectors.selectVisibleMidpointOrTargetTime(state), - filterQuery: logFilterSelectors.selectLogFilterQueryAsJson(state), }))( ({ children, - filterQuery, visibleMidpointTime, }: { children: RendererFunction<{ @@ -32,6 +31,7 @@ export const WithSummary = connect((state: State) => ({ }) => { const { intervalSize } = useContext(LogViewConfiguration.Context); const { sourceId } = useContext(Source.Context); + const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); const { buckets, start, end } = useLogSummary( sourceId, diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx index 60261fc728eb..1b4943fa51f2 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx @@ -4,62 +4,57 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { connect } from 'react-redux'; - +import React, { useContext } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; -import { logFilterActions, logFilterSelectors, State } from '../../store'; -import { FilterQuery } from '../../store/local/log_filter'; +import { LogFilterState, LogFilterStateParams, FilterQuery } from './log_filter'; + import { convertKueryToElasticSearchQuery } from '../../utils/kuery'; -import { asChildFunctionRenderer } from '../../utils/typed_react'; -import { bindPlainActionCreators } from '../../utils/typed_redux'; +import { RendererFunction } from '../../utils/typed_react'; import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state'; interface WithLogFilterProps { indexPattern: IIndexPattern; + children: RendererFunction< + LogFilterStateParams & { + applyFilterQuery: (query: FilterQuery) => void; + applyFilterQueryFromKueryExpression: (expression: string) => void; + setFilterQueryDraft: (expression: FilterQuery) => void; + setFilterQueryDraftFromKueryExpression: (expression: string) => void; + } + >; } -export const withLogFilter = connect( - (state: State) => ({ - filterQuery: logFilterSelectors.selectLogFilterQuery(state), - serializedFilterQuery: logFilterSelectors.selectLogFilterQueryAsJson(state), - filterQueryDraft: logFilterSelectors.selectLogFilterQueryDraft(state), - isFilterQueryDraftValid: logFilterSelectors.selectIsLogFilterQueryDraftValid(state), - }), - (dispatch, ownProps: WithLogFilterProps) => - bindPlainActionCreators({ - applyFilterQuery: (query: FilterQuery) => - logFilterActions.applyLogFilterQuery({ - query, - serializedQuery: convertKueryToElasticSearchQuery( - query.expression, - ownProps.indexPattern - ), - }), - applyFilterQueryFromKueryExpression: (expression: string) => - logFilterActions.applyLogFilterQuery({ - query: { - kind: 'kuery', - expression, - }, - serializedQuery: convertKueryToElasticSearchQuery(expression, ownProps.indexPattern), - }), - setFilterQueryDraft: logFilterActions.setLogFilterQueryDraft, - setFilterQueryDraftFromKueryExpression: (expression: string) => - logFilterActions.setLogFilterQueryDraft({ +export const WithLogFilter: React.FC = ({ children, indexPattern }) => { + const [logFilterState, logFilterCallbacks] = useContext(LogFilterState.Context); + return children({ + ...logFilterState, + applyFilterQuery: (query: FilterQuery) => + logFilterCallbacks.applyLogFilterQuery({ + query, + serializedQuery: convertKueryToElasticSearchQuery(query.expression, indexPattern), + }), + applyFilterQueryFromKueryExpression: (expression: string) => + logFilterCallbacks.applyLogFilterQuery({ + query: { kind: 'kuery', expression, - }), - })(dispatch) -); - -export const WithLogFilter = asChildFunctionRenderer(withLogFilter); + }, + serializedQuery: convertKueryToElasticSearchQuery(expression, indexPattern), + }), + setFilterQueryDraft: logFilterCallbacks.setLogFilterQueryDraft, + setFilterQueryDraftFromKueryExpression: (expression: string) => + logFilterCallbacks.setLogFilterQueryDraft({ + kind: 'kuery', + expression, + }), + }); +}; /** * Url State */ -type LogFilterUrlState = ReturnType; +type LogFilterUrlState = LogFilterStateParams['filterQuery']; type WithLogFilterUrlStateProps = WithLogFilterProps; @@ -85,7 +80,7 @@ export const WithLogFilterUrlState: React.FC = ({ in ); -const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => +const mapToFilterQuery = (value: any): FilterQuery | null | undefined => value && value.kind === 'kuery' && typeof value.expression === 'string' ? { kind: value.kind, diff --git a/x-pack/legacy/plugins/infra/public/store/local/actions.ts b/x-pack/legacy/plugins/infra/public/store/local/actions.ts index 1c6918ea4dc1..1827005e5e5e 100644 --- a/x-pack/legacy/plugins/infra/public/store/local/actions.ts +++ b/x-pack/legacy/plugins/infra/public/store/local/actions.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export { logFilterActions } from './log_filter'; export { logPositionActions } from './log_position'; export { waffleFilterActions } from './waffle_filter'; export { waffleTimeActions } from './waffle_time'; diff --git a/x-pack/legacy/plugins/infra/public/store/local/log_filter/actions.ts b/x-pack/legacy/plugins/infra/public/store/local/log_filter/actions.ts deleted file mode 100644 index 32da478c6196..000000000000 --- a/x-pack/legacy/plugins/infra/public/store/local/log_filter/actions.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import actionCreatorFactory from 'typescript-fsa'; - -import { FilterQuery, SerializedFilterQuery } from './reducer'; - -const actionCreator = actionCreatorFactory('x-pack/infra/local/log_filter'); - -export const setLogFilterQueryDraft = actionCreator('SET_LOG_FILTER_QUERY_DRAFT'); - -export const applyLogFilterQuery = actionCreator('APPLY_LOG_FILTER_QUERY'); diff --git a/x-pack/legacy/plugins/infra/public/store/local/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/store/local/log_filter/index.ts deleted file mode 100644 index 369f5f013d66..000000000000 --- a/x-pack/legacy/plugins/infra/public/store/local/log_filter/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as logFilterActions from './actions'; -import * as logFilterSelectors from './selectors'; - -export { logFilterActions, logFilterSelectors }; -export * from './reducer'; diff --git a/x-pack/legacy/plugins/infra/public/store/local/log_filter/reducer.ts b/x-pack/legacy/plugins/infra/public/store/local/log_filter/reducer.ts deleted file mode 100644 index afb77dd9ddc6..000000000000 --- a/x-pack/legacy/plugins/infra/public/store/local/log_filter/reducer.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { reducerWithInitialState } from 'typescript-fsa-reducers/dist'; - -import { applyLogFilterQuery, setLogFilterQueryDraft } from './actions'; - -export interface KueryFilterQuery { - kind: 'kuery'; - expression: string; -} - -export type FilterQuery = KueryFilterQuery; - -export interface SerializedFilterQuery { - query: FilterQuery; - serializedQuery: string; -} - -export interface LogFilterState { - filterQuery: SerializedFilterQuery | null; - filterQueryDraft: KueryFilterQuery | null; -} - -export const initialLogFilterState: LogFilterState = { - filterQuery: null, - filterQueryDraft: null, -}; - -export const logFilterReducer = reducerWithInitialState(initialLogFilterState) - .case(setLogFilterQueryDraft, (state, filterQueryDraft) => ({ - ...state, - filterQueryDraft, - })) - .case(applyLogFilterQuery, (state, filterQuery) => ({ - ...state, - filterQuery, - filterQueryDraft: filterQuery.query, - })) - .build(); diff --git a/x-pack/legacy/plugins/infra/public/store/local/log_filter/selectors.ts b/x-pack/legacy/plugins/infra/public/store/local/log_filter/selectors.ts deleted file mode 100644 index f17f7be4defe..000000000000 --- a/x-pack/legacy/plugins/infra/public/store/local/log_filter/selectors.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { createSelector } from 'reselect'; -import { LogFilterState } from './reducer'; -import { esKuery } from '../../../../../../../../src/plugins/data/public'; - -export const selectLogFilterQuery = (state: LogFilterState) => - state.filterQuery ? state.filterQuery.query : null; - -export const selectLogFilterQueryAsJson = (state: LogFilterState) => - state.filterQuery ? state.filterQuery.serializedQuery : null; - -export const selectLogFilterQueryDraft = (state: LogFilterState) => state.filterQueryDraft; - -export const selectIsLogFilterQueryDraftValid = createSelector( - selectLogFilterQueryDraft, - filterQueryDraft => { - if (filterQueryDraft && filterQueryDraft.kind === 'kuery') { - try { - esKuery.fromKueryExpression(filterQueryDraft.expression); - } catch (err) { - return false; - } - } - - return true; - } -); diff --git a/x-pack/legacy/plugins/infra/public/store/local/reducer.ts b/x-pack/legacy/plugins/infra/public/store/local/reducer.ts index 6308f1bc7542..5cc839af4c7c 100644 --- a/x-pack/legacy/plugins/infra/public/store/local/reducer.ts +++ b/x-pack/legacy/plugins/infra/public/store/local/reducer.ts @@ -6,7 +6,6 @@ import { combineReducers } from 'redux'; -import { initialLogFilterState, logFilterReducer, LogFilterState } from './log_filter'; import { initialLogPositionState, logPositionReducer, LogPositionState } from './log_position'; import { initialWaffleFilterState, waffleFilterReducer, WaffleFilterState } from './waffle_filter'; import { @@ -17,7 +16,6 @@ import { import { initialWaffleTimeState, waffleTimeReducer, WaffleTimeState } from './waffle_time'; export interface LocalState { - logFilter: LogFilterState; logPosition: LogPositionState; waffleFilter: WaffleFilterState; waffleTime: WaffleTimeState; @@ -25,7 +23,6 @@ export interface LocalState { } export const initialLocalState: LocalState = { - logFilter: initialLogFilterState, logPosition: initialLogPositionState, waffleFilter: initialWaffleFilterState, waffleTime: initialWaffleTimeState, @@ -33,7 +30,6 @@ export const initialLocalState: LocalState = { }; export const localReducer = combineReducers({ - logFilter: logFilterReducer, logPosition: logPositionReducer, waffleFilter: waffleFilterReducer, waffleTime: waffleTimeReducer, diff --git a/x-pack/legacy/plugins/infra/public/store/local/selectors.ts b/x-pack/legacy/plugins/infra/public/store/local/selectors.ts index ef57835496f6..c367901353b3 100644 --- a/x-pack/legacy/plugins/infra/public/store/local/selectors.ts +++ b/x-pack/legacy/plugins/infra/public/store/local/selectors.ts @@ -5,18 +5,12 @@ */ import { globalizeSelectors } from '../../utils/typed_redux'; -import { logFilterSelectors as innerLogFilterSelectors } from './log_filter'; import { logPositionSelectors as innerLogPositionSelectors } from './log_position'; import { LocalState } from './reducer'; import { waffleFilterSelectors as innerWaffleFilterSelectors } from './waffle_filter'; import { waffleOptionsSelectors as innerWaffleOptionsSelectors } from './waffle_options'; import { waffleTimeSelectors as innerWaffleTimeSelectors } from './waffle_time'; -export const logFilterSelectors = globalizeSelectors( - (state: LocalState) => state.logFilter, - innerLogFilterSelectors -); - export const logPositionSelectors = globalizeSelectors( (state: LocalState) => state.logPosition, innerLogPositionSelectors From f91debda09860dd75d9f0eae8b62a2b080b5fe74 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 10 Dec 2019 11:16:57 -0600 Subject: [PATCH 02/16] Update typedef --- .../plugins/infra/public/containers/logs/with_log_filter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx index 1b4943fa51f2..8d5498065e8b 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx @@ -80,7 +80,7 @@ export const WithLogFilterUrlState: React.FC = ({ in ); -const mapToFilterQuery = (value: any): FilterQuery | null | undefined => +const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => value && value.kind === 'kuery' && typeof value.expression === 'string' ? { kind: value.kind, From 4e5035d506ac4dc6e716f96cc7d0f481afd418d1 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 10 Dec 2019 15:20:55 -0600 Subject: [PATCH 03/16] Typecheck fix --- .../public/containers/logs/log_summary/with_summary.ts | 1 - .../infra/public/containers/logs/with_log_filter.tsx | 2 +- .../infra/public/pages/logs/stream/page_logs_content.tsx | 9 ++------- .../infra/public/pages/logs/stream/page_providers.tsx | 4 ++-- x-pack/legacy/plugins/infra/public/store/actions.ts | 1 - x-pack/legacy/plugins/infra/public/store/selectors.ts | 2 -- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts index 71cc36cd97bf..3cdf48773985 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts @@ -26,7 +26,6 @@ export const WithSummary = connect((state: State) => ({ start: number | null; end: number | null; }>; - filterQuery: string | null; visibleMidpointTime: number | null; }) => { const { intervalSize } = useContext(LogViewConfiguration.Context); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx index 8d5498065e8b..7e2c7a891b62 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx @@ -56,7 +56,7 @@ export const WithLogFilter: React.FC = ({ children, indexPat type LogFilterUrlState = LogFilterStateParams['filterQuery']; -type WithLogFilterUrlStateProps = WithLogFilterProps; +type WithLogFilterUrlStateProps = Omit; export const WithLogFilterUrlState: React.FC = ({ indexPattern }) => ( diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index 88212849d459..c11204796b8a 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -46,7 +46,7 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { const derivedIndexPattern = createDerivedIndexPattern('logs'); return ( <> - + @@ -132,12 +132,7 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { {({ buckets }) => ( - {({ - isAutoReloading, - jumpToTargetPosition, - visibleMidpointTime, - visibleTimeInterval, - }) => ( + {({ jumpToTargetPosition, visibleMidpointTime, visibleTimeInterval }) => ( {({ isReloading }) => ( { const { timeKey, pagesBeforeStart, pagesAfterEnd, isAutoReloading } = useContext( LogPositionState.Context ); - const { filterQuery } = useContext(LogFilterState.Context); + const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); const entriesProps = { timeKey, pagesBeforeStart, @@ -35,7 +35,7 @@ const LogEntriesStateProvider: React.FC = ({ children }) => { const LogHighlightsStateProvider: React.FC = ({ children }) => { const { sourceId, version } = useContext(Source.Context); const [{ entriesStart, entriesEnd }] = useContext(LogEntriesState.Context); - const { filterQuery } = useContext(LogFilterState.Context); + const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); const highlightsProps = { sourceId, sourceVersion: version, diff --git a/x-pack/legacy/plugins/infra/public/store/actions.ts b/x-pack/legacy/plugins/infra/public/store/actions.ts index e2be0d64b8f1..ce0c0d8a4e01 100644 --- a/x-pack/legacy/plugins/infra/public/store/actions.ts +++ b/x-pack/legacy/plugins/infra/public/store/actions.ts @@ -5,7 +5,6 @@ */ export { - logFilterActions, logPositionActions, waffleFilterActions, waffleTimeActions, diff --git a/x-pack/legacy/plugins/infra/public/store/selectors.ts b/x-pack/legacy/plugins/infra/public/store/selectors.ts index aecba1779d03..d98e8ae9a0aa 100644 --- a/x-pack/legacy/plugins/infra/public/store/selectors.ts +++ b/x-pack/legacy/plugins/infra/public/store/selectors.ts @@ -6,7 +6,6 @@ import { globalizeSelectors } from '../utils/typed_redux'; import { - logFilterSelectors as localLogFilterSelectors, logPositionSelectors as localLogPositionSelectors, waffleFilterSelectors as localWaffleFilterSelectors, waffleOptionsSelectors as localWaffleOptionsSelectors, @@ -19,7 +18,6 @@ import { State } from './reducer'; const selectLocal = (state: State) => state.local; -export const logFilterSelectors = globalizeSelectors(selectLocal, localLogFilterSelectors); export const logPositionSelectors = globalizeSelectors(selectLocal, localLogPositionSelectors); export const waffleFilterSelectors = globalizeSelectors(selectLocal, localWaffleFilterSelectors); export const waffleTimeSelectors = globalizeSelectors(selectLocal, localWaffleTimeSelectors); From 2759d2fb6fac00fcf20053ac9146c421166076b5 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 10 Dec 2019 15:58:05 -0600 Subject: [PATCH 04/16] Typecheck fix --- x-pack/legacy/plugins/infra/public/store/store.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/store/store.ts b/x-pack/legacy/plugins/infra/public/store/store.ts index 601db0f56a69..2781b0b2cef3 100644 --- a/x-pack/legacy/plugins/infra/public/store/store.ts +++ b/x-pack/legacy/plugins/infra/public/store/store.ts @@ -12,7 +12,6 @@ import { map } from 'rxjs/operators'; import { createRootEpic, initialState, - logFilterSelectors, logPositionSelectors, reducer, State, @@ -39,7 +38,6 @@ export function createStore({ apolloClient, observableApi }: StoreDependencies) apolloClient$: apolloClient, selectIsAutoReloadingLogEntries: logPositionSelectors.selectIsAutoReloading, selectIsAutoReloadingScrollLocked: logPositionSelectors.selectAutoReloadScrollLock, - selectLogFilterQueryAsJson: logFilterSelectors.selectLogFilterQueryAsJson, selectLogTargetPosition: logPositionSelectors.selectTargetPosition, selectVisibleLogMidpointOrTarget: logPositionSelectors.selectVisibleMidpointOrTarget, selectWaffleTimeUpdatePolicyInterval: waffleTimeSelectors.selectTimeUpdatePolicyInterval, From c16e03cfdee4767c185da3fe818964dcea8bf275 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 12 Dec 2019 11:51:55 -0600 Subject: [PATCH 05/16] Simplify log filter state --- .../containers/logs/log_filter/index.ts | 106 ++++++------------ .../logs/log_summary/with_summary.ts | 2 +- .../containers/logs/with_log_filter.tsx | 14 +-- .../pages/logs/stream/page_providers.tsx | 4 +- 4 files changed, 46 insertions(+), 80 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts index 8bcd3265b643..86cca2beeb9f 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts @@ -4,65 +4,54 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useReducer, useMemo } from 'react'; +import { useState, useMemo } from 'react'; import createContainer from 'constate'; import { esKuery } from '../../../../../../../../src/plugins/data/public'; -enum Action { - SetDraftFilterQuery, - ApplyFilterQuery, -} - -interface SetDraftQueryAction { - type: Action.SetDraftFilterQuery; - payload: FilterQuery | null; -} - -interface ApplyFilterQueryAction { - type: Action.ApplyFilterQuery; - payload: SerializedFilterQuery; -} - -type ActionObj = SetDraftQueryAction | ApplyFilterQueryAction; - export interface KueryFilterQuery { kind: 'kuery'; expression: string; } -export type FilterQuery = KueryFilterQuery; - export interface SerializedFilterQuery { - query: FilterQuery; + query: KueryFilterQuery; serializedQuery: string; } -interface LogFilterBaseStateParams { +interface LogFilterInternalStateParams { filterQuery: SerializedFilterQuery | null; filterQueryDraft: KueryFilterQuery | null; } -export const logFilterInitialState: LogFilterBaseStateParams = { +export const logFilterInitialState: LogFilterInternalStateParams = { filterQuery: null, filterQueryDraft: null, }; -interface LogFilterDerivatives { +export type LogFilterStateParams = Omit & { + filterQuery: SerializedFilterQuery['serializedQuery'] | null; + filterQueryAsKuery: SerializedFilterQuery['query'] | null; isFilterQueryDraftValid: boolean; - filterQueryAsJson: SerializedFilterQuery['serializedQuery'] | null; - filterQuery: FilterQuery | null; -} - -export type LogFilterStateParams = Omit & - LogFilterDerivatives; - +}; export interface LogFilterCallbacks { - setLogFilterQueryDraft: (payload: FilterQuery) => void; + setLogFilterQueryDraft: (payload: KueryFilterQuery) => void; applyLogFilterQuery: (payload: SerializedFilterQuery) => void; } -const getDerivatives = (state: LogFilterBaseStateParams) => ({ - get isFilterQueryDraftValid() { +export const useLogFilterState: () => [LogFilterStateParams, LogFilterCallbacks] = () => { + const [state, setState] = useState(logFilterInitialState); + const callbacks = useMemo( + () => ({ + setLogFilterQueryDraft: (payload: KueryFilterQuery) => + setState({ ...state, filterQueryDraft: payload }), + + applyLogFilterQuery: (payload: SerializedFilterQuery) => + setState({ ...state, filterQueryDraft: payload.query, filterQuery: payload }), + }), + [] + ); + + const isFilterQueryDraftValid = useMemo(() => { const { filterQueryDraft } = state; if (filterQueryDraft && filterQueryDraft.kind === 'kuery') { try { @@ -73,45 +62,22 @@ const getDerivatives = (state: LogFilterBaseStateParams) => ({ } return true; - }, - get filterQueryAsJson() { - const { filterQuery } = state; - return filterQuery ? filterQuery.serializedQuery : null; - }, - get filterQuery() { - const { filterQuery } = state; - return filterQuery ? filterQuery.query : null; - }, -}); - -export const useLogFilterState: () => [LogFilterStateParams, LogFilterCallbacks] = () => { - const [state, dispatch] = useReducer(logFilterStateReducer, logFilterInitialState); - - const callbacks = useMemo( - () => ({ - setLogFilterQueryDraft: (payload: FilterQuery) => - dispatch({ type: Action.SetDraftFilterQuery, payload }), + }, [esKuery.fromKueryExpression, state.filterQueryDraft]); - applyLogFilterQuery: (payload: SerializedFilterQuery) => - dispatch({ type: Action.ApplyFilterQuery, payload }), - }), - [] + const serializedFilterQuery = useMemo( + () => (state.filterQuery ? state.filterQuery.serializedQuery : null), + [esKuery.fromKueryExpression, state.filterQuery] ); - const derivatives = useMemo(() => getDerivatives(state), [state]); - - return [{ ...state, ...derivatives }, callbacks]; -}; - -const logFilterStateReducer = (prevState: LogFilterBaseStateParams, action: ActionObj) => { - switch (action.type) { - case Action.SetDraftFilterQuery: - return { ...prevState, filterQueryDraft: action.payload }; - case Action.ApplyFilterQuery: - return { ...prevState, filterQueryDraft: action.payload.query, filterQuery: action.payload }; - default: - throw new Error(); - } + return [ + { + ...state, + filterQueryAsKuery: state.filterQuery ? state.filterQuery.query : null, + filterQuery: serializedFilterQuery, + isFilterQueryDraftValid, + }, + callbacks, + ]; }; export const LogFilterState = createContainer(useLogFilterState); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts index 3cdf48773985..3265b7e4b018 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_summary/with_summary.ts @@ -30,7 +30,7 @@ export const WithSummary = connect((state: State) => ({ }) => { const { intervalSize } = useContext(LogViewConfiguration.Context); const { sourceId } = useContext(Source.Context); - const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); + const [{ filterQuery }] = useContext(LogFilterState.Context); const { buckets, start, end } = useLogSummary( sourceId, diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx index 7e2c7a891b62..f0b28be1e806 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx @@ -6,7 +6,7 @@ import React, { useContext } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; -import { LogFilterState, LogFilterStateParams, FilterQuery } from './log_filter'; +import { LogFilterState, LogFilterStateParams, KueryFilterQuery } from './log_filter'; import { convertKueryToElasticSearchQuery } from '../../utils/kuery'; import { RendererFunction } from '../../utils/typed_react'; @@ -16,9 +16,9 @@ interface WithLogFilterProps { indexPattern: IIndexPattern; children: RendererFunction< LogFilterStateParams & { - applyFilterQuery: (query: FilterQuery) => void; + applyFilterQuery: (query: KueryFilterQuery) => void; applyFilterQueryFromKueryExpression: (expression: string) => void; - setFilterQueryDraft: (expression: FilterQuery) => void; + setFilterQueryDraft: (expression: KueryFilterQuery) => void; setFilterQueryDraftFromKueryExpression: (expression: string) => void; } >; @@ -28,7 +28,7 @@ export const WithLogFilter: React.FC = ({ children, indexPat const [logFilterState, logFilterCallbacks] = useContext(LogFilterState.Context); return children({ ...logFilterState, - applyFilterQuery: (query: FilterQuery) => + applyFilterQuery: (query: KueryFilterQuery) => logFilterCallbacks.applyLogFilterQuery({ query, serializedQuery: convertKueryToElasticSearchQuery(query.expression, indexPattern), @@ -54,15 +54,15 @@ export const WithLogFilter: React.FC = ({ children, indexPat * Url State */ -type LogFilterUrlState = LogFilterStateParams['filterQuery']; +type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; type WithLogFilterUrlStateProps = Omit; export const WithLogFilterUrlState: React.FC = ({ indexPattern }) => ( - {({ applyFilterQuery, filterQuery }) => ( + {({ applyFilterQuery, filterQueryAsKuery }) => ( { diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx index 97ccea0986ba..ff0a0cc76bee 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -20,7 +20,7 @@ const LogEntriesStateProvider: React.FC = ({ children }) => { const { timeKey, pagesBeforeStart, pagesAfterEnd, isAutoReloading } = useContext( LogPositionState.Context ); - const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); + const [{ filterQuery }] = useContext(LogFilterState.Context); const entriesProps = { timeKey, pagesBeforeStart, @@ -35,7 +35,7 @@ const LogEntriesStateProvider: React.FC = ({ children }) => { const LogHighlightsStateProvider: React.FC = ({ children }) => { const { sourceId, version } = useContext(Source.Context); const [{ entriesStart, entriesEnd }] = useContext(LogEntriesState.Context); - const [{ filterQueryAsJson: filterQuery }] = useContext(LogFilterState.Context); + const [{ filterQuery }] = useContext(LogFilterState.Context); const highlightsProps = { sourceId, sourceVersion: version, From 57b5b18bc954d24ded209eeeb443b04f2b56f612 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 12 Dec 2019 12:59:10 -0600 Subject: [PATCH 06/16] Remove WithLogFilter HOC and simplify hook further --- .../containers/logs/log_filter/index.js | 8 ++ .../{index.ts => log_filter_state.ts} | 51 ++++++---- .../log_filter/with_log_filter_url_state.tsx | 46 +++++++++ .../containers/logs/with_log_filter.tsx | 95 ------------------- .../pages/logs/stream/page_logs_content.tsx | 45 ++++----- .../pages/logs/stream/page_providers.tsx | 17 +++- .../public/pages/logs/stream/page_toolbar.tsx | 59 +++++------- 7 files changed, 147 insertions(+), 174 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js rename x-pack/legacy/plugins/infra/public/containers/logs/log_filter/{index.ts => log_filter_state.ts} (56%) create mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js new file mode 100644 index 000000000000..4c4c317759bb --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './log_filter_state'; +export * from './with_log_filter_url_state'; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts similarity index 56% rename from x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts rename to x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts index 86cca2beeb9f..ed3546a8ecce 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts @@ -6,7 +6,9 @@ import { useState, useMemo } from 'react'; import createContainer from 'constate'; +import { IIndexPattern } from 'src/plugins/data/public'; import { esKuery } from '../../../../../../../../src/plugins/data/public'; +import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; export interface KueryFilterQuery { kind: 'kuery'; @@ -34,25 +36,39 @@ export type LogFilterStateParams = Omit void; - applyLogFilterQuery: (payload: SerializedFilterQuery) => void; + setLogFilterQueryDraft: (expression: string) => void; + applyLogFilterQuery: (expression: string) => void; } -export const useLogFilterState: () => [LogFilterStateParams, LogFilterCallbacks] = () => { +export const useLogFilterState: (props: { + indexPattern: IIndexPattern; +}) => [LogFilterStateParams, LogFilterCallbacks] = ({ indexPattern }) => { const [state, setState] = useState(logFilterInitialState); - const callbacks = useMemo( - () => ({ - setLogFilterQueryDraft: (payload: KueryFilterQuery) => - setState({ ...state, filterQueryDraft: payload }), + const { filterQuery, filterQueryDraft } = state; - applyLogFilterQuery: (payload: SerializedFilterQuery) => - setState({ ...state, filterQueryDraft: payload.query, filterQuery: payload }), - }), - [] - ); + const callbacks: LogFilterCallbacks = useMemo(() => { + const setLogFilterQueryDraft = (payload: KueryFilterQuery) => + setState({ ...state, filterQueryDraft: payload }); + const applyLogFilterQuery = (payload: SerializedFilterQuery) => + setState({ ...state, filterQueryDraft: payload.query, filterQuery: payload }); + return { + setLogFilterQueryDraft: expression => + setLogFilterQueryDraft({ + kind: 'kuery', + expression, + }), + applyLogFilterQuery: expression => + applyLogFilterQuery({ + query: { + kind: 'kuery', + expression, + }, + serializedQuery: convertKueryToElasticSearchQuery(expression, indexPattern), + }), + }; + }, [state, indexPattern]); const isFilterQueryDraftValid = useMemo(() => { - const { filterQueryDraft } = state; if (filterQueryDraft && filterQueryDraft.kind === 'kuery') { try { esKuery.fromKueryExpression(filterQueryDraft.expression); @@ -62,12 +78,11 @@ export const useLogFilterState: () => [LogFilterStateParams, LogFilterCallbacks] } return true; - }, [esKuery.fromKueryExpression, state.filterQueryDraft]); + }, [filterQueryDraft]); - const serializedFilterQuery = useMemo( - () => (state.filterQuery ? state.filterQuery.serializedQuery : null), - [esKuery.fromKueryExpression, state.filterQuery] - ); + const serializedFilterQuery = useMemo(() => (filterQuery ? filterQuery.serializedQuery : null), [ + filterQuery, + ]); return [ { diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx new file mode 100644 index 000000000000..1470e4148bf3 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext } from 'react'; +import { LogFilterState, LogFilterStateParams } from './log_filter'; +import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state'; + +type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; + +export const WithLogFilterUrlState: React.FC = () => { + const [{ filterQueryAsKuery }, { applyLogFilterQuery }] = useContext(LogFilterState.Context); + return ( + { + if (urlState) { + applyLogFilterQuery(urlState.expression); + } + }} + onInitialize={urlState => { + if (urlState) { + applyLogFilterQuery(urlState.expression); + } + }} + /> + ); +}; + +const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => + value && value.kind === 'kuery' && typeof value.expression === 'string' + ? { + kind: value.kind, + expression: value.expression, + } + : undefined; + +export const replaceLogFilterInQueryString = (expression: string) => + replaceStateKeyInQueryString('logFilter', { + kind: 'kuery', + expression, + }); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx deleted file mode 100644 index f0b28be1e806..000000000000 --- a/x-pack/legacy/plugins/infra/public/containers/logs/with_log_filter.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useContext } from 'react'; -import { IIndexPattern } from 'src/plugins/data/public'; -import { LogFilterState, LogFilterStateParams, KueryFilterQuery } from './log_filter'; - -import { convertKueryToElasticSearchQuery } from '../../utils/kuery'; -import { RendererFunction } from '../../utils/typed_react'; -import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state'; - -interface WithLogFilterProps { - indexPattern: IIndexPattern; - children: RendererFunction< - LogFilterStateParams & { - applyFilterQuery: (query: KueryFilterQuery) => void; - applyFilterQueryFromKueryExpression: (expression: string) => void; - setFilterQueryDraft: (expression: KueryFilterQuery) => void; - setFilterQueryDraftFromKueryExpression: (expression: string) => void; - } - >; -} - -export const WithLogFilter: React.FC = ({ children, indexPattern }) => { - const [logFilterState, logFilterCallbacks] = useContext(LogFilterState.Context); - return children({ - ...logFilterState, - applyFilterQuery: (query: KueryFilterQuery) => - logFilterCallbacks.applyLogFilterQuery({ - query, - serializedQuery: convertKueryToElasticSearchQuery(query.expression, indexPattern), - }), - applyFilterQueryFromKueryExpression: (expression: string) => - logFilterCallbacks.applyLogFilterQuery({ - query: { - kind: 'kuery', - expression, - }, - serializedQuery: convertKueryToElasticSearchQuery(expression, indexPattern), - }), - setFilterQueryDraft: logFilterCallbacks.setLogFilterQueryDraft, - setFilterQueryDraftFromKueryExpression: (expression: string) => - logFilterCallbacks.setLogFilterQueryDraft({ - kind: 'kuery', - expression, - }), - }); -}; - -/** - * Url State - */ - -type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; - -type WithLogFilterUrlStateProps = Omit; - -export const WithLogFilterUrlState: React.FC = ({ indexPattern }) => ( - - {({ applyFilterQuery, filterQueryAsKuery }) => ( - { - if (urlState) { - applyFilterQuery(urlState); - } - }} - onInitialize={urlState => { - if (urlState) { - applyFilterQuery(urlState); - } - }} - /> - )} - -); - -const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => - value && value.kind === 'kuery' && typeof value.expression === 'string' - ? { - kind: value.kind, - expression: value.expression, - } - : undefined; - -export const replaceLogFilterInQueryString = (expression: string) => - replaceStateKeyInQueryString('logFilter', { - kind: 'kuery', - expression, - }); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index c11204796b8a..03adc9933a6b 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -15,7 +15,7 @@ import { PageContent } from '../../../components/page'; import { WithSummary } from '../../../containers/logs/log_summary'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; -import { WithLogFilter, WithLogFilterUrlState } from '../../../containers/logs/with_log_filter'; +import { LogFilterState } from '../../../containers/logs/log_filter'; import { LogFlyout as LogFlyoutState, WithFlyoutOptionsUrlState, @@ -31,7 +31,7 @@ import { LogsToolbar } from './page_toolbar'; import { LogHighlightsBridge, LogHighlightsState } from '../../../containers/logs/log_highlights'; export const LogsPageLogsContent: React.FunctionComponent = () => { - const { createDerivedIndexPattern, source, sourceId, version } = useContext(Source.Context); + const { source, sourceId, version } = useContext(Source.Context); const { intervalSize, textScale, textWrap } = useContext(LogViewConfiguration.Context); const { setFlyoutVisibility, @@ -43,37 +43,32 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { isLoading, } = useContext(LogFlyoutState.Context); const { logSummaryHighlights } = useContext(LogHighlightsState.Context); - const derivedIndexPattern = createDerivedIndexPattern('logs'); + const [, { applyLogFilterQuery }] = useContext(LogFilterState.Context); return ( <> - - - {({ applyFilterQueryFromKueryExpression }) => ( - - {({ jumpToTargetPosition, stopLiveStreaming }) => - flyoutVisible ? ( - { - jumpToTargetPosition(timeKey); - setSurroundingLogsId(flyoutItemId); - stopLiveStreaming(); - }} - setFlyoutVisibility={setFlyoutVisibility} - flyoutItem={flyoutItem} - loading={isLoading} - /> - ) : null - } - - )} - + + {({ jumpToTargetPosition, stopLiveStreaming }) => + flyoutVisible ? ( + { + jumpToTargetPosition(timeKey); + setSurroundingLogsId(flyoutItemId); + stopLiveStreaming(); + }} + setFlyoutVisibility={setFlyoutVisibility} + flyoutItem={flyoutItem} + loading={isLoading} + /> + ) : null + } + {({ diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx index ff0a0cc76bee..8ac6d74923a7 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -10,11 +10,22 @@ import { LogFlyout } from '../../../containers/logs/log_flyout'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; import { LogHighlightsState } from '../../../containers/logs/log_highlights/log_highlights'; import { LogPositionState } from '../../../containers/logs/log_position'; -import { LogFilterState } from '../../../containers/logs/log_filter'; +import { LogFilterState, WithLogFilterUrlState } from '../../../containers/logs/log_filter'; import { LogEntriesState } from '../../../containers/logs/log_entries'; import { Source } from '../../../containers/source'; +const LogFilterStateProvider: React.FC = ({ children }) => { + const { createDerivedIndexPattern } = useContext(Source.Context); + const derivedIndexPattern = createDerivedIndexPattern('logs'); + return ( + + + {children} + + ); +}; + const LogEntriesStateProvider: React.FC = ({ children }) => { const { sourceId } = useContext(Source.Context); const { timeKey, pagesBeforeStart, pagesAfterEnd, isAutoReloading } = useContext( @@ -51,11 +62,11 @@ export const LogsPageProviders: React.FunctionComponent = ({ children }) => { - + {children} - + diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx index 60c0ebdfc349..ba1523e5939f 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx @@ -19,7 +19,7 @@ import { LogTextWrapControls } from '../../../components/logging/log_text_wrap_c import { LogTimeControls } from '../../../components/logging/log_time_controls'; import { LogFlyout } from '../../../containers/logs/log_flyout'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; -import { WithLogFilter } from '../../../containers/logs/with_log_filter'; +import { LogFilterState } from '../../../containers/logs/log_filter'; import { WithLogPosition } from '../../../containers/logs/with_log_position'; import { Source } from '../../../containers/source'; import { WithKueryAutocompletion } from '../../../containers/with_kuery_autocompletion'; @@ -37,7 +37,10 @@ export const LogsToolbar = () => { textScale, textWrap, } = useContext(LogViewConfiguration.Context); - + const [ + { filterQueryDraft, isFilterQueryDraftValid }, + { applyLogFilterQuery, setLogFilterQueryDraft }, + ] = useContext(LogFilterState.Context); const { setSurroundingLogsId } = useContext(LogFlyout.Context); const { @@ -55,38 +58,28 @@ export const LogsToolbar = () => { {({ isLoadingSuggestions, loadSuggestions, suggestions }) => ( - - {({ - applyFilterQueryFromKueryExpression, - filterQueryDraft, - isFilterQueryDraftValid, - setFilterQueryDraftFromKueryExpression, - }) => ( - { - setSurroundingLogsId(null); - setFilterQueryDraftFromKueryExpression(expression); - }} - onSubmit={(expression: string) => { - setSurroundingLogsId(null); - applyFilterQueryFromKueryExpression(expression); - }} - placeholder={i18n.translate( - 'xpack.infra.logsPage.toolbar.kqlSearchFieldPlaceholder', - { defaultMessage: 'Search for log entries… (e.g. host.name:host-1)' } - )} - suggestions={suggestions} - value={filterQueryDraft ? filterQueryDraft.expression : ''} - aria-label={i18n.translate( - 'xpack.infra.logsPage.toolbar.kqlSearchFieldAriaLabel', - { defaultMessage: 'Search for log entries' } - )} - /> + { + setSurroundingLogsId(null); + setLogFilterQueryDraft(expression); + }} + onSubmit={(expression: string) => { + setSurroundingLogsId(null); + applyLogFilterQuery(expression); + }} + placeholder={i18n.translate( + 'xpack.infra.logsPage.toolbar.kqlSearchFieldPlaceholder', + { defaultMessage: 'Search for log entries… (e.g. host.name:host-1)' } )} - + suggestions={suggestions} + value={filterQueryDraft ? filterQueryDraft.expression : ''} + aria-label={i18n.translate('xpack.infra.logsPage.toolbar.kqlSearchFieldAriaLabel', { + defaultMessage: 'Search for log entries', + })} + /> )} From ede66d826fcb75bcf9415b4928c0220c687d6153 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 12 Dec 2019 15:59:29 -0600 Subject: [PATCH 07/16] Rename js to ts --- .../public/containers/logs/log_filter/{index.js => index.ts} | 0 .../containers/logs/log_filter/with_log_filter_url_state.tsx | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename x-pack/legacy/plugins/infra/public/containers/logs/log_filter/{index.js => index.ts} (100%) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts similarity index 100% rename from x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.js rename to x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx index 1470e4148bf3..54cdf0b1f734 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx @@ -5,8 +5,8 @@ */ import React, { useContext } from 'react'; -import { LogFilterState, LogFilterStateParams } from './log_filter'; -import { replaceStateKeyInQueryString, UrlStateContainer } from '../../utils/url_state'; +import { LogFilterState, LogFilterStateParams } from './log_filter_state'; +import { replaceStateKeyInQueryString, UrlStateContainer } from '../../../utils/url_state'; type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; From 968b5a7b78ca4244d1c4fd2725b003113537e725 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 12 Dec 2019 16:27:52 -0600 Subject: [PATCH 08/16] Fix redirect imports --- .../plugins/infra/public/pages/link_to/redirect_to_logs.tsx | 2 +- .../infra/public/pages/link_to/redirect_to_node_logs.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.tsx index c409470eb24c..bfa1ede4236a 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.tsx @@ -8,7 +8,7 @@ import compose from 'lodash/fp/compose'; import React from 'react'; import { match as RouteMatch, Redirect, RouteComponentProps } from 'react-router-dom'; -import { replaceLogFilterInQueryString } from '../../containers/logs/with_log_filter'; +import { replaceLogFilterInQueryString } from '../../containers/logs/log_filter'; import { replaceLogPositionInQueryString } from '../../containers/logs/with_log_position'; import { replaceSourceIdInQueryString } from '../../containers/source_id'; import { getFilterFromLocation, getTimeFromLocation } from './query_params'; diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx index fe79c169d862..2ec0a53b5e38 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import { LoadingPage } from '../../components/loading_page'; -import { replaceLogFilterInQueryString } from '../../containers/logs/with_log_filter'; +import { replaceLogFilterInQueryString } from '../../containers/logs/log_filter'; import { replaceLogPositionInQueryString } from '../../containers/logs/with_log_position'; import { replaceSourceIdInQueryString } from '../../containers/source_id'; import { InfraNodeType } from '../../graphql/types'; From 9c392863d1a286531634b92a10c58073f66163df Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 17 Dec 2019 14:13:11 -0600 Subject: [PATCH 09/16] Fix link-to test accuracy --- x-pack/test/functional/apps/infra/link_to.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/infra/link_to.ts b/x-pack/test/functional/apps/infra/link_to.ts index efe60b41badc..a68637600be8 100644 --- a/x-pack/test/functional/apps/infra/link_to.ts +++ b/x-pack/test/functional/apps/infra/link_to.ts @@ -22,7 +22,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { state: undefined, }; const expectedSearchString = - "logFilter=(expression:'trace.id:433b4651687e18be2c6c8e3b11f53d09',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1565707203194))&sourceId=default&_g=()"; + "logFilter=(expression:'trace.id:433b4651687e18be2c6c8e3b11f53d09',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1565707203194))&sourceId=default"; const expectedRedirect = `/logs/stream?${expectedSearchString}`; await pageObjects.common.navigateToActualUrl( From 47ffa996dd9301c977858f5de716ac710dd8736b Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 17 Dec 2019 16:56:38 -0600 Subject: [PATCH 10/16] Fix link-to test --- x-pack/test/functional/apps/infra/link_to.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional/apps/infra/link_to.ts b/x-pack/test/functional/apps/infra/link_to.ts index a68637600be8..a564da9ab877 100644 --- a/x-pack/test/functional/apps/infra/link_to.ts +++ b/x-pack/test/functional/apps/infra/link_to.ts @@ -23,7 +23,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; const expectedSearchString = "logFilter=(expression:'trace.id:433b4651687e18be2c6c8e3b11f53d09',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1565707203194))&sourceId=default"; - const expectedRedirect = `/logs/stream?${expectedSearchString}`; + const expectedRedirectPath = '/logs/stream?'; await pageObjects.common.navigateToActualUrl( 'infraOps', @@ -32,7 +32,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); const [, currentHash] = decodeURIComponent(currentUrl).split('#'); - expect(currentHash).to.contain(expectedRedirect); + // Account for unpredictable location of the g parameter in the search string + expect(currentHash.slice(0, 13)).to.be(expectedRedirectPath); + expect(currentHash.slice(13)).to.contain(expectedSearchString); }); }); }); From ef00491a083d5b59bf5439d299f6d51df5fc95b0 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 19 Dec 2019 12:10:27 -0600 Subject: [PATCH 11/16] Simplify destructuring signature --- .../logs/log_filter/log_filter_state.ts | 63 ++++++++++--------- .../log_filter/with_log_filter_url_state.tsx | 2 +- .../logs/log_summary/with_summary.ts | 2 +- .../pages/logs/stream/page_logs_content.tsx | 2 +- .../pages/logs/stream/page_providers.tsx | 4 +- .../public/pages/logs/stream/page_toolbar.tsx | 10 +-- 6 files changed, 44 insertions(+), 39 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts index ed3546a8ecce..2911ee729638 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/log_filter_state.ts @@ -42,34 +42,38 @@ export interface LogFilterCallbacks { export const useLogFilterState: (props: { indexPattern: IIndexPattern; -}) => [LogFilterStateParams, LogFilterCallbacks] = ({ indexPattern }) => { +}) => LogFilterStateParams & LogFilterCallbacks = ({ indexPattern }) => { const [state, setState] = useState(logFilterInitialState); const { filterQuery, filterQueryDraft } = state; - const callbacks: LogFilterCallbacks = useMemo(() => { - const setLogFilterQueryDraft = (payload: KueryFilterQuery) => - setState({ ...state, filterQueryDraft: payload }); - const applyLogFilterQuery = (payload: SerializedFilterQuery) => - setState({ ...state, filterQueryDraft: payload.query, filterQuery: payload }); - return { - setLogFilterQueryDraft: expression => - setLogFilterQueryDraft({ + const setLogFilterQueryDraft = useMemo(() => { + const setDraft = (payload: KueryFilterQuery) => + setState(prevState => ({ ...prevState, filterQueryDraft: payload })); + return (expression: string) => + setDraft({ + kind: 'kuery', + expression, + }); + }, []); + const applyLogFilterQuery = useMemo(() => { + const applyQuery = (payload: SerializedFilterQuery) => + setState(prevState => ({ + ...prevState, + filterQueryDraft: payload.query, + filterQuery: payload, + })); + return (expression: string) => + applyQuery({ + query: { kind: 'kuery', expression, - }), - applyLogFilterQuery: expression => - applyLogFilterQuery({ - query: { - kind: 'kuery', - expression, - }, - serializedQuery: convertKueryToElasticSearchQuery(expression, indexPattern), - }), - }; - }, [state, indexPattern]); + }, + serializedQuery: convertKueryToElasticSearchQuery(expression, indexPattern), + }); + }, [indexPattern]); const isFilterQueryDraftValid = useMemo(() => { - if (filterQueryDraft && filterQueryDraft.kind === 'kuery') { + if (filterQueryDraft?.kind === 'kuery') { try { esKuery.fromKueryExpression(filterQueryDraft.expression); } catch (err) { @@ -84,15 +88,14 @@ export const useLogFilterState: (props: { filterQuery, ]); - return [ - { - ...state, - filterQueryAsKuery: state.filterQuery ? state.filterQuery.query : null, - filterQuery: serializedFilterQuery, - isFilterQueryDraftValid, - }, - callbacks, - ]; + return { + ...state, + filterQueryAsKuery: state.filterQuery ? state.filterQuery.query : null, + filterQuery: serializedFilterQuery, + isFilterQueryDraftValid, + setLogFilterQueryDraft, + applyLogFilterQuery, + }; }; export const LogFilterState = createContainer(useLogFilterState); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx index 54cdf0b1f734..90ba39a15db4 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx @@ -11,7 +11,7 @@ import { replaceStateKeyInQueryString, UrlStateContainer } from '../../../utils/ type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; export const WithLogFilterUrlState: React.FC = () => { - const [{ filterQueryAsKuery }, { applyLogFilterQuery }] = useContext(LogFilterState.Context); + const { filterQueryAsKuery, applyLogFilterQuery } = useContext(LogFilterState.Context); return ( ({ }) => { const { intervalSize } = useContext(LogViewConfiguration.Context); const { sourceId } = useContext(Source.Context); - const [{ filterQuery }] = useContext(LogFilterState.Context); + const { filterQuery } = useContext(LogFilterState.Context); const { buckets, start, end } = useLogSummary( sourceId, diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index 03adc9933a6b..aff2a3b43106 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -43,7 +43,7 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { isLoading, } = useContext(LogFlyoutState.Context); const { logSummaryHighlights } = useContext(LogHighlightsState.Context); - const [, { applyLogFilterQuery }] = useContext(LogFilterState.Context); + const { applyLogFilterQuery } = useContext(LogFilterState.Context); return ( <> diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx index 8ac6d74923a7..63425368b040 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -31,7 +31,7 @@ const LogEntriesStateProvider: React.FC = ({ children }) => { const { timeKey, pagesBeforeStart, pagesAfterEnd, isAutoReloading } = useContext( LogPositionState.Context ); - const [{ filterQuery }] = useContext(LogFilterState.Context); + const { filterQuery } = useContext(LogFilterState.Context); const entriesProps = { timeKey, pagesBeforeStart, @@ -46,7 +46,7 @@ const LogEntriesStateProvider: React.FC = ({ children }) => { const LogHighlightsStateProvider: React.FC = ({ children }) => { const { sourceId, version } = useContext(Source.Context); const [{ entriesStart, entriesEnd }] = useContext(LogEntriesState.Context); - const [{ filterQuery }] = useContext(LogFilterState.Context); + const { filterQuery } = useContext(LogFilterState.Context); const highlightsProps = { sourceId, sourceVersion: version, diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx index ba1523e5939f..84be3eeaf238 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx @@ -37,10 +37,12 @@ export const LogsToolbar = () => { textScale, textWrap, } = useContext(LogViewConfiguration.Context); - const [ - { filterQueryDraft, isFilterQueryDraftValid }, - { applyLogFilterQuery, setLogFilterQueryDraft }, - ] = useContext(LogFilterState.Context); + const { + filterQueryDraft, + isFilterQueryDraftValid, + applyLogFilterQuery, + setLogFilterQueryDraft, + } = useContext(LogFilterState.Context); const { setSurroundingLogsId } = useContext(LogFlyout.Context); const { From 8cb525d9cefdea921a822c2082dd6e2db2233426 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 19 Dec 2019 13:19:53 -0600 Subject: [PATCH 12/16] Stylistic fixes --- .../containers/logs/log_filter/with_log_filter_url_state.tsx | 2 +- x-pack/test/functional/apps/infra/link_to.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx index 90ba39a15db4..d1da6c715cfc 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx @@ -32,7 +32,7 @@ export const WithLogFilterUrlState: React.FC = () => { }; const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => - value && value.kind === 'kuery' && typeof value.expression === 'string' + value?.kind === 'kuery' && typeof value.expression === 'string' ? { kind: value.kind, expression: value.expression, diff --git a/x-pack/test/functional/apps/infra/link_to.ts b/x-pack/test/functional/apps/infra/link_to.ts index a564da9ab877..d1ae7138ecc6 100644 --- a/x-pack/test/functional/apps/infra/link_to.ts +++ b/x-pack/test/functional/apps/infra/link_to.ts @@ -33,8 +33,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const currentUrl = await browser.getCurrentUrl(); const [, currentHash] = decodeURIComponent(currentUrl).split('#'); // Account for unpredictable location of the g parameter in the search string - expect(currentHash.slice(0, 13)).to.be(expectedRedirectPath); - expect(currentHash.slice(13)).to.contain(expectedSearchString); + expect(currentHash.slice(0, expectedRedirectPath.length)).to.be(expectedRedirectPath); + expect(currentHash.slice(expectedRedirectPath.length)).to.contain(expectedSearchString); }); }); }); From c61f5b190b75594c5a699f0b3ce69cc98a96ef88 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 19 Dec 2019 15:45:59 -0600 Subject: [PATCH 13/16] Move URL state to hook --- .../containers/logs/log_filter/index.ts | 2 +- .../log_filter/use_log_filter_url_state.tsx | 44 ++++++++++++++++++ .../log_filter/with_log_filter_url_state.tsx | 46 ------------------- .../pages/logs/stream/page_logs_content.tsx | 5 +- .../pages/logs/stream/page_providers.tsx | 7 +-- .../infra/public/utils/validate_url_rt.ts | 16 +++++++ 6 files changed, 67 insertions(+), 53 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx create mode 100644 x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts index 4c4c317759bb..a2eaf9692b91 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts @@ -5,4 +5,4 @@ */ export * from './log_filter_state'; -export * from './with_log_filter_url_state'; +export * from './use_log_filter_url_state'; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx new file mode 100644 index 000000000000..f5d4dbea05f7 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useContext, useEffect } from 'react'; +import * as rt from 'io-ts'; +import { LogFilterState } from './log_filter_state'; +import { replaceStateKeyInQueryString } from '../../../utils/url_state'; +import { useUrlState } from '../../../utils/use_url_state'; +import { getEncodeDecodeFromRT } from '../../../utils/validate_url_rt'; + +const logFilterRT = rt.union([ + rt.type({ + kind: rt.literal('kuery'), + expression: rt.string, + }), + rt.undefined, +]); +type LogFilterUrlState = rt.TypeOf; + +const LOG_FILTER_URL_STATE_KEY = 'logFilter'; + +export const useLogFilterUrlState = () => { + const { filterQueryAsKuery, applyLogFilterQuery } = useContext(LogFilterState.Context); + const [logFilterUrlState, setLogFilterUrlState] = useUrlState({ + defaultState: filterQueryAsKuery, + urlStateKey: LOG_FILTER_URL_STATE_KEY, + writeDefaultState: true, + ...getEncodeDecodeFromRT(logFilterRT), + }); + + /* eslint-disable react-hooks/exhaustive-deps */ + useEffect(() => applyLogFilterQuery(logFilterUrlState.expression), [logFilterUrlState]); + useEffect(() => setLogFilterUrlState(filterQueryAsKuery), [filterQueryAsKuery]); + /* eslint-enable react-hooks/exhaustive-deps */ +}; + +export const replaceLogFilterInQueryString = (expression: string) => + replaceStateKeyInQueryString('logFilter', { + kind: 'kuery', + expression, + }); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx deleted file mode 100644 index d1da6c715cfc..000000000000 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useContext } from 'react'; -import { LogFilterState, LogFilterStateParams } from './log_filter_state'; -import { replaceStateKeyInQueryString, UrlStateContainer } from '../../../utils/url_state'; - -type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; - -export const WithLogFilterUrlState: React.FC = () => { - const { filterQueryAsKuery, applyLogFilterQuery } = useContext(LogFilterState.Context); - return ( - { - if (urlState) { - applyLogFilterQuery(urlState.expression); - } - }} - onInitialize={urlState => { - if (urlState) { - applyLogFilterQuery(urlState.expression); - } - }} - /> - ); -}; - -const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => - value?.kind === 'kuery' && typeof value.expression === 'string' - ? { - kind: value.kind, - expression: value.expression, - } - : undefined; - -export const replaceLogFilterInQueryString = (expression: string) => - replaceStateKeyInQueryString('logFilter', { - kind: 'kuery', - expression, - }); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index aff2a3b43106..0681a339efd1 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -15,7 +15,7 @@ import { PageContent } from '../../../components/page'; import { WithSummary } from '../../../containers/logs/log_summary'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; -import { LogFilterState } from '../../../containers/logs/log_filter'; +import { LogFilterState, useLogFilterUrlState } from '../../../containers/logs/log_filter'; import { LogFlyout as LogFlyoutState, WithFlyoutOptionsUrlState, @@ -42,6 +42,9 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { flyoutItem, isLoading, } = useContext(LogFlyoutState.Context); + + useLogFilterUrlState(); + const { logSummaryHighlights } = useContext(LogHighlightsState.Context); const { applyLogFilterQuery } = useContext(LogFilterState.Context); return ( diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx index 63425368b040..3d325cfcf8d8 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -10,7 +10,7 @@ import { LogFlyout } from '../../../containers/logs/log_flyout'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; import { LogHighlightsState } from '../../../containers/logs/log_highlights/log_highlights'; import { LogPositionState } from '../../../containers/logs/log_position'; -import { LogFilterState, WithLogFilterUrlState } from '../../../containers/logs/log_filter'; +import { LogFilterState } from '../../../containers/logs/log_filter'; import { LogEntriesState } from '../../../containers/logs/log_entries'; import { Source } from '../../../containers/source'; @@ -19,10 +19,7 @@ const LogFilterStateProvider: React.FC = ({ children }) => { const { createDerivedIndexPattern } = useContext(Source.Context); const derivedIndexPattern = createDerivedIndexPattern('logs'); return ( - - - {children} - + {children} ); }; diff --git a/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts b/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts new file mode 100644 index 000000000000..d68cef10f8c5 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { fold } from 'fp-ts/lib/Either'; +import { constant, identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; +import * as rt from 'io-ts'; + +export const getEncodeDecodeFromRT = (typeRT: rt.Type) => ({ + encodeUrlState: typeRT.encode, + decodeUrlState: (value: unknown) => + pipe(typeRT.decode(value), fold(constant(undefined), identity)), +}); From 43302b354af64f353397ef6936000e13b0996ff6 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 20 Dec 2019 12:32:43 -0600 Subject: [PATCH 14/16] Fix log filter URL state infinite loop --- .../containers/logs/log_filter/use_log_filter_url_state.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx index f5d4dbea05f7..76eff9e9812c 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx @@ -32,7 +32,11 @@ export const useLogFilterUrlState = () => { }); /* eslint-disable react-hooks/exhaustive-deps */ - useEffect(() => applyLogFilterQuery(logFilterUrlState.expression), [logFilterUrlState]); + useEffect(() => { + if (logFilterUrlState && filterQueryAsKuery?.expression !== logFilterUrlState.expression) { + applyLogFilterQuery(logFilterUrlState.expression); + } + }, [logFilterUrlState]); useEffect(() => setLogFilterUrlState(filterQueryAsKuery), [filterQueryAsKuery]); /* eslint-enable react-hooks/exhaustive-deps */ }; From 94ae62886f681929a845e8dd5be9946f962addd8 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 23 Dec 2019 11:16:59 -0600 Subject: [PATCH 15/16] Revert "Fix log filter URL state infinite loop" This reverts commit 43302b354af64f353397ef6936000e13b0996ff6. --- .../containers/logs/log_filter/use_log_filter_url_state.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx index 76eff9e9812c..f5d4dbea05f7 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx @@ -32,11 +32,7 @@ export const useLogFilterUrlState = () => { }); /* eslint-disable react-hooks/exhaustive-deps */ - useEffect(() => { - if (logFilterUrlState && filterQueryAsKuery?.expression !== logFilterUrlState.expression) { - applyLogFilterQuery(logFilterUrlState.expression); - } - }, [logFilterUrlState]); + useEffect(() => applyLogFilterQuery(logFilterUrlState.expression), [logFilterUrlState]); useEffect(() => setLogFilterUrlState(filterQueryAsKuery), [filterQueryAsKuery]); /* eslint-enable react-hooks/exhaustive-deps */ }; From 9a7e15d93b0eef55796f5b865b0f5e870ddac8e0 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 23 Dec 2019 11:17:10 -0600 Subject: [PATCH 16/16] Revert "Move URL state to hook" This reverts commit c61f5b190b75594c5a699f0b3ce69cc98a96ef88. --- .../containers/logs/log_filter/index.ts | 2 +- .../log_filter/use_log_filter_url_state.tsx | 44 ------------------ .../log_filter/with_log_filter_url_state.tsx | 46 +++++++++++++++++++ .../pages/logs/stream/page_logs_content.tsx | 5 +- .../pages/logs/stream/page_providers.tsx | 7 ++- .../infra/public/utils/validate_url_rt.ts | 16 ------- 6 files changed, 53 insertions(+), 67 deletions(-) delete mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx create mode 100644 x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts index a2eaf9692b91..4c4c317759bb 100644 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/index.ts @@ -5,4 +5,4 @@ */ export * from './log_filter_state'; -export * from './use_log_filter_url_state'; +export * from './with_log_filter_url_state'; diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx deleted file mode 100644 index f5d4dbea05f7..000000000000 --- a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/use_log_filter_url_state.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { useContext, useEffect } from 'react'; -import * as rt from 'io-ts'; -import { LogFilterState } from './log_filter_state'; -import { replaceStateKeyInQueryString } from '../../../utils/url_state'; -import { useUrlState } from '../../../utils/use_url_state'; -import { getEncodeDecodeFromRT } from '../../../utils/validate_url_rt'; - -const logFilterRT = rt.union([ - rt.type({ - kind: rt.literal('kuery'), - expression: rt.string, - }), - rt.undefined, -]); -type LogFilterUrlState = rt.TypeOf; - -const LOG_FILTER_URL_STATE_KEY = 'logFilter'; - -export const useLogFilterUrlState = () => { - const { filterQueryAsKuery, applyLogFilterQuery } = useContext(LogFilterState.Context); - const [logFilterUrlState, setLogFilterUrlState] = useUrlState({ - defaultState: filterQueryAsKuery, - urlStateKey: LOG_FILTER_URL_STATE_KEY, - writeDefaultState: true, - ...getEncodeDecodeFromRT(logFilterRT), - }); - - /* eslint-disable react-hooks/exhaustive-deps */ - useEffect(() => applyLogFilterQuery(logFilterUrlState.expression), [logFilterUrlState]); - useEffect(() => setLogFilterUrlState(filterQueryAsKuery), [filterQueryAsKuery]); - /* eslint-enable react-hooks/exhaustive-deps */ -}; - -export const replaceLogFilterInQueryString = (expression: string) => - replaceStateKeyInQueryString('logFilter', { - kind: 'kuery', - expression, - }); diff --git a/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx new file mode 100644 index 000000000000..d1da6c715cfc --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/containers/logs/log_filter/with_log_filter_url_state.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext } from 'react'; +import { LogFilterState, LogFilterStateParams } from './log_filter_state'; +import { replaceStateKeyInQueryString, UrlStateContainer } from '../../../utils/url_state'; + +type LogFilterUrlState = LogFilterStateParams['filterQueryAsKuery']; + +export const WithLogFilterUrlState: React.FC = () => { + const { filterQueryAsKuery, applyLogFilterQuery } = useContext(LogFilterState.Context); + return ( + { + if (urlState) { + applyLogFilterQuery(urlState.expression); + } + }} + onInitialize={urlState => { + if (urlState) { + applyLogFilterQuery(urlState.expression); + } + }} + /> + ); +}; + +const mapToFilterQuery = (value: any): LogFilterUrlState | undefined => + value?.kind === 'kuery' && typeof value.expression === 'string' + ? { + kind: value.kind, + expression: value.expression, + } + : undefined; + +export const replaceLogFilterInQueryString = (expression: string) => + replaceStateKeyInQueryString('logFilter', { + kind: 'kuery', + expression, + }); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index 0681a339efd1..aff2a3b43106 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -15,7 +15,7 @@ import { PageContent } from '../../../components/page'; import { WithSummary } from '../../../containers/logs/log_summary'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; -import { LogFilterState, useLogFilterUrlState } from '../../../containers/logs/log_filter'; +import { LogFilterState } from '../../../containers/logs/log_filter'; import { LogFlyout as LogFlyoutState, WithFlyoutOptionsUrlState, @@ -42,9 +42,6 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { flyoutItem, isLoading, } = useContext(LogFlyoutState.Context); - - useLogFilterUrlState(); - const { logSummaryHighlights } = useContext(LogHighlightsState.Context); const { applyLogFilterQuery } = useContext(LogFilterState.Context); return ( diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx index 3d325cfcf8d8..63425368b040 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -10,7 +10,7 @@ import { LogFlyout } from '../../../containers/logs/log_flyout'; import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; import { LogHighlightsState } from '../../../containers/logs/log_highlights/log_highlights'; import { LogPositionState } from '../../../containers/logs/log_position'; -import { LogFilterState } from '../../../containers/logs/log_filter'; +import { LogFilterState, WithLogFilterUrlState } from '../../../containers/logs/log_filter'; import { LogEntriesState } from '../../../containers/logs/log_entries'; import { Source } from '../../../containers/source'; @@ -19,7 +19,10 @@ const LogFilterStateProvider: React.FC = ({ children }) => { const { createDerivedIndexPattern } = useContext(Source.Context); const derivedIndexPattern = createDerivedIndexPattern('logs'); return ( - {children} + + + {children} + ); }; diff --git a/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts b/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts deleted file mode 100644 index d68cef10f8c5..000000000000 --- a/x-pack/legacy/plugins/infra/public/utils/validate_url_rt.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { fold } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; -import * as rt from 'io-ts'; - -export const getEncodeDecodeFromRT = (typeRT: rt.Type) => ({ - encodeUrlState: typeRT.encode, - decodeUrlState: (value: unknown) => - pipe(typeRT.decode(value), fold(constant(undefined), identity)), -});