Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Uptime] Use dynamic index pattern in Uptime #55446

Merged
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/uptime/common/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
*/

export const UNNAMED_LOCATION = 'Unnamed-location';

export const UPTIME_INDEX_PATTERN = 'heartbeat-8*';
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<State>({
suggestions: [],
isLoadingIndexPattern: true,
});
const [indexPattern, setIndexPattern] = useState<any | undefined>(undefined);
const [isLoadingIndexPattern, setIsLoadingIndexPattern] = useState<boolean>(true);
const [isLoadingSuggestions, setIsLoadingSuggestions] = useState<boolean>(false);
let currentRequestCheck: string;

useIndexPattern((result: any) => setIndexPattern(toStaticIndexPattern(result)));

useEffect(() => {
if (indexPattern !== undefined) {
setIsLoadingIndexPattern(false);
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/uptime/public/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
50 changes: 50 additions & 0 deletions x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts
Original file line number Diff line number Diff line change
@@ -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) => {
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
let error: any;
let kueryString: string = '';
try {
if (urlFilters !== '') {
const filterMap = new Map<string, Array<string | number>>(JSON.parse(urlFilters));
kueryString = stringifyKueries(filterMap);
}
} catch {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that this is not new code, but it may be worth addressing while we're working on this.

In general swallowing errors is something we should avoid because it makes debugging issues (esp. in production) very difficult. Tracing back a genuine error to this code would be tricky, and then we wouldn't know if the issue was in the stringify part, the map instantiation, or the JSON parsing. If we have to do it we should limit it to a single statement. If it's to catch the JSON parse failure then we should do something like:

let parsed;
let parseError;
try {
  parsed = JSON.parse(urlFilters);
} catch (e) {
  parseError = e;
}

// We can safely ignore parse errors here because <<insert explanation>>
if (parseError) {
  kueryString = stringify(kueries)
} else {
  ...the happy path...
}

Then, we could execute conditional logic later depending on whether there's an error or not.

Note that we should document the reason why we're swallowing the error here. Is there a situation where the JSON is expected to be invalid? If so, why? Why is it better to ignore it rather than surfacing an error?

My suspicion is that we can possibly even remove the error handling here. @justinkambic may know more here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can't have control over user input into url or kuery bar, i have improve the code to make it more readable.

kueryString = '';
}

const filterQueryString = search || '';
let filters: any | undefined;
try {
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
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];
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
error = e;
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
return [urlFilters, error];
}
};
21 changes: 0 additions & 21 deletions x-pack/legacy/plugins/uptime/public/hooks/use_index_pattern.ts

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion x-pack/legacy/plugins/uptime/public/lib/helper/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/uptime/public/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/';
66 changes: 15 additions & 51 deletions x-pack/legacy/plugins/uptime/public/pages/overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<any>(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<string, Array<string | number>>(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,
Expand All @@ -107,7 +71,7 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => {
const linkParameters = stringifyUrlParams(params, true);

return (
<Fragment>
<>
<PageHeader setBreadcrumbs={setBreadcrumbs} />
<EmptyState implementsCustomErrorState={true} variables={{}}>
<EuiFlexGroup gutterSize="xs" wrap responsive>
Expand All @@ -117,9 +81,9 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => {
<EuiFlexItemStyled grow={true}>
<FilterGroup
{...sharedProps}
currentFilter={urlFilters}
currentFilter={filters}
onFilterUpdate={(filtersKuery: string) => {
if (urlFilters !== filtersKuery) {
if (filters !== filtersKuery) {
updateUrl({ filters: filtersKuery, pagination: '' });
}
}}
Expand Down Expand Up @@ -152,6 +116,6 @@ export const OverviewPage = ({ autocomplete, setBreadcrumbs }: Props) => {
}}
/>
</EmptyState>
</Fragment>
</>
);
};
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/uptime/public/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
1 change: 1 addition & 0 deletions x-pack/legacy/plugins/uptime/public/state/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './overview_filters';
export * from './snapshot';
export * from './ui';
export * from './monitor_status';
export * from './index_patternts';
Loading