From 8f449ddd910ee43bbb867d7b4030b915451fdd26 Mon Sep 17 00:00:00 2001 From: shahzad Date: Fri, 24 Jan 2020 17:59:24 +0100 Subject: [PATCH] refactor index pattern state --- .../connected/index.ts} | 7 +- .../kuerybar/kuery_bar_container.tsx | 21 ++++++ .../connected/pages/overview_container.ts | 14 ++++ .../public/components/functional/index.ts | 2 +- .../kuery_bar/{index.tsx => kuery_bar.tsx} | 19 ++++-- .../plugins/uptime/public/hooks/index.ts | 2 +- .../public/hooks/update_kuery_string.ts | 50 ++++++++++++++ .../uptime/public/hooks/use_index_pattern.ts | 21 ------ .../plugins/uptime/public/lib/helper/index.ts | 1 - .../plugins/uptime/public/pages/index.ts | 2 +- .../plugins/uptime/public/pages/overview.tsx | 66 +++++-------------- .../legacy/plugins/uptime/public/routes.tsx | 2 +- .../uptime/public/state/actions/index.ts | 1 + .../public/state/actions/index_patternts.ts | 12 ++++ .../plugins/uptime/public/state/api/index.ts | 1 + .../uptime/public/state/api/index_pattern.ts | 21 ++++++ .../uptime/public/state/effects/index.ts | 2 + .../public/state/effects/index_pattern.ts | 17 +++++ .../uptime/public/state/reducers/index.ts | 2 + .../public/state/reducers/index_pattern.ts | 41 ++++++++++++ .../uptime/public/state/selectors/index.ts | 4 ++ .../lib/adapters/framework/adapter_types.ts | 15 +---- .../kibana_saved_objects_adapter.ts | 51 ++++++++++---- .../index_pattern/get_index_pattern.ts | 4 +- 24 files changed, 261 insertions(+), 117 deletions(-) rename x-pack/legacy/plugins/uptime/public/{lib/helper/to_static_index_pattern.ts => components/connected/index.ts} (59%) create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx create mode 100644 x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts rename x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/{index.tsx => kuery_bar.tsx} (91%) create mode 100644 x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts delete mode 100644 x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts create mode 100644 x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts similarity index 59% rename from x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts rename to x-pack/legacy/plugins/uptime/public/components/connected/index.ts index b8a12c1e578e39..4411432c890f11 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/to_static_index_pattern.ts +++ b/x-pack/legacy/plugins/uptime/public/components/connected/index.ts @@ -4,8 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export const toStaticIndexPattern = (indexPattern: any) => ({ - ...indexPattern, - fields: JSON.parse(indexPattern.attributes.fields), - title: indexPattern.id, -}); +export * from './kuerybar/kuery_bar_container'; +export * from './pages/overview_container'; diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx b/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx new file mode 100644 index 00000000000000..d0f160b2c55403 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/kuerybar/kuery_bar_container.tsx @@ -0,0 +1,21 @@ +/* + * 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 { connect } from 'react-redux'; +import { AppState } from '../../../state'; +import { selectIndexPattern } from '../../../state/selectors'; +import { getIndexPattern } from '../../../state/actions'; +import { KueryBarComponent } from '../../functional'; + +const mapStateToProps = (state: AppState) => ({ indexPattern: selectIndexPattern(state) }); + +const mapDispatchToProps = (dispatch: any) => ({ + loadIndexPattern: () => { + dispatch(getIndexPattern({})); + }, +}); + +export const KueryBar = connect(mapStateToProps, mapDispatchToProps)(KueryBarComponent); diff --git a/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts b/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts new file mode 100644 index 00000000000000..406fab8f5bf010 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/connected/pages/overview_container.ts @@ -0,0 +1,14 @@ +/* + * 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 { connect } from 'react-redux'; +import { OverviewPageComponent } from '../../../pages/overview'; +import { selectIndexPattern } from '../../../state/selectors'; +import { AppState } from '../../../state'; + +const mapStateToProps = (state: AppState) => ({ indexPattern: selectIndexPattern(state) }); + +export const OverviewPage = connect(mapStateToProps)(OverviewPageComponent); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts index 7370faa12f3939..bf72d664be4b20 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/index.ts +++ b/x-pack/legacy/plugins/uptime/public/components/functional/index.ts @@ -9,7 +9,7 @@ export { EmptyState } from './empty_state'; export { MonitorStatusBar } from './monitor_status_details'; export { FilterGroup } from './filter_group'; export { IntegrationLink } from './integration_link'; -export { KueryBar } from './kuery_bar'; +export { KueryBarComponent } from './kuery_bar/kuery_bar'; export { MonitorCharts } from './monitor_charts'; export { MonitorList } from './monitor_list'; export { OverviewPageParsingErrorCallout } from './overview_page_parsing_error_callout'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx similarity index 91% rename from x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx rename to x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx index 679106f7e19b4d..63c8885fe5864a 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/kuery_bar.tsx @@ -11,14 +11,12 @@ import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import { Typeahead } from './typeahead'; import { useUrlParams } from '../../../hooks'; -import { toStaticIndexPattern } from '../../../lib/helper'; import { esKuery, IIndexPattern, autocomplete, DataPublicPluginStart, } from '../../../../../../../../src/plugins/data/public'; -import { useIndexPattern } from '../../../hooks'; const Container = styled.div` margin-bottom: 10px; @@ -36,20 +34,29 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { interface Props { autocomplete: DataPublicPluginStart['autocomplete']; + loadIndexPattern: any; + indexPattern: any; } -export function KueryBar({ autocomplete: autocompleteService }: Props) { +export function KueryBarComponent({ + autocomplete: autocompleteService, + loadIndexPattern, + indexPattern, +}: Props) { + useEffect(() => { + if (!indexPattern) { + loadIndexPattern(); + } + }, [indexPattern, loadIndexPattern]); + const [state, setState] = useState({ suggestions: [], isLoadingIndexPattern: true, }); - const [indexPattern, setIndexPattern] = useState(undefined); const [isLoadingIndexPattern, setIsLoadingIndexPattern] = useState(true); const [isLoadingSuggestions, setIsLoadingSuggestions] = useState(false); let currentRequestCheck: string; - useIndexPattern((result: any) => setIndexPattern(toStaticIndexPattern(result))); - useEffect(() => { if (indexPattern !== undefined) { setIsLoadingIndexPattern(false); diff --git a/x-pack/legacy/plugins/uptime/public/hooks/index.ts b/x-pack/legacy/plugins/uptime/public/hooks/index.ts index aa7bb0a220357d..cfb8d71f783a6f 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/index.ts +++ b/x-pack/legacy/plugins/uptime/public/hooks/index.ts @@ -5,5 +5,5 @@ */ export { useUrlParams } from './use_url_params'; -export { useIndexPattern } from './use_index_pattern'; export * from './use_telemetry'; +export * from './update_kuery_string'; diff --git a/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts b/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts new file mode 100644 index 00000000000000..c2ee967f28d7f2 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts @@ -0,0 +1,50 @@ +/* + * 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 { combineFiltersAndUserSearch, stringifyKueries } from '../lib/helper'; +import { esKuery } from '../../../../../../src/plugins/data/common/es_query'; +import { store } from '../state'; +import { setEsKueryString } from '../state/actions'; + +export const useUpdateKueryString = (indexPattern: any, search: string, urlFilters: string) => { + let error: any; + let kueryString: string = ''; + try { + if (urlFilters !== '') { + const filterMap = new Map>(JSON.parse(urlFilters)); + kueryString = stringifyKueries(filterMap); + } + } catch { + kueryString = ''; + } + + const filterQueryString = search || ''; + let filters: any | undefined; + try { + if (filterQueryString || urlFilters) { + if (indexPattern) { + const staticIndexPattern = indexPattern; + const combinedFilterString = combineFiltersAndUserSearch(filterQueryString, kueryString); + const ast = esKuery.fromKueryExpression(combinedFilterString); + const elasticsearchQuery = esKuery.toElasticsearchQuery(ast, staticIndexPattern); + filters = JSON.stringify(elasticsearchQuery); + const searchDSL: string = filterQueryString + ? JSON.stringify( + esKuery.toElasticsearchQuery( + esKuery.fromKueryExpression(filterQueryString), + staticIndexPattern + ) + ) + : ''; + store.dispatch(setEsKueryString(searchDSL)); + } + } + return [filters, error]; + } catch (e) { + error = e; + return [urlFilters, error]; + } +}; diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts b/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts deleted file mode 100644 index f2b586b27dba69..00000000000000 --- a/x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts +++ /dev/null @@ -1,21 +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 { useEffect, Dispatch } from 'react'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; - -export const useIndexPattern = (setIndexPattern: Dispatch) => { - const core = useKibana(); - useEffect(() => { - const fetch = core.services.http?.fetch; - async function getIndexPattern() { - if (!fetch) throw new Error('Http core services are not defined'); - setIndexPattern(await fetch('/api/uptime/index_pattern', { method: 'GET' })); - } - getIndexPattern(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [core.services.http]); -}; diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts index ced06ce7a1d7b6..ef191ce32e5321 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts +++ b/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts @@ -12,5 +12,4 @@ export { getChartDateLabel } from './charts'; export { parameterizeValues } from './parameterize_values'; export { seriesHasDownValues } from './series_has_down_values'; export { stringifyKueries } from './stringify_kueries'; -export { toStaticIndexPattern } from './to_static_index_pattern'; export { UptimeUrlParams, getSupportedUrlParams } from './url_params'; diff --git a/x-pack/legacy/plugins/uptime/public/pages/index.ts b/x-pack/legacy/plugins/uptime/public/pages/index.ts index a96be42eb0deea..17f083ca023ed4 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/index.ts +++ b/x-pack/legacy/plugins/uptime/public/pages/index.ts @@ -5,6 +5,6 @@ */ export { MonitorPage } from './monitor'; -export { OverviewPage } from './overview'; export { NotFoundPage } from './not_found'; export { PageHeader } from './page_header'; +export { OverviewPage } from '../components/connected/'; diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index 36abee673b6829..0967cf45e682c1 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -5,30 +5,29 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import React, { Fragment, useContext, useState } from 'react'; +import React, { useContext } from 'react'; import styled from 'styled-components'; import { EmptyState, FilterGroup, - KueryBar, MonitorList, OverviewPageParsingErrorCallout, StatusPanel, } from '../components/functional'; import { UMUpdateBreadcrumbs } from '../lib/lib'; -import { useIndexPattern, useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks'; +import { useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; import { useTrackPageview } from '../../../infra/public'; -import { combineFiltersAndUserSearch, stringifyKueries, toStaticIndexPattern } from '../lib/helper'; -import { store } from '../state'; -import { setEsKueryString } from '../state/actions'; import { PageHeader } from './page_header'; -import { esKuery, DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; -import { UptimeThemeContext } from '../contexts/uptime_theme_context'; +import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; +import { UptimeThemeContext } from '../contexts'; +import { KueryBar } from '../components/connected'; +import { useUpdateKueryString } from '../hooks'; interface OverviewPageProps { autocomplete: DataPublicPluginStart['autocomplete']; setBreadcrumbs: UMUpdateBreadcrumbs; + indexPattern: any; } type Props = OverviewPageProps; @@ -42,60 +41,25 @@ const EuiFlexItemStyled = styled(EuiFlexItem)` } `; -export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { +export const OverviewPageComponent = ({ autocomplete, setBreadcrumbs, indexPattern }: Props) => { const { colors } = useContext(UptimeThemeContext); const [getUrlParams, updateUrl] = useUrlParams(); const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams(); const { dateRangeStart, dateRangeEnd, - search, pagination, statusFilter, + search, filters: urlFilters, } = params; - const [indexPattern, setIndexPattern] = useState(undefined); + useUptimeTelemetry(UptimePage.Overview); - useIndexPattern(setIndexPattern); useTrackPageview({ app: 'uptime', path: 'overview' }); useTrackPageview({ app: 'uptime', path: 'overview', delay: 15000 }); - let error: any; - let kueryString: string = ''; - try { - if (urlFilters !== '') { - const filterMap = new Map>(JSON.parse(urlFilters)); - kueryString = stringifyKueries(filterMap); - } - } catch { - kueryString = ''; - } - - const filterQueryString = search || ''; - let filters: any | undefined; - try { - if (filterQueryString || urlFilters) { - if (indexPattern) { - const staticIndexPattern = toStaticIndexPattern(indexPattern); - const combinedFilterString = combineFiltersAndUserSearch(filterQueryString, kueryString); - const ast = esKuery.fromKueryExpression(combinedFilterString); - const elasticsearchQuery = esKuery.toElasticsearchQuery(ast, staticIndexPattern); - filters = JSON.stringify(elasticsearchQuery); - const searchDSL: string = filterQueryString - ? JSON.stringify( - esKuery.toElasticsearchQuery( - esKuery.fromKueryExpression(filterQueryString), - staticIndexPattern - ) - ) - : ''; - store.dispatch(setEsKueryString(searchDSL)); - } - } - } catch (e) { - error = e; - } + const [filters, error] = useUpdateKueryString(indexPattern, search, urlFilters); const sharedProps = { dateRangeStart, @@ -107,7 +71,7 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { const linkParameters = stringifyUrlParams(params, true); return ( - + <> @@ -117,9 +81,9 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { { - if (urlFilters !== filtersKuery) { + if (filters !== filtersKuery) { updateUrl({ filters: filtersKuery, pagination: '' }); } }} @@ -152,6 +116,6 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => { }} /> - + ); }; diff --git a/x-pack/legacy/plugins/uptime/public/routes.tsx b/x-pack/legacy/plugins/uptime/public/routes.tsx index 07bba5163922e6..c318a82ab7f199 100644 --- a/x-pack/legacy/plugins/uptime/public/routes.tsx +++ b/x-pack/legacy/plugins/uptime/public/routes.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; -import { MonitorPage, OverviewPage, NotFoundPage } from './pages'; +import { MonitorPage, NotFoundPage, OverviewPage } from './pages'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { UMUpdateBreadcrumbs } from './lib/lib'; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index.ts b/x-pack/legacy/plugins/uptime/public/state/actions/index.ts index 9874da1839c2f3..689b812b4ea415 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/actions/index.ts @@ -8,3 +8,4 @@ export * from './overview_filters'; export * from './snapshot'; export * from './ui'; export * from './monitor_status'; +export * from './index_patternts'; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts b/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts new file mode 100644 index 00000000000000..f52dac805a199e --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts @@ -0,0 +1,12 @@ +/* + * 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 { createAction } from 'redux-actions'; +import { QueryParams } from './types'; + +export const getIndexPattern = createAction('GET_INDEX_PATTERN'); +export const getIndexPatternSuccess = createAction('GET_INDEX_PATTERN_SUCCESS'); +export const getIndexPatternFail = createAction('GET_INDEX_PATTERN_FAIL'); diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index.ts b/x-pack/legacy/plugins/uptime/public/state/api/index.ts index 1d0cac5f878543..d98856eadba750 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/api/index.ts @@ -8,3 +8,4 @@ export * from './monitor'; export * from './overview_filters'; export * from './snapshot'; export * from './monitor_status'; +export * from './index_pattern'; diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts new file mode 100644 index 00000000000000..895fe209e5a5cc --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts @@ -0,0 +1,21 @@ +/* + * 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 { getApiPath } from '../../lib/helper'; + +export interface APIParams { + basePath: string; +} + +export const fetchIndexPattern = async ({ basePath }: APIParams) => { + const url = getApiPath(`/api/uptime/index_pattern`, basePath); + + const response = await fetch(url); + if (!response.ok) { + throw new Error(response.statusText); + } + return await response.json(); +}; diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts index 41dda145edb4e2..acd7c3424fad26 100644 --- a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/effects/index.ts @@ -9,10 +9,12 @@ import { fetchMonitorDetailsEffect } from './monitor'; import { fetchOverviewFiltersEffect } from './overview_filters'; import { fetchSnapshotCountEffect } from './snapshot'; import { fetchMonitorStatusEffect } from './monitor_status'; +import { fetchIndexPatternEffect } from './index_pattern'; export function* rootEffect() { yield fork(fetchMonitorDetailsEffect); yield fork(fetchSnapshotCountEffect); yield fork(fetchOverviewFiltersEffect); yield fork(fetchMonitorStatusEffect); + yield fork(fetchIndexPatternEffect); } diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts new file mode 100644 index 00000000000000..a6f9256d5ccd96 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts @@ -0,0 +1,17 @@ +/* + * 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 { takeLatest } from 'redux-saga/effects'; +import { getIndexPattern, getIndexPatternSuccess, getIndexPatternFail } from '../actions'; +import { fetchIndexPattern } from '../api'; +import { fetchEffectFactory } from './fetch_effect'; + +export function* fetchIndexPatternEffect() { + yield takeLatest( + getIndexPattern, + fetchEffectFactory(fetchIndexPattern, getIndexPatternSuccess, getIndexPatternFail) + ); +} diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts index 5f915d970e5431..b00cc16ec337de 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts @@ -10,6 +10,7 @@ import { overviewFiltersReducer } from './overview_filters'; import { snapshotReducer } from './snapshot'; import { uiReducer } from './ui'; import { monitorStatusReducer } from './monitor_status'; +import { indexPatternReducer } from './index_pattern'; export const rootReducer = combineReducers({ monitor: monitorReducer, @@ -17,4 +18,5 @@ export const rootReducer = combineReducers({ snapshot: snapshotReducer, ui: uiReducer, monitorStatus: monitorStatusReducer, + indexPattern: indexPatternReducer, }); diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts new file mode 100644 index 00000000000000..dff043f81b95c2 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts @@ -0,0 +1,41 @@ +/* + * 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 { handleActions, Action } from 'redux-actions'; +import { getIndexPattern, getIndexPatternSuccess, getIndexPatternFail } from '../actions'; + +export interface IndexPatternState { + index_pattern: any; + errors: any[]; + loading: boolean; +} + +const initialState: IndexPatternState = { + index_pattern: null, + loading: false, + errors: [], +}; + +export const indexPatternReducer = handleActions( + { + [String(getIndexPattern)]: state => ({ + ...state, + loading: true, + }), + + [String(getIndexPatternSuccess)]: (state, action: Action) => ({ + ...state, + loading: false, + index_pattern: { ...action.payload }, + }), + + [String(getIndexPatternFail)]: (state, action: Action) => ({ + ...state, + errors: [...state.errors, action.payload], + loading: false, + }), + }, + initialState +); diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts index 337e99f6ede16a..f8ea7e59eb1c5c 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts @@ -28,3 +28,7 @@ export const selectSelectedMonitor = (state: AppState) => { export const selectMonitorStatus = (state: AppState) => { return state.monitorStatus.status; }; + +export const selectIndexPattern = ({ indexPattern }: AppState) => { + return indexPattern.index_pattern; +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index 2f72081a709884..1cb11634bb306c 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -8,26 +8,12 @@ import { GraphQLSchema } from 'graphql'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { SavedObjectsLegacyService, - RequestHandler, IRouter, CallAPIOptions, SavedObjectsClientContract, } from 'src/core/server'; -import { ObjectType } from '@kbn/config-schema'; import { UMKibanaRoute } from '../../../rest_api'; -export interface UMFrameworkRouteOptions< - P extends ObjectType, - Q extends ObjectType, - B extends ObjectType -> { - path: string; - method: string; - handler: RequestHandler; - config?: any; - validate: any; -} - type APICaller = ( endpoint: string, clientParams: Record, @@ -56,4 +42,5 @@ export interface UptimeCorePlugins { export interface UMBackendFrameworkAdapter { registerRoute(route: UMKibanaRoute): void; registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void; + getIndexPatternsService(); } diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts index 265efe10e82ed9..ff6327d97b828f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts @@ -4,23 +4,48 @@ * you may not use this file except in compliance with the Elastic License. */ +import { APICaller } from 'kibana/server'; import { UMSavedObjectsAdapter } from './types'; -import { UPTIME_INDEX_PATTERN } from '../../../../common/constants'; +import { + IndexPatternsFetcher, + IIndexPattern, +} from '../../../../../../../../src/plugins/data/server'; export const savedObjectsAdapter: UMSavedObjectsAdapter = { - getUptimeIndexPattern: async client => { + getUptimeIndexPattern: async callES => { + const indexPatternTitle = 'heartbeat-8*'; + + const indexPatternsFetcher = new IndexPatternsFetcher((...rest: Parameters) => + callES(...rest) + ); + + // Since `getDynamicIndexPattern` is called in setup_request (and thus by every endpoint) + // and since `getFieldsForWildcard` will throw if the specified indices don't exist, + // we have to catch errors here to avoid all endpoints returning 500 for users without APM data + // (would be a bad first time experience) try { - return await client.get('index-pattern', UPTIME_INDEX_PATTERN); - } catch (error) { - return await client.create( - 'index-pattern', - { - timeFieldName: '@timestamp', - title: 'heartbeat-8*', - fields: '[]', - }, - { id: UPTIME_INDEX_PATTERN, overwrite: false } - ); + const fields = await indexPatternsFetcher.getFieldsForWildcard({ + pattern: 'heartbeat-8*', + }); + + const indexPattern: IIndexPattern = { + fields, + title: indexPatternTitle, + }; + + return indexPattern; + } catch (e) { + const notExists = e.output?.statusCode === 404; + if (notExists) { + // eslint-disable-next-line no-console + console.error( + `Could not get dynamic index pattern because indices "${indexPatternTitle}" don't exist` + ); + return; + } + + // re-throw + throw e; } }, }; diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts index f061307807a42d..be603f88b6e911 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts @@ -14,11 +14,11 @@ export const createGetIndexPatternRoute: UMRestApiRouteFactory = (libs: UMServer options: { tags: ['access:uptime'], }, - handler: async ({ savedObjectsClient: client }, _context, _request, response): Promise => { + handler: async ({ callES }, _context, _request, response): Promise => { try { return response.ok({ body: { - ...(await libs.savedObjects.getUptimeIndexPattern(client, undefined)), + ...(await libs.savedObjects.getUptimeIndexPattern(callES, undefined)), }, }); } catch (e) {