From a524ca84b94a79446e5b1cc5b1f44eaa63ae3701 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 21 Apr 2021 10:22:18 +0200 Subject: [PATCH 01/17] wip --- .../exploratory_view/exploratory_view.tsx | 2 +- .../public/hooks/use_values_list.ts | 42 +++++++++++++++- .../server/routes/field_values_search.ts | 48 +++++++++++++++++++ ...l_observability_server_route_repository.ts | 3 +- 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/observability/server/routes/field_values_search.ts diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index 6bc91be876cf7..acae4a37f91f7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -53,7 +53,7 @@ export function ExploratoryView() { {lens ? ( <> - {lensAttributes && seriesId && series?.reportType && series?.time ? ( + {!lensAttributes && seriesId && series?.reportType && series?.time ? ( { + // if (!sourceField || !indexPattern) { + // return []; + // } + return new Promise((resolve) => { + const search$ = data.search + .search({ + params: { + index: indexPattern.title, + body: { + query: { match_all: {} }, + size: 0, + aggs: { + values: { + terms: { + field: 'monitor.name', + size: 65000, + }, + }, + }, + }, + }, + }) + .subscribe({ + next: (response) => { + if (isCompleteResponse(response)) { + // Final result + resolve(response); + search$.unsubscribe(); + } else { + resolve(response); + } + }, + }); + }); + }, [query, sourceField, data.autocomplete, indexPattern, from, to, filters]); + + console.log(values1); + return { values: values as string[], loading }; }; diff --git a/x-pack/plugins/observability/server/routes/field_values_search.ts b/x-pack/plugins/observability/server/routes/field_values_search.ts new file mode 100644 index 0000000000000..0019209508140 --- /dev/null +++ b/x-pack/plugins/observability/server/routes/field_values_search.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import * as t from 'io-ts'; +import { isoToEpochRt, toNumberRt } from '@kbn/io-ts-utils'; +import Boom from '@hapi/boom'; +import { createObservabilityServerRoute } from './create_observability_server_route'; +import { createObservabilityServerRouteRepository } from './create_observability_server_route_repository'; +import { getTopAlerts } from '../lib/rules/get_top_alerts'; + +const fieldValuesSearchRoute = createObservabilityServerRoute({ + endpoint: 'GET /api/observability/field_values_search', + options: { + tags: [], + }, + params: t.type({ + query: t.intersection([ + t.type({ + start: isoToEpochRt, + end: isoToEpochRt, + }), + t.partial({ + kuery: t.string, + size: toNumberRt, + }), + ]), + }), + handler: async ({ ruleRegistry, context, params }) => { + const { + query: { start, end, kuery, size = 100 }, + } = params; + + return getTopAlerts({ + ruleRegistryClient, + start, + end, + kuery, + size, + }); + }, +}); + +export const fieldValuesRouteRepository = createObservabilityServerRouteRepository().add( + fieldValuesSearchRoute +); diff --git a/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts b/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts index 8bc7c79a40b1b..35df3debb1f36 100644 --- a/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts +++ b/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts @@ -5,9 +5,10 @@ * 2.0. */ import { rulesRouteRepository } from './rules'; +import { fieldValuesRouteRepository } from './field_values_search'; export function getGlobalObservabilityServerRouteRepository() { - return rulesRouteRepository; + return rulesRouteRepository.merge(fieldValuesRouteRepository); } export type ObservabilityServerRouteRepository = ReturnType< From e08720b2e65a5812533343ccfcc2883f1069704f Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 21 Apr 2021 12:33:51 +0200 Subject: [PATCH 02/17] update --- .../autocomplete/value_suggestions_route.ts | 20 +++++- .../public/hooks/use_es_search.ts | 45 +++++++++++++ .../public/hooks/use_values_list.ts | 63 +++++++------------ 3 files changed, 84 insertions(+), 44 deletions(-) create mode 100644 x-pack/plugins/observability/public/hooks/use_es_search.ts diff --git a/src/plugins/data/server/autocomplete/value_suggestions_route.ts b/src/plugins/data/server/autocomplete/value_suggestions_route.ts index f0487b93b8ee5..30d2090fd37c4 100644 --- a/src/plugins/data/server/autocomplete/value_suggestions_route.ts +++ b/src/plugins/data/server/autocomplete/value_suggestions_route.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { get, map } from 'lodash'; +import { get, map, capitalize } from 'lodash'; import { schema } from '@kbn/config-schema'; import { IRouter, SharedGlobalConfig } from 'kibana/server'; @@ -79,7 +79,7 @@ async function getBody( // eslint-disable-next-line @typescript-eslint/naming-convention { timeout, terminate_after }: Record, field: IFieldType | string, - query: string, + rawQuery: string, filters: estypes.QueryContainer[] = [] ) { const isFieldObject = (f: any): f is IFieldType => Boolean(f && f.name); @@ -88,6 +88,20 @@ async function getBody( const getEscapedQuery = (q: string = '') => q.replace(/[.?+*|{}[\]()"\\#@&<>~]/g, (match) => `\\${match}`); + const query = getEscapedQuery(rawQuery); + + let includeClause = ''; + + if (query) { + if (query[0].toLowerCase() === query[0]) { + // if first letter is lowercase we also add the capitalize option + includeClause = `(${query}|${capitalize(query)}).*`; + } else { + // otherwise we add lowercase option prefix + includeClause = `(${query}|${query.toLowerCase()}).*`; + } + } + // Helps ensure that the regex is not evaluated eagerly against the terms dictionary const executionHint = 'map' as const; @@ -107,7 +121,7 @@ async function getBody( suggestions: { terms: { field: isFieldObject(field) ? field.name : field, - include: `${getEscapedQuery(query)}.*`, + ...(query ? { include: includeClause } : {}), execution_hint: executionHint, shard_size: shardSize, }, diff --git a/x-pack/plugins/observability/public/hooks/use_es_search.ts b/x-pack/plugins/observability/public/hooks/use_es_search.ts new file mode 100644 index 0000000000000..1bc524fd63cc2 --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/use_es_search.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { estypes } from '@elastic/elasticsearch'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import { ESSearchResponse } from '../../../../../typings/elasticsearch'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { isCompleteResponse } from '../../../../../src/plugins/data/common'; +import { useFetcher } from './use_fetcher'; + +export const useEsSearch = (params: TParams) => { + const { + services: { data }, + } = useKibana<{ data: DataPublicPluginStart }>(); + + const { data: response } = useFetcher(() => { + return new Promise((resolve) => { + const search$ = data.search + .search({ + params, + }) + .subscribe({ + next: (result) => { + if (isCompleteResponse(result)) { + // Final result + resolve(result); + search$.unsubscribe(); + } else { + resolve(result); + } + }, + }); + }); + }, [data.search, params]); + + return response as { body: ESSearchResponse }; +}; + +export function createEsParams(params: T): T { + return params; +} diff --git a/x-pack/plugins/observability/public/hooks/use_values_list.ts b/x-pack/plugins/observability/public/hooks/use_values_list.ts index e383558b20f47..992fdd4a2c260 100644 --- a/x-pack/plugins/observability/public/hooks/use_values_list.ts +++ b/x-pack/plugins/observability/public/hooks/use_values_list.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { IndexPattern, isCompleteResponse } from '../../../../../src/plugins/data/common'; +import { IndexPattern } from '../../../../../src/plugins/data/common'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { useFetcher } from './use_fetcher'; import { ESFilter } from '../../../../../typings/elasticsearch'; -import { buildPhraseFilter } from '../components/shared/exploratory_view/configurations/utils'; +import { createEsParams, useEsSearch } from './use_es_search'; export interface Props { sourceField: string; @@ -33,6 +33,26 @@ export const useValuesList = ({ const { from, to } = time ?? {}; + const response = useEsSearch( + createEsParams({ + index: indexPattern.title, + body: { + query: { match_all: {} }, + size: 0, + aggs: { + values: { + terms: { + field: 'monitor.name', + size: 65000, + }, + }, + }, + }, + }) + ); + + const vals = response.body.aggregations?.values.buckets; + const { data: values, loading } = useFetcher(() => { if (!sourceField || !indexPattern) { return []; @@ -59,44 +79,5 @@ export const useValuesList = ({ }); }, [query, sourceField, data.autocomplete, indexPattern, from, to, filters]); - const { data: values1 } = useFetcher(async () => { - // if (!sourceField || !indexPattern) { - // return []; - // } - return new Promise((resolve) => { - const search$ = data.search - .search({ - params: { - index: indexPattern.title, - body: { - query: { match_all: {} }, - size: 0, - aggs: { - values: { - terms: { - field: 'monitor.name', - size: 65000, - }, - }, - }, - }, - }, - }) - .subscribe({ - next: (response) => { - if (isCompleteResponse(response)) { - // Final result - resolve(response); - search$.unsubscribe(); - } else { - resolve(response); - } - }, - }); - }); - }, [query, sourceField, data.autocomplete, indexPattern, from, to, filters]); - - console.log(values1); - return { values: values as string[], loading }; }; From fed2f9bb537e554ae7a9a62298ee8e736dd08258 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 21 Apr 2021 13:56:35 +0200 Subject: [PATCH 03/17] wip --- .../exploratory_view/exploratory_view.tsx | 12 ++++- .../series_editor/chart_edit_options.tsx | 30 +++++++++++ .../series_editor/series_editor.tsx | 52 +++++++++---------- 3 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index 6bc91be876cf7..58d6353cea398 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import { EuiPanel, EuiTitle } from '@elastic/eui'; +import styled from 'styled-components'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { ExploratoryViewHeader } from './header/header'; @@ -49,7 +50,7 @@ export function ExploratoryView() { }, [JSON.stringify(lensAttributesT ?? {}), series?.reportType, series?.time?.from]); return ( - + {lens ? ( <> @@ -75,6 +76,13 @@ export function ExploratoryView() { )} - + ); } + +const Wrapper = styled(EuiPanel)` + max-width: 1800px; + min-width: 800px; + margin: 0 auto; + width: 100%; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx new file mode 100644 index 0000000000000..c95d322748607 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { Breakdowns } from './columns/breakdowns'; +import { DataSeries } from '../types'; +import { ChartOptions } from './columns/chart_options'; + +interface Props { + series: DataSeries; + seriesId: string; + breakdowns: string[]; +} +export function ChartEditOptions({ series, seriesId, breakdowns }: Props) { + return ( + + + + + + + + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx index b9e68c1267c9e..951077bc09cde 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx @@ -9,16 +9,16 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiBasicTable, EuiIcon, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import styled from 'styled-components'; import { SeriesFilter } from './columns/series_filter'; -import { Breakdowns } from './columns/breakdowns'; import { DataSeries } from '../types'; import { SeriesBuilder } from '../series_builder/series_builder'; import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_storage'; import { getDefaultConfigs } from '../configurations/default_configs'; import { DatePickerCol } from './columns/date_picker_col'; import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; -import { ChartOptions } from './columns/chart_options'; import { SeriesActions } from './columns/series_actions'; +import { ChartEditOptions } from './chart_edit_options'; export function SeriesEditor() { const { allSeries, firstSeriesId } = useUrlStorage(); @@ -44,7 +44,7 @@ export function SeriesEditor() { defaultMessage: 'Filters', }), field: 'defaultFilters', - width: '25%', + width: '15%', render: (defaultFilters: string[], series: DataSeries) => ( ), @@ -54,18 +54,11 @@ export function SeriesEditor() { defaultMessage: 'Breakdowns', }), field: 'breakdowns', - width: '15%', + width: '25%', render: (val: string[], item: DataSeries) => ( - + ), }, - { - name: '', - align: 'center' as const, - width: '15%', - field: 'id', - render: (val: string, item: DataSeries) => , - }, { name: (
@@ -85,7 +78,7 @@ export function SeriesEditor() { defaultMessage: 'Actions', }), align: 'center' as const, - width: '8%', + width: '10%', field: 'id', render: (val: string, item: DataSeries) => , }, @@ -115,22 +108,27 @@ export function SeriesEditor() { return ( <> - (firstSeriesId === NEW_SERIES_KEY ? {} : { height: 100 })} - noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.notFound', { - defaultMessage: 'No series found, please add a series.', - })} - cellProps={{ - style: { - verticalAlign: 'top', - }, - }} - /> + + (firstSeriesId === NEW_SERIES_KEY ? {} : { height: 100 })} + noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.notFound', { + defaultMessage: 'No series found, please add a series.', + })} + cellProps={{ + style: { + verticalAlign: 'top', + }, + }} + tableLayout="auto" + /> + ); } + +const Wrapper = styled.div``; From af25418f214df66f6bcac6bfa90cb2cd0bfee330 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 21 Apr 2021 17:27:00 +0200 Subject: [PATCH 04/17] improved filtering search --- .../exploratory_view/exploratory_view.tsx | 2 +- .../series_editor/columns/filter_expanded.tsx | 110 +++++++++++------- .../public/hooks/use_es_search.ts | 16 ++- .../public/hooks/use_values_list.ts | 100 ++++++++++------ 4 files changed, 145 insertions(+), 83 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index acae4a37f91f7..6bc91be876cf7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -53,7 +53,7 @@ export function ExploratoryView() { {lens ? ( <> - {!lensAttributes && seriesId && series?.reportType && series?.time ? ( + {lensAttributes && seriesId && series?.reportType && series?.time ? ( ([]); + const [value, setValue] = useState(''); const [isOpen, setIsOpen] = useState({ value: '', negate: false }); @@ -45,14 +45,21 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField, is time: series.time, }); + useEffect(() => { + setDisplayValues((prevState) => { + const newValues = merge(prevState, values); + const filteredValues = newValues.filter((opt) => + opt.toLowerCase().includes(value.toLowerCase()) + ); + return [...filteredValues]; + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [loading, value, values?.length]); + const filters = series?.filters ?? []; const currFilter: UrlFilter | undefined = filters.find(({ field: fd }) => field === fd); - const displayValues = (values || []).filter((opt) => - opt.toLowerCase().includes(value.toLowerCase()) - ); - return ( goBack()}> @@ -60,50 +67,75 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField, is { setValue(evt.target.value); }} + placeholder={i18n.translate('xpack.observability.filters.expanded.search', { + defaultMessage: 'Search for {label}', + values: { label }, + })} /> - {loading && ( -
- -
- )} - {displayValues.map((opt) => ( - - - {isNegated !== false && ( + + {displayValues.map((opt) => ( + + + {isNegated !== false && ( + + )} - )} - - - - - ))} + + + + ))} +
); } +// const ListWrapper = styled.div` +// max-height: 600px; +// overflow-y: auto; +// `; + +const ListWrapper = euiStyled.div` + height: 400px; + overflow-y: auto; + &::-webkit-scrollbar { + height: ${({ theme }) => theme.eui.euiScrollBar}; + width: ${({ theme }) => theme.eui.euiScrollBar}; + } + &::-webkit-scrollbar-thumb { + background-clip: content-box; + background-color: ${({ theme }) => rgba(theme.eui.euiColorDarkShade, 0.5)}; + border: ${({ theme }) => theme.eui.euiScrollBarCorner} solid transparent; + } + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } +`; + const Wrapper = styled.div` - max-width: 400px; + width: 400px; `; diff --git a/x-pack/plugins/observability/public/hooks/use_es_search.ts b/x-pack/plugins/observability/public/hooks/use_es_search.ts index 1bc524fd63cc2..b6ee4a63823b1 100644 --- a/x-pack/plugins/observability/public/hooks/use_es_search.ts +++ b/x-pack/plugins/observability/public/hooks/use_es_search.ts @@ -12,12 +12,15 @@ import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { isCompleteResponse } from '../../../../../src/plugins/data/common'; import { useFetcher } from './use_fetcher'; -export const useEsSearch = (params: TParams) => { +export const useEsSearch = ( + params: TParams, + fnDeps: any[] +) => { const { services: { data }, } = useKibana<{ data: DataPublicPluginStart }>(); - const { data: response } = useFetcher(() => { + const { data: response = {}, loading } = useFetcher(() => { return new Promise((resolve) => { const search$ = data.search .search({ @@ -29,15 +32,16 @@ export const useEsSearch = (params: TPara // Final result resolve(result); search$.unsubscribe(); - } else { - resolve(result); } }, }); }); - }, [data.search, params]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [...fnDeps]); + + const { rawResponse } = response as any; - return response as { body: ESSearchResponse }; + return { data: rawResponse as ESSearchResponse, loading }; }; export function createEsParams(params: T): T { diff --git a/x-pack/plugins/observability/public/hooks/use_values_list.ts b/x-pack/plugins/observability/public/hooks/use_values_list.ts index 992fdd4a2c260..147a66f3d505e 100644 --- a/x-pack/plugins/observability/public/hooks/use_values_list.ts +++ b/x-pack/plugins/observability/public/hooks/use_values_list.ts @@ -5,10 +5,10 @@ * 2.0. */ +import { capitalize, merge } from 'lodash'; +import { useEffect, useState } from 'react'; +import { useDebounce } from 'react-use'; import { IndexPattern } from '../../../../../src/plugins/data/common'; -import { useKibana } from '../../../../../src/plugins/kibana_react/public'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { useFetcher } from './use_fetcher'; import { ESFilter } from '../../../../../typings/elasticsearch'; import { createEsParams, useEsSearch } from './use_es_search'; @@ -18,6 +18,7 @@ export interface Props { indexPattern: IndexPattern; filters?: ESFilter[]; time?: { from: string; to: string }; + keepHistory?: boolean; } export const useValuesList = ({ @@ -26,58 +27,83 @@ export const useValuesList = ({ query = '', filters, time, + keepHistory, }: Props): { values: string[]; loading?: boolean } => { - const { - services: { data }, - } = useKibana<{ data: DataPublicPluginStart }>(); + const [debouncedQuery, setDebounceQuery] = useState(query); + const [values, setValues] = useState([]); const { from, to } = time ?? {}; - const response = useEsSearch( + let includeClause = ''; + + if (query) { + if (query[0].toLowerCase() === query[0]) { + // if first letter is lowercase we also add the capitalize option + includeClause = `(${query}|${capitalize(query)}).*`; + } else { + // otherwise we add lowercase option prefix + includeClause = `(${query}|${query.toLowerCase()}).*`; + } + } + + useDebounce( + () => { + setDebounceQuery(query); + }, + 350, + [query] + ); + + const { data, loading } = useEsSearch( createEsParams({ index: indexPattern.title, body: { - query: { match_all: {} }, + query: { + bool: { + filter: [ + ...(filters ?? []), + ...(from && to + ? [ + { + range: { + '@timestamp': { + gte: from, + lte: to, + }, + }, + }, + ] + : []), + ], + }, + }, size: 0, aggs: { values: { terms: { - field: 'monitor.name', - size: 65000, + field: sourceField, + size: 100, + ...(query ? { include: includeClause } : {}), }, }, }, }, - }) + }), + [debouncedQuery, from, to] ); - const vals = response.body.aggregations?.values.buckets; + useEffect(() => { + const newValues = + data?.aggregations?.values.buckets.map(({ key: value }) => value as string) ?? []; - const { data: values, loading } = useFetcher(() => { - if (!sourceField || !indexPattern) { - return []; + if (keepHistory) { + setValues((prevState) => { + return merge(newValues, prevState); + }); + } else { + setValues(newValues); } - return data.autocomplete.getValueSuggestions({ - indexPattern, - query: query || '', - useTimeRange: !(from && to), - field: indexPattern.getFieldByName(sourceField)!, - boolFilter: - from && to - ? [ - ...(filters || []), - { - range: { - '@timestamp': { - gte: from, - lte: to, - }, - }, - }, - ] - : filters || [], - }); - }, [query, sourceField, data.autocomplete, indexPattern, from, to, filters]); + }, [data, keepHistory, loading]); - return { values: values as string[], loading }; + return { values, loading }; }; From 7af65fa302d4a5646a78c686a5729142ea94be2e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 21 Apr 2021 17:43:36 +0200 Subject: [PATCH 05/17] update hook --- .../series_editor/columns/filter_expanded.tsx | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx index 98015e70ab8dd..7a646c9035968 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import React, { useState, Fragment, useEffect } from 'react'; -import { merge } from 'lodash'; +import React, { useState, Fragment } from 'react'; import { EuiFieldSearch, EuiSpacer, EuiButtonEmpty, EuiFilterGroup } from '@elastic/eui'; import styled from 'styled-components'; import { rgba } from 'polished'; @@ -30,8 +29,6 @@ interface Props { export function FilterExpanded({ seriesId, field, label, goBack, nestedField, isNegated }: Props) { const { indexPattern } = useAppIndexPatternContext(); - const [displayValues, setDisplayValues] = useState([]); - const [value, setValue] = useState(''); const [isOpen, setIsOpen] = useState({ value: '', negate: false }); @@ -43,23 +40,15 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField, is indexPattern, sourceField: field, time: series.time, + keepHistory: true, }); - useEffect(() => { - setDisplayValues((prevState) => { - const newValues = merge(prevState, values); - const filteredValues = newValues.filter((opt) => - opt.toLowerCase().includes(value.toLowerCase()) - ); - return [...filteredValues]; - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [loading, value, values?.length]); - const filters = series?.filters ?? []; const currFilter: UrlFilter | undefined = filters.find(({ field: fd }) => field === fd); + const displayValues = values.filter((opt) => opt.toLowerCase().includes(value.toLowerCase())); + return ( goBack()}> @@ -113,11 +102,6 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField, is ); } -// const ListWrapper = styled.div` -// max-height: 600px; -// overflow-y: auto; -// `; - const ListWrapper = euiStyled.div` height: 400px; overflow-y: auto; From 88652b316451c7a460508c8fde0c0c33d202f818 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 22 Apr 2021 21:17:00 +0200 Subject: [PATCH 06/17] fix types --- .../autocomplete/value_suggestions_route.ts | 20 ++------ .../columns/filter_expanded.test.tsx | 3 +- .../server/routes/field_values_search.ts | 48 ------------------- ...l_observability_server_route_repository.ts | 3 +- 4 files changed, 6 insertions(+), 68 deletions(-) delete mode 100644 x-pack/plugins/observability/server/routes/field_values_search.ts diff --git a/src/plugins/data/server/autocomplete/value_suggestions_route.ts b/src/plugins/data/server/autocomplete/value_suggestions_route.ts index 30d2090fd37c4..f0487b93b8ee5 100644 --- a/src/plugins/data/server/autocomplete/value_suggestions_route.ts +++ b/src/plugins/data/server/autocomplete/value_suggestions_route.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { get, map, capitalize } from 'lodash'; +import { get, map } from 'lodash'; import { schema } from '@kbn/config-schema'; import { IRouter, SharedGlobalConfig } from 'kibana/server'; @@ -79,7 +79,7 @@ async function getBody( // eslint-disable-next-line @typescript-eslint/naming-convention { timeout, terminate_after }: Record, field: IFieldType | string, - rawQuery: string, + query: string, filters: estypes.QueryContainer[] = [] ) { const isFieldObject = (f: any): f is IFieldType => Boolean(f && f.name); @@ -88,20 +88,6 @@ async function getBody( const getEscapedQuery = (q: string = '') => q.replace(/[.?+*|{}[\]()"\\#@&<>~]/g, (match) => `\\${match}`); - const query = getEscapedQuery(rawQuery); - - let includeClause = ''; - - if (query) { - if (query[0].toLowerCase() === query[0]) { - // if first letter is lowercase we also add the capitalize option - includeClause = `(${query}|${capitalize(query)}).*`; - } else { - // otherwise we add lowercase option prefix - includeClause = `(${query}|${query.toLowerCase()}).*`; - } - } - // Helps ensure that the regex is not evaluated eagerly against the terms dictionary const executionHint = 'map' as const; @@ -121,7 +107,7 @@ async function getBody( suggestions: { terms: { field: isFieldObject(field) ? field.name : field, - ...(query ? { include: includeClause } : {}), + include: `${getEscapedQuery(query)}.*`, execution_hint: executionHint, shard_size: shardSize, }, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx index 530b8dee3a4d2..8d3060792857e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx @@ -8,12 +8,13 @@ import React from 'react'; import { fireEvent, screen } from '@testing-library/react'; import { FilterExpanded } from './filter_expanded'; -import { mockUrlStorage, mockUseValuesList, render } from '../../rtl_helpers'; +import { mockAppIndexPattern, mockUrlStorage, mockUseValuesList, render } from '../../rtl_helpers'; import { USER_AGENT_NAME } from '../../configurations/constants/elasticsearch_fieldnames'; describe('FilterExpanded', function () { it('should render properly', async function () { mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + mockAppIndexPattern(); render( { - const { - query: { start, end, kuery, size = 100 }, - } = params; - - return getTopAlerts({ - ruleRegistryClient, - start, - end, - kuery, - size, - }); - }, -}); - -export const fieldValuesRouteRepository = createObservabilityServerRouteRepository().add( - fieldValuesSearchRoute -); diff --git a/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts b/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts index 35df3debb1f36..8bc7c79a40b1b 100644 --- a/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts +++ b/x-pack/plugins/observability/server/routes/get_global_observability_server_route_repository.ts @@ -5,10 +5,9 @@ * 2.0. */ import { rulesRouteRepository } from './rules'; -import { fieldValuesRouteRepository } from './field_values_search'; export function getGlobalObservabilityServerRouteRepository() { - return rulesRouteRepository.merge(fieldValuesRouteRepository); + return rulesRouteRepository; } export type ObservabilityServerRouteRepository = ReturnType< From 040bcee5d8a41b9b1358e6046697c16eeb11c4ac Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 22 Apr 2021 21:49:37 +0200 Subject: [PATCH 07/17] remove/comment add series workflow --- .../exploratory_view/exploratory_view.tsx | 4 +- .../series_builder/series_builder.tsx | 98 ++++--------------- .../series_editor/series_editor.tsx | 37 +++---- 3 files changed, 35 insertions(+), 104 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index 58d6353cea398..58ce1e44934e2 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -11,13 +11,13 @@ import styled from 'styled-components'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { ExploratoryViewHeader } from './header/header'; -import { SeriesEditor } from './series_editor/series_editor'; import { useUrlStorage } from './hooks/use_url_storage'; import { useLensAttributes } from './hooks/use_lens_attributes'; import { EmptyView } from './components/empty_view'; import { TypedLensByValueInput } from '../../../../../lens/public'; import { useAppIndexPatternContext } from './hooks/use_app_index_pattern'; import { ReportToDataTypeMap } from './configurations/constants'; +import { SeriesBuilder } from './series_builder/series_builder'; export function ExploratoryView() { const { @@ -64,7 +64,7 @@ export function ExploratoryView() { ) : ( )} - + ) : ( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx index db6e075cc90fb..ba3a06325a429 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx @@ -5,10 +5,10 @@ * 2.0. */ -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButton, EuiBasicTable, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { AppDataType, ReportViewTypeId, ReportViewTypes, SeriesUrl } from '../types'; import { DataTypesCol } from './columns/data_types_col'; import { ReportTypesCol } from './columns/report_types_col'; @@ -45,8 +45,8 @@ export const ReportTypes: Record { return getDefaultConfigs({ + seriesId, indexPattern, reportType: reportType!, - seriesId: NEW_SERIES_KEY, }); }; - useEffect(() => { - setIsFlyoutVisible(!!series.dataType); - }, [series.dataType]); - const columns = [ { name: i18n.translate('xpack.observability.expView.seriesBuilder.dataType', { @@ -152,80 +146,24 @@ export function SeriesBuilder() { setSeries(newSeriesId, newSeriesN).then(() => { removeSeries(NEW_SERIES_KEY); - setIsFlyoutVisible(false); }); } }; - const items = [{ id: NEW_SERIES_KEY }]; - - let flyout; - - if (isFlyoutVisible) { - flyout = ( - <> - - - - - - {i18n.translate('xpack.observability.expView.seriesBuilder.add', { - defaultMessage: 'Add', - })} - - - - { - removeSeries(NEW_SERIES_KEY); - setIsFlyoutVisible(false); - }} - > - {i18n.translate('xpack.observability.expView.seriesBuilder.cancel', { - defaultMessage: 'Cancel', - })} - - - - - ); - } - - return ( -
- {!isFlyoutVisible && ( - <> - setIsFlyoutVisible((prevState) => !prevState)} - disabled={allSeriesIds.length > 0} - > - {i18n.translate('xpack.observability.expView.seriesBuilder.addSeries', { - defaultMessage: 'Add series', - })} - - - - )} - {flyout} -
+ const items = [{ id: seriesId }]; + + const flyout = ( + <> + + + ); + + return
{flyout}
; } export const INITIATING_VIEW = i18n.translate( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx index 951077bc09cde..d883b854c88cb 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx @@ -9,10 +9,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiBasicTable, EuiIcon, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import styled from 'styled-components'; import { SeriesFilter } from './columns/series_filter'; import { DataSeries } from '../types'; -import { SeriesBuilder } from '../series_builder/series_builder'; import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_storage'; import { getDefaultConfigs } from '../configurations/default_configs'; import { DatePickerCol } from './columns/date_picker_col'; @@ -108,27 +106,22 @@ export function SeriesEditor() { return ( <> - - (firstSeriesId === NEW_SERIES_KEY ? {} : { height: 100 })} - noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.notFound', { - defaultMessage: 'No series found, please add a series.', - })} - cellProps={{ - style: { - verticalAlign: 'top', - }, - }} - tableLayout="auto" - /> - + (firstSeriesId === NEW_SERIES_KEY ? {} : { height: 100 })} + noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.notFound', { + defaultMessage: 'No series found, please add a series.', + })} + cellProps={{ + style: { + verticalAlign: 'top', + }, + }} + tableLayout="auto" + /> - ); } - -const Wrapper = styled.div``; From 21e7a8496ce514b3e69eaa5d96a8b24bf60e2994 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 23 Apr 2021 13:38:49 +0200 Subject: [PATCH 08/17] Polish exploratory view --- .../components/app/layout/with_header.tsx | 4 +- .../components/empty_view.tsx | 35 ++++++------- .../configurations/constants/constants.ts | 2 +- .../configurations/constants/url_constants.ts | 1 + .../configurations/lens_attributes.ts | 10 ++-- .../exploratory_view/configurations/utils.ts | 2 + .../exploratory_view/exploratory_view.tsx | 49 ++++++++++++++----- .../hooks/use_lens_attributes.ts | 2 +- .../hooks/use_series_filters.ts | 24 ++++----- .../hooks/use_url_storage.tsx | 5 +- .../series_builder/columns/data_types_col.tsx | 13 ++--- .../columns/report_breakdowns.tsx | 11 +++-- .../columns/report_definition_col.tsx | 42 +++++++++------- .../series_builder/columns/report_filters.tsx | 11 +++-- .../columns/report_types_col.tsx | 11 +++-- .../series_builder/series_builder.tsx | 46 ++++++++++------- .../series_editor/columns/series_filter.tsx | 11 ++--- .../series_editor/selected_filters.tsx | 4 +- .../shared/exploratory_view/types.ts | 6 ++- .../field_value_selection.stories.tsx | 10 ++-- .../field_value_selection.tsx | 32 +++++++----- .../shared/field_value_suggestions/index.tsx | 4 +- .../shared/field_value_suggestions/types.ts | 6 +-- .../common/charts/ping_histogram.tsx | 1 + .../monitor_duration_container.tsx | 1 + 25 files changed, 203 insertions(+), 140 deletions(-) diff --git a/x-pack/plugins/observability/public/components/app/layout/with_header.tsx b/x-pack/plugins/observability/public/components/app/layout/with_header.tsx index 648b49440546b..f2d50539395bd 100644 --- a/x-pack/plugins/observability/public/components/app/layout/with_header.tsx +++ b/x-pack/plugins/observability/public/components/app/layout/with_header.tsx @@ -16,7 +16,9 @@ const Page = styled(EuiPage)` const Container = styled.div<{ color?: string }>` overflow-y: hidden; - min-height: calc(100vh - ${(props) => props.theme.eui.euiHeaderChildSize}); + min-height: calc( + 100vh - ${(props) => props.theme.eui.euiHeaderHeight + props.theme.eui.euiHeaderHeight} + ); background: ${(props) => props.color}; `; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx index 69b8b6eb89e46..b54f6f6db00ff 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx @@ -6,18 +6,13 @@ */ import React from 'react'; -import { EuiImage, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui'; import styled from 'styled-components'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; -import { INITIATING_VIEW } from '../series_builder/series_builder'; - -export function EmptyView({ loading }: { loading: boolean }) { - const { - services: { http }, - } = useKibana(); +import { LOADING_VIEW } from '../series_builder/series_builder'; +export function EmptyView({ loading, height }: { loading: boolean; height: string }) { return ( - + {loading && ( )} - - {INITIATING_VIEW} + + + {LOADING_VIEW} + + ); } -const ImageWrap = styled(EuiImage)` - opacity: 0.4; -`; - -const Wrapper = styled.div` +const Wrapper = styled.div<{ height: string }>` text-align: center; - height: 550px; + height: ${(props) => props.height}; position: relative; `; + +const FlexGroup = styled(EuiFlexGroup)` + height: 100%; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index 5c09dbcff2d91..0e1e1681373cb 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -34,7 +34,7 @@ export const FieldLabels: Record = { 'monitor.name': 'Monitor name', 'monitor.type': 'Monitor Type', 'url.port': 'Port', - 'url.full': 'Url', + 'url.full': 'URL', tags: 'Tags', // custom diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/url_constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/url_constants.ts index 67d72a656744c..b5a5169216b7b 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/url_constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/url_constants.ts @@ -6,6 +6,7 @@ */ export enum URL_KEYS { + DATA_TYPE = 'dt', OPERATION_TYPE = 'op', REPORT_TYPE = 'rt', SERIES_TYPE = 'st', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index 146f488450f3a..3e22c4da6115a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -31,7 +31,7 @@ import { IndexPattern, } from '../../../../../../../../src/plugins/data/common'; import { FieldLabels } from './constants'; -import { DataSeries, UrlFilter } from '../types'; +import { DataSeries, UrlFilter, URLReportDefinition } from '../types'; function getLayerReferenceName(layerId: string) { return `indexpattern-datasource-layer-${layerId}`; @@ -49,7 +49,7 @@ function buildNumberColumn(sourceField: string) { export const parseCustomFieldName = ( sourceField: string, reportViewConfig: DataSeries, - selectedDefinitions: Record + selectedDefinitions: URLReportDefinition ) => { let fieldName = sourceField; let columnType; @@ -60,7 +60,7 @@ export const parseCustomFieldName = ( if (customField) { if (selectedDefinitions[fieldName]) { - fieldName = selectedDefinitions[fieldName]; + fieldName = selectedDefinitions[fieldName][0]; if (customField?.options) columnType = customField?.options?.find(({ field }) => field === fieldName)?.columnType; } else if (customField.defaultValue) { @@ -81,7 +81,7 @@ export class LensAttributes { filters: UrlFilter[]; seriesType: SeriesType; reportViewConfig: DataSeries; - reportDefinitions: Record; + reportDefinitions: URLReportDefinition; constructor( indexPattern: IndexPattern, @@ -89,7 +89,7 @@ export class LensAttributes { seriesType?: SeriesType, filters?: UrlFilter[], operationType?: OperationType, - reportDefinitions?: Record + reportDefinitions?: URLReportDefinition ) { this.indexPattern = indexPattern; this.layers = {}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts index 5d5cdb23d3520..d7acccbde75e1 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts @@ -19,6 +19,7 @@ export function convertToShortUrl(series: SeriesUrl) { breakdown, filters, reportDefinitions, + dataType, ...restSeries } = series; @@ -29,6 +30,7 @@ export function convertToShortUrl(series: SeriesUrl) { [URL_KEYS.BREAK_DOWN]: breakdown, [URL_KEYS.FILTERS]: filters, [URL_KEYS.REPORT_DEFINITIONS]: reportDefinitions, + [URL_KEYS.DATA_TYPE]: dataType, ...restSeries, }; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index 58ce1e44934e2..595c8e69e834a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -5,7 +5,7 @@ * 2.0. */ import { i18n } from '@kbn/i18n'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { EuiPanel, EuiTitle } from '@elastic/eui'; import styled from 'styled-components'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; @@ -24,6 +24,11 @@ export function ExploratoryView() { services: { lens }, } = useKibana(); + const seriesBuilderRef = useRef(null); + const wrapperRef = useRef(null); + + const [height, setHeight] = useState('100vh'); + const [lensAttributes, setLensAttributes] = useState( null ); @@ -38,6 +43,14 @@ export function ExploratoryView() { seriesId, }); + const setHeightOffset = () => { + if (seriesBuilderRef?.current && wrapperRef.current) { + const headerOffset = wrapperRef.current.getBoundingClientRect().top; + const seriesOffset = seriesBuilderRef.current.getBoundingClientRect().height; + setHeight(`calc(100vh - ${seriesOffset + headerOffset + 32}px)`); + } + }; + useEffect(() => { if (series?.reportType || series?.dataType) { loadIndexPattern({ dataType: series?.dataType ?? ReportToDataTypeMap[series?.reportType] }); @@ -49,22 +62,27 @@ export function ExploratoryView() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(lensAttributesT ?? {}), series?.reportType, series?.time?.from]); + useEffect(() => { + setHeightOffset(); + }); + return ( {lens ? ( <> - {lensAttributes && seriesId && series?.reportType && series?.time ? ( - - ) : ( - - )} - + + {lensAttributes && seriesId && series?.reportType && series?.time ? ( + + ) : ( + + )} + + ) : ( @@ -79,7 +97,14 @@ export function ExploratoryView() { ); } +const LensWrapper = styled.div<{ height: string }>` + min-height: 400px; + height: ${(props) => props.height}; + &&& > div { + height: 100%; + } +`; const Wrapper = styled(EuiPanel)` max-width: 1800px; min-width: 800px; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts index a5fce74c4a2f6..5e356364159db 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts @@ -25,7 +25,7 @@ export const getFiltersFromDefs = ( const rdfFilters = Object.entries(reportDefinitions ?? {}).map(([field, value]) => { return { field, - values: [value], + values: value, }; }) as UrlFilter[]; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts index 34f0a7c1a7f86..2605818ed7846 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts @@ -20,19 +20,21 @@ export const useSeriesFilters = ({ seriesId }: { seriesId: string }) => { const filters = series.filters ?? []; const removeFilter = ({ field, value, negate }: UpdateFilter) => { - const filtersN = filters.map((filter) => { - if (filter.field === field) { - if (negate) { - const notValuesN = filter.notValues?.filter((val) => val !== value); - return { ...filter, notValues: notValuesN }; - } else { - const valuesN = filter.values?.filter((val) => val !== value); - return { ...filter, values: valuesN }; + const filtersN = filters + .map((filter) => { + if (filter.field === field) { + if (negate) { + const notValuesN = filter.notValues?.filter((val) => val !== value); + return { ...filter, notValues: notValuesN }; + } else { + const valuesN = filter.values?.filter((val) => val !== value); + return { ...filter, values: valuesN }; + } } - } - return filter; - }); + return filter; + }) + .filter(({ values = [], notValues = [] }) => values.length > 0 || notValues.length > 0); setSeries(seriesId, { ...series, filters: filtersN }); }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx index 139b7faac4a37..9e2669206695f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx @@ -26,7 +26,7 @@ export function UrlStorageContextProvider({ } function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl { - const { op, st, rt, bd, ft, time, rdf, ...restSeries } = newValue; + const { dt, op, st, rt, bd, ft, time, rdf, ...restSeries } = newValue; return { operationType: op, reportType: rt!, @@ -35,6 +35,7 @@ function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl { filters: ft!, time: time!, reportDefinitions: rdf, + dataType: dt!, ...restSeries, }; } @@ -42,6 +43,7 @@ function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl { interface ShortUrlSeries { [URL_KEYS.OPERATION_TYPE]?: OperationType; [URL_KEYS.REPORT_TYPE]?: ReportViewTypeId; + [URL_KEYS.DATA_TYPE]?: AppDataType; [URL_KEYS.SERIES_TYPE]?: SeriesType; [URL_KEYS.BREAK_DOWN]?: string; [URL_KEYS.FILTERS]?: UrlFilter[]; @@ -50,7 +52,6 @@ interface ShortUrlSeries { to: string; from: string; }; - dataType?: AppDataType; } export type AllShortSeries = Record; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx index 79008d91b294d..2fd28c7f0d4c9 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx @@ -10,7 +10,8 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; import { AppDataType } from '../../types'; import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; -import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_storage'; +import { useUrlStorage } from '../../hooks/use_url_storage'; +import { ReportToDataTypeMap } from '../../configurations/constants'; export const dataTypes: Array<{ id: AppDataType; label: string }> = [ { id: 'synthetics', label: 'Synthetic Monitoring' }, @@ -20,20 +21,20 @@ export const dataTypes: Array<{ id: AppDataType; label: string }> = [ // { id: 'apm', label: 'APM' }, ]; -export function DataTypesCol() { - const { series, setSeries, removeSeries } = useUrlStorage(NEW_SERIES_KEY); +export function DataTypesCol({ seriesId }: { seriesId: string }) { + const { series, setSeries, removeSeries } = useUrlStorage(seriesId); const { loading } = useAppIndexPatternContext(); const onDataTypeChange = (dataType?: AppDataType) => { if (!dataType) { - removeSeries(NEW_SERIES_KEY); + removeSeries(seriesId); } else { - setSeries(NEW_SERIES_KEY, { dataType } as any); + setSeries(seriesId, { dataType } as any); } }; - const selectedDataType = series.dataType; + const selectedDataType = series.dataType ?? ReportToDataTypeMap[series.reportType]; return ( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx index 619e2ec4fe9b0..162892071dbff 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx @@ -7,9 +7,14 @@ import React from 'react'; import { Breakdowns } from '../../series_editor/columns/breakdowns'; -import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; import { DataSeries } from '../../types'; -export function ReportBreakdowns({ dataViewSeries }: { dataViewSeries: DataSeries }) { - return ; +export function ReportBreakdowns({ + seriesId, + dataViewSeries, +}: { + dataViewSeries: DataSeries; + seriesId: string; +}) { + return ; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx index 0351508ebb59e..74be565dafd8b 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -9,16 +9,16 @@ import React from 'react'; import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; -import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_storage'; +import { useUrlStorage } from '../../hooks/use_url_storage'; import { CustomReportField } from '../custom_report_field'; import FieldValueSuggestions from '../../../field_value_suggestions'; -import { DataSeries } from '../../types'; +import { DataSeries, URLReportDefinition } from '../../types'; import { SeriesChartTypesSelect } from './chart_types'; import { OperationTypeSelect } from './operation_type_select'; import { DatePickerCol } from './date_picker_col'; import { parseCustomFieldName } from '../../configurations/lens_attributes'; -function getColumnType(dataView: DataSeries, selectedDefinition: Record) { +function getColumnType(dataView: DataSeries, selectedDefinition: URLReportDefinition) { const { reportDefinitions } = dataView; const customColumn = reportDefinitions.find((item) => item.custom); if (customColumn?.field && selectedDefinition[customColumn?.field]) { @@ -31,10 +31,16 @@ function getColumnType(dataView: DataSeries, selectedDefinition: Record { - if (!value) { + const onChange = (field: string, value?: string[]) => { + if (!value?.[0]) { delete rtd[field]; - setSeries(NEW_SERIES_KEY, { + setSeries(seriesId, { ...series, reportDefinitions: { ...rtd }, }); } else { - setSeries(NEW_SERIES_KEY, { + setSeries(seriesId, { ...series, reportDefinitions: { ...rtd, [field]: value }, }); @@ -64,7 +70,7 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe const onRemove = (field: string) => { delete rtd[field]; - setSeries(NEW_SERIES_KEY, { + setSeries(seriesId, { ...series, reportDefinitions: rtd, }); @@ -75,7 +81,7 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe return ( - + {indexPattern && reportDefinitions.map(({ field, custom, options, defaultValue }) => ( @@ -87,8 +93,8 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe label={labels[field]} sourceField={field} indexPattern={indexPattern} - value={rtd?.[field]} - onChange={(val?: string) => onChange(field, val)} + selectedValue={rtd?.[field]} + onChange={(val?: string[]) => onChange(field, val)} filters={(filters ?? []).map(({ query }) => query)} time={series.time} fullWidth={true} @@ -101,12 +107,12 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe iconSide="right" iconType="cross" color="hollow" - onClick={() => onRemove(field)} + onClick={() => {}} iconOnClick={() => onRemove(field)} iconOnClickAriaLabel={'Click to remove'} onClickAriaLabel={'Click to remove'} > - {rtd?.[field]} + {labels[field]}: {(rtd?.[field] ?? []).join(', ')} )} @@ -116,7 +122,7 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe field={field} options={options} defaultValue={defaultValue} - seriesId={NEW_SERIES_KEY} + seriesId={seriesId} /> )} @@ -124,13 +130,13 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe {(hasOperationType || columnType === 'operation') && ( )} - + ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx index 24b24b76af1f6..9687f1bea4ec9 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx @@ -7,15 +7,20 @@ import React from 'react'; import { SeriesFilter } from '../../series_editor/columns/series_filter'; -import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; import { DataSeries } from '../../types'; -export function ReportFilters({ dataViewSeries }: { dataViewSeries: DataSeries }) { +export function ReportFilters({ + dataViewSeries, + seriesId, +}: { + dataViewSeries: DataSeries; + seriesId: string; +}) { return ( ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx index b8ab1c80009d9..f514fd27d2aa6 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx @@ -11,19 +11,20 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import styled from 'styled-components'; import { ReportViewTypeId, SeriesUrl } from '../../types'; -import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_storage'; +import { useUrlStorage } from '../../hooks/use_url_storage'; import { DEFAULT_TIME } from '../../configurations/constants'; import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; interface Props { + seriesId: string; reportTypes: Array<{ id: ReportViewTypeId; label: string }>; } -export function ReportTypesCol({ reportTypes }: Props) { +export function ReportTypesCol({ seriesId, reportTypes }: Props) { const { series: { reportType: selectedReportType, ...restSeries }, setSeries, - } = useUrlStorage(NEW_SERIES_KEY); + } = useUrlStorage(seriesId); const { loading, hasData, selectedApp } = useAppIndexPatternContext(); @@ -50,12 +51,12 @@ export function ReportTypesCol({ reportTypes }: Props) { isDisabled={loading} onClick={() => { if (reportType === selectedReportType) { - setSeries(NEW_SERIES_KEY, { + setSeries(seriesId, { dataType: restSeries.dataType, time: DEFAULT_TIME, } as SeriesUrl); } else { - setSeries(NEW_SERIES_KEY, { + setSeries(seriesId, { ...restSeries, reportType, reportDefinitions: {}, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx index ba3a06325a429..341959450777a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx @@ -5,10 +5,10 @@ * 2.0. */ -import React from 'react'; +import React, { RefObject } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiBasicTable, EuiSpacer } from '@elastic/eui'; +import { EuiBasicTable } from '@elastic/eui'; import { AppDataType, ReportViewTypeId, ReportViewTypes, SeriesUrl } from '../types'; import { DataTypesCol } from './columns/data_types_col'; import { ReportTypesCol } from './columns/report_types_col'; @@ -45,7 +45,13 @@ export const ReportTypes: Record; +}) { const { series, setSeries, removeSeries } = useUrlStorage(seriesId); const { @@ -75,7 +81,7 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { defaultMessage: 'Data Type', }), width: '15%', - render: (val: string) => , + render: (val: string) => , }, { name: i18n.translate('xpack.observability.expView.seriesBuilder.report', { @@ -83,7 +89,7 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { }), width: '15%', render: (val: string) => ( - + ), }, { @@ -94,9 +100,9 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { render: (val: string) => { if (dataType && hasData) { return loading ? ( - INITIATING_VIEW + LOADING_VIEW ) : reportType ? ( - + ) : ( SELECT_REPORT_TYPE ); @@ -111,7 +117,9 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { }), width: '20%', render: (val: string) => - reportType && indexPattern ? : null, + reportType && indexPattern ? ( + + ) : null, }, { name: i18n.translate('xpack.observability.expView.seriesBuilder.breakdown', { @@ -121,11 +129,13 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { field: 'id', render: (val: string) => reportType && indexPattern ? ( - + ) : null, }, ]; + // TODO: Remove this if remain unused during multiple series view + // @ts-expect-error const addSeries = () => { if (reportType) { const newSeriesId = `${ @@ -135,6 +145,7 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { }`; const newSeriesN: SeriesUrl = { + dataType, time, filters, breakdown, @@ -152,24 +163,21 @@ export function SeriesBuilder({ seriesId }: { seriesId: string }) { const items = [{ id: seriesId }]; - const flyout = ( - <> + return ( +
- - +
); - - return
{flyout}
; } -export const INITIATING_VIEW = i18n.translate( - 'xpack.observability.expView.seriesBuilder.initView', +export const LOADING_VIEW = i18n.translate( + 'xpack.observability.expView.seriesBuilder.loadingView', { - defaultMessage: 'Initiating view ...', + defaultMessage: 'Loading view ...', } ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx index 88cb538263419..fe65911f64e2f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx @@ -19,7 +19,7 @@ import { FilterExpanded } from './filter_expanded'; import { DataSeries } from '../../types'; import { FieldLabels } from '../../configurations/constants/constants'; import { SelectedFilters } from '../selected_filters'; -import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_storage'; +import { useUrlStorage } from '../../hooks/use_url_storage'; interface Props { seriesId: string; @@ -46,13 +46,12 @@ export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: P } return { - label: FieldLabels[field.field], field: field.field, nested: field.nested, isNegated: field.isNegated, + label: FieldLabels[field.field], }; }); - const disabled = seriesId === NEW_SERIES_KEY && !isNew; const { setSeries, series: urlSeries } = useUrlStorage(seriesId); @@ -63,7 +62,6 @@ export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: P onClick={() => { setIsPopoverVisible(true); }} - isDisabled={disabled} size="s" > {i18n.translate('xpack.observability.expView.seriesEditor.addFilter', { @@ -113,7 +111,7 @@ export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: P return ( - {!disabled && } + { setSeries(seriesId, { ...urlSeries, filters: undefined }); }} - isDisabled={disabled} - size="s" + size="xs" > {i18n.translate('xpack.observability.expView.seriesEditor.clearFilter', { defaultMessage: 'Clear filters', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx index 4055a592c75d2..aabb39f88507f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx @@ -7,7 +7,7 @@ import React, { Fragment } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_storage'; +import { useUrlStorage } from '../hooks/use_url_storage'; import { FilterLabel } from '../components/filter_label'; import { DataSeries, UrlFilter } from '../types'; import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; @@ -31,7 +31,7 @@ export function SelectedFilters({ seriesId, isNew, series: dataSeries }: Props) let definitionFilters: UrlFilter[] = getFiltersFromDefs(reportDefinitions, dataSeries); // we don't want to display report definition filters in new series view - if (seriesId === NEW_SERIES_KEY && isNew) { + if (isNew) { definitionFilters = []; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts index 3878c1cde7aa5..b815e7c4b1201 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts @@ -67,6 +67,8 @@ export interface DataSeries { yTitle?: string; } +export type URLReportDefinition = Record; + export interface SeriesUrl { time: { to: string; @@ -77,8 +79,8 @@ export interface SeriesUrl { seriesType?: SeriesType; reportType: ReportViewTypeId; operationType?: OperationType; - dataType?: AppDataType; - reportDefinitions?: Record; + dataType: AppDataType; + reportDefinitions?: URLReportDefinition; } export interface UrlFilter { diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx index ae91e1a439188..809937c2c4b18 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx @@ -31,7 +31,7 @@ export default { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={() => {}} /> @@ -48,7 +48,7 @@ export function ValuesLoaded() { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={() => {}} /> @@ -61,7 +61,7 @@ export function LoadingState() { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={true} setQuery={() => {}} /> @@ -74,7 +74,7 @@ export function EmptyState() { label="Service name" values={[]} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={() => {}} /> @@ -94,7 +94,7 @@ export function SearchState(args: FieldValueSelectionProps) { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={setQuery} /> diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx index d7e075d7fc3f2..a6cb21c523474 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx @@ -16,19 +16,20 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; +import { isEqual } from 'lodash'; import { FieldValueSelectionProps } from './types'; -const formatOptions = (values?: string[], value?: string): EuiSelectableOption[] => { +const formatOptions = (values?: string[], selectedValue?: string[]): EuiSelectableOption[] => { return (values ?? []).map((val) => ({ label: val, - ...(value === val ? { checked: 'on' } : {}), + ...(selectedValue?.includes(val) ? { checked: 'on' } : {}), })); }; export function FieldValueSelection({ fullWidth, label, - value, + selectedValue, loading, values, setQuery, @@ -39,12 +40,14 @@ export function FieldValueSelection({ singleSelection, onChange: onSelectionChange, }: FieldValueSelectionProps) { - const [options, setOptions] = useState(formatOptions(values, value)); + const [options, setOptions] = useState( + formatOptions(values, selectedValue ?? []) + ); const [isPopoverOpen, setIsPopoverOpen] = useState(false); useEffect(() => { - setOptions(formatOptions(values, value)); - }, [values, value]); + setOptions(formatOptions(values, selectedValue)); + }, [values, selectedValue]); const onButtonClick = () => { setIsPopoverOpen(!isPopoverOpen); @@ -77,6 +80,14 @@ export function FieldValueSelection({ ); + const applyDisabled = () => { + const currSelected = (options ?? []) + .filter((opt) => opt?.checked === 'on') + .map(({ label: labelN }) => labelN); + + return isEqual(selectedValue ?? [], currSelected); + }; + return ( opt?.checked === 'on')) - } + isDisabled={applyDisabled()} onClick={() => { - const selected = options.find((opt) => opt?.checked === 'on'); - onSelectionChange(selected?.label); + const selectedValuesN = options.filter((opt) => opt?.checked === 'on'); + onSelectionChange(selectedValuesN.map(({ label: lbl }) => lbl)); setIsPopoverOpen(false); }} > diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx index a3bfd8daac7dc..60c44e175a724 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx @@ -17,7 +17,7 @@ export function FieldValueSuggestions({ sourceField, label, indexPattern, - value, + selectedValue, filters, button, time, @@ -49,7 +49,7 @@ export function FieldValueSuggestions({ onChange={onSelectionChange} setQuery={setDebouncedValue} loading={loading} - value={value} + selectedValue={selectedValue} button={button} forceOpen={forceOpen} anchorPosition={anchorPosition} diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts index c7f8aa4a09514..944a631a6222a 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts @@ -11,7 +11,7 @@ import { ESFilter } from 'typings/elasticsearch'; import { IndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns/index_patterns'; interface CommonProps { - value?: string; + selectedValue?: string[]; label: string; button?: JSX.Element; width?: number; @@ -24,14 +24,14 @@ interface CommonProps { export type FieldValueSuggestionsProps = CommonProps & { indexPattern: IndexPattern; sourceField: string; - onChange: (val?: string) => void; + onChange: (val?: string[]) => void; filters: ESFilter[]; time?: { from: string; to: string }; }; export type FieldValueSelectionProps = CommonProps & { loading?: boolean; - onChange: (val?: string) => void; + onChange: (val?: string[]) => void; values?: string[]; setQuery: Dispatch>; }; diff --git a/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx b/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx index 09273b1a3f95e..b6ac14e114a31 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx @@ -190,6 +190,7 @@ export const PingHistogramComponent: React.FC = ({ const pingHistogramExploratoryViewLink = createExploratoryViewUrl( { 'pings-over-time': { + dataType: 'synthetics', reportType: 'upp', time: { from: dateRangeStart, to: dateRangeEnd }, ...(monitorId ? { filters: [{ field: 'monitor.id', values: [monitorId] }] } : {}), diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx index 677d580b6979a..b629da60bec53 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx @@ -63,6 +63,7 @@ export const MonitorDuration: React.FC = ({ monitorId }) => { }, breakdown: 'observer.geo.name', operationType: 'average', + dataType: 'synthetics', }, }, basePath From c497116f2c52bcb130473bbace148e349d58c0fd Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 23 Apr 2021 16:08:20 +0200 Subject: [PATCH 09/17] fix test --- .../exploratory_view.test.tsx | 25 +------------------ .../exploratory_view/exploratory_view.tsx | 2 +- .../shared/exploratory_view/index.tsx | 18 ++++++------- .../columns/data_types_col.test.tsx | 13 ++++++---- .../columns/report_breakdowns.test.tsx | 14 +++++------ .../columns/report_definition_col.test.tsx | 16 ++++++------ .../columns/report_filters.test.tsx | 7 +++--- .../series_date_picker.test.tsx | 5 ++++ .../field_value_selection.test.tsx | 4 +-- 9 files changed, 44 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx index 375c021bc9b56..b6937f894f941 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx @@ -44,29 +44,6 @@ describe('ExploratoryView', () => { await waitFor(() => { screen.getByText(/open in lens/i); screen.getByRole('heading', { name: /exploratory view/i }); - screen.getByRole('img', { name: /visulization/i }); - screen.getByText(/add series/i); - screen.getByText(/no series found, please add a series\./i); - }); - }); - - it('can add, cancel new series', async () => { - render(); - - await fireEvent.click(screen.getByText(/add series/i)); - - await waitFor(() => { - screen.getByText(/open in lens/i); - }); - - await waitFor(() => { - screen.getByText(/select a data type to start building a series\./i); - }); - - await fireEvent.click(screen.getByText(/cancel/i)); - - await waitFor(() => { - screen.getByText(/add series/i); }); }); @@ -74,6 +51,7 @@ describe('ExploratoryView', () => { mockUrlStorage({ data: { 'uptime-pings-histogram': { + dataType: 'synthetics', reportType: 'upp', breakdown: 'monitor.status', time: { from: 'now-15m', to: 'now' }, @@ -86,7 +64,6 @@ describe('ExploratoryView', () => { await waitFor(() => { screen.getByText(/open in lens/i); screen.getByRole('heading', { name: /uptime pings/i }); - screen.getByText(/uptime-pings-histogram/i); screen.getByText(/Lens Embeddable Component/i); screen.getByRole('table', { name: /this table contains 1 rows\./i }); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx index 595c8e69e834a..44fa4f3c6db85 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -47,7 +47,7 @@ export function ExploratoryView() { if (seriesBuilderRef?.current && wrapperRef.current) { const headerOffset = wrapperRef.current.getBoundingClientRect().top; const seriesOffset = seriesBuilderRef.current.getBoundingClientRect().height; - setHeight(`calc(100vh - ${seriesOffset + headerOffset + 32}px)`); + setHeight(`calc(100vh - ${seriesOffset + headerOffset + 40}px)`); } }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx index 9fe133098549c..4d766ad42c960 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import React, { useContext } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; import { useHistory } from 'react-router-dom'; -import { ThemeContext } from 'styled-components'; import { ExploratoryView } from './exploratory_view'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { useBreadcrumbs } from '../../../hooks/use_breadcrumbs'; import { IndexPatternContextProvider } from './hooks/use_app_index_pattern'; @@ -19,7 +19,6 @@ import { withNotifyOnErrors, } from '../../../../../../../src/plugins/kibana_utils/public/'; import { UrlStorageContextProvider } from './hooks/use_url_storage'; -import { WithHeaderLayout } from '../../app/layout/with_header'; export function ExploratoryViewPage() { useBreadcrumbs([ @@ -30,8 +29,6 @@ export function ExploratoryViewPage() { }, ]); - const theme = useContext(ThemeContext); - const { services: { uiSettings, notifications }, } = useKibana(); @@ -45,15 +42,16 @@ export function ExploratoryViewPage() { }); return ( - + - + ); } + +const Wrapper = euiStyled.div` + padding: ${(props) => props.theme.eui.paddingSizes.l}; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx index cf5d08b4110d7..98863346c5209 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx @@ -10,12 +10,15 @@ import { fireEvent, screen } from '@testing-library/react'; import { mockAppIndexPattern, mockUrlStorage, render } from '../../rtl_helpers'; import { dataTypes, DataTypesCol } from './data_types_col'; import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; +import { ReportDefinitionCol } from './report_definition_col'; describe('DataTypesCol', function () { + const seriesId = 'test-series-id'; + mockAppIndexPattern(); it('should render properly', function () { - const { getByText } = render(); + const { getByText } = render(); dataTypes.forEach(({ label }) => { getByText(label); @@ -25,18 +28,18 @@ describe('DataTypesCol', function () { it('should set series on change', function () { const { setSeries } = mockUrlStorage({}); - render(); + render(); fireEvent.click(screen.getByText(/user experience\(rum\)/i)); expect(setSeries).toHaveBeenCalledTimes(1); - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { dataType: 'ux' }); + expect(setSeries).toHaveBeenCalledWith(seriesId, { dataType: 'ux' }); }); it('should set series on change on already selected', function () { mockUrlStorage({ data: { - [NEW_SERIES_KEY]: { + [seriesId]: { dataType: 'synthetics', reportType: 'upp', breakdown: 'monitor.status', @@ -45,7 +48,7 @@ describe('DataTypesCol', function () { }, }); - render(); + render(); const button = screen.getByRole('button', { name: /Synthetic Monitoring/i, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx index 63cabeabc2ced..22cbcf23b30ad 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx @@ -10,21 +10,21 @@ import { fireEvent, screen } from '@testing-library/react'; import { render } from '../../../../../utils/test_helper'; import { getDefaultConfigs } from '../../configurations/default_configs'; import { mockIndexPattern, mockUrlStorage } from '../../rtl_helpers'; -import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; import { ReportBreakdowns } from './report_breakdowns'; import { USER_AGENT_OS } from '../../configurations/constants/elasticsearch_fieldnames'; describe('Series Builder ReportBreakdowns', function () { + const seriesId = 'test-series-id'; const dataViewSeries = getDefaultConfigs({ + seriesId, reportType: 'pld', indexPattern: mockIndexPattern, - seriesId: NEW_SERIES_KEY, }); it('should render properly', function () { mockUrlStorage({}); - render(); + render(); screen.getByText('Select an option: , is selected'); screen.getAllByText('Browser family'); @@ -33,7 +33,7 @@ describe('Series Builder ReportBreakdowns', function () { it('should set new series breakdown on change', function () { const { setSeries } = mockUrlStorage({}); - render(); + render(); const btn = screen.getByRole('button', { name: /select an option: Browser family , is selected/i, @@ -45,7 +45,7 @@ describe('Series Builder ReportBreakdowns', function () { fireEvent.click(screen.getByText(/operating system/i)); expect(setSeries).toHaveBeenCalledTimes(1); - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { + expect(setSeries).toHaveBeenCalledWith(seriesId, { breakdown: USER_AGENT_OS, reportType: 'pld', time: { from: 'now-15m', to: 'now' }, @@ -54,7 +54,7 @@ describe('Series Builder ReportBreakdowns', function () { it('should set undefined on new series on no select breakdown', function () { const { setSeries } = mockUrlStorage({}); - render(); + render(); const btn = screen.getByRole('button', { name: /select an option: Browser family , is selected/i, @@ -66,7 +66,7 @@ describe('Series Builder ReportBreakdowns', function () { fireEvent.click(screen.getByText(/no breakdown/i)); expect(setSeries).toHaveBeenCalledTimes(1); - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { + expect(setSeries).toHaveBeenCalledWith(seriesId, { breakdown: undefined, reportType: 'pld', time: { from: 'now-15m', to: 'now' }, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx index 91786a2f48fab..8cbed1713a5e0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx @@ -15,17 +15,17 @@ import { mockUseValuesList, render, } from '../../rtl_helpers'; -import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; import { ReportDefinitionCol } from './report_definition_col'; import { SERVICE_NAME } from '../../configurations/constants/elasticsearch_fieldnames'; describe('Series Builder ReportDefinitionCol', function () { mockAppIndexPattern(); + const seriesId = 'test-series-id'; const dataViewSeries = getDefaultConfigs({ + seriesId, reportType: 'pld', indexPattern: mockIndexPattern, - seriesId: NEW_SERIES_KEY, }); const { setSeries } = mockUrlStorage({ @@ -34,13 +34,13 @@ describe('Series Builder ReportDefinitionCol', function () { dataType: 'ux', reportType: 'pld', time: { from: 'now-30d', to: 'now' }, - reportDefinitions: { [SERVICE_NAME]: 'elastic-co' }, + reportDefinitions: { [SERVICE_NAME]: ['elastic-co'] }, }, }, }); it('should render properly', async function () { - render(); + render(); screen.getByText('Web Application'); screen.getByText('Environment'); @@ -49,20 +49,20 @@ describe('Series Builder ReportDefinitionCol', function () { }); it('should render selected report definitions', function () { - render(); + render(); screen.getByText('elastic-co'); }); it('should be able to remove selected definition', function () { - render(); + render(); const removeBtn = screen.getByText(/elastic-co/i); fireEvent.click(removeBtn); expect(setSeries).toHaveBeenCalledTimes(1); - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { + expect(setSeries).toHaveBeenCalledWith(seriesId, { dataType: 'ux', reportDefinitions: {}, reportType: 'pld', @@ -72,7 +72,7 @@ describe('Series Builder ReportDefinitionCol', function () { it('should be able to unselected selected definition', async function () { mockUseValuesList(['elastic-co']); - render(); + render(); const definitionBtn = screen.getByText(/web application/i); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx index 4c9b5827e2bde..1467cb54d648a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx @@ -11,17 +11,18 @@ import { render } from '../../../../../utils/test_helper'; import { ReportFilters } from './report_filters'; import { getDefaultConfigs } from '../../configurations/default_configs'; import { mockIndexPattern, mockUrlStorage } from '../../rtl_helpers'; -import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; describe('Series Builder ReportFilters', function () { + const seriesId = 'test-series-id'; + const dataViewSeries = getDefaultConfigs({ + seriesId, reportType: 'pld', indexPattern: mockIndexPattern, - seriesId: NEW_SERIES_KEY, }); mockUrlStorage({}); it('should render properly', function () { - render(); + render(); screen.getByText('Add filter'); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx index 8fe1d5ed9f2ac..e99b701f091fe 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx @@ -16,6 +16,7 @@ describe('SeriesDatePicker', function () { mockUrlStorage({ data: { 'uptime-pings-histogram': { + dataType: 'synthetics', reportType: 'upp', breakdown: 'monitor.status', time: { from: 'now-30m', to: 'now' }, @@ -32,6 +33,7 @@ describe('SeriesDatePicker', function () { data: { 'uptime-pings-histogram': { reportType: 'upp', + dataType: 'synthetics', breakdown: 'monitor.status', }, }, @@ -40,6 +42,7 @@ describe('SeriesDatePicker', function () { expect(setSeries1).toHaveBeenCalledTimes(1); expect(setSeries1).toHaveBeenCalledWith('uptime-pings-histogram', { breakdown: 'monitor.status', + dataType: 'synthetics', reportType: 'upp', time: DEFAULT_TIME, }); @@ -49,6 +52,7 @@ describe('SeriesDatePicker', function () { const { setSeries } = mockUrlStorage({ data: { 'uptime-pings-histogram': { + dataType: 'synthetics', reportType: 'upp', breakdown: 'monitor.status', time: { from: 'now-30m', to: 'now' }, @@ -69,6 +73,7 @@ describe('SeriesDatePicker', function () { expect(setSeries).toHaveBeenCalledWith('series-id', { breakdown: 'monitor.status', + dataType: 'synthetics', reportType: 'upp', time: { from: 'now/d', to: 'now/d' }, }); diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.test.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.test.tsx index 46f2ce6efa97c..ba898c7dc380f 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.test.tsx @@ -17,7 +17,7 @@ describe('FieldValueSelection', () => { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={() => {}} /> @@ -33,7 +33,7 @@ describe('FieldValueSelection', () => { label="Service name" values={['elastic co frontend', 'apm server', 'opbean python']} onChange={() => {}} - value={''} + selectedValue={[]} loading={false} setQuery={() => {}} /> From 9ad2a3b98e1bbc0b8ac33e456acf22230be144ad Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 23 Apr 2021 16:20:53 +0200 Subject: [PATCH 10/17] fix test --- .../configurations/lens_attributes.test.ts | 2 +- .../columns/report_definition_col.test.tsx | 4 ++-- .../columns/report_definition_col.tsx | 2 -- .../columns/report_types_col.test.tsx | 14 ++++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index 56c20289669f4..68d9afc76d51a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -79,7 +79,7 @@ describe('Lens Attribute', () => { it('should return expected field type for custom field with passed value', function () { lnsAttr = new LensAttributes(mockIndexPattern, reportViewConfig, 'line', [], 'count', { - 'performance.metric': LCP_FIELD, + 'performance.metric': [LCP_FIELD], }); expect(JSON.stringify(lnsAttr.getFieldMeta('performance.metric'))).toEqual( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx index 8cbed1713a5e0..9cc4c371b0134 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx @@ -51,13 +51,13 @@ describe('Series Builder ReportDefinitionCol', function () { it('should render selected report definitions', function () { render(); - screen.getByText('elastic-co'); + screen.getByTitle('Web Application: elastic-co'); }); it('should be able to remove selected definition', function () { render(); - const removeBtn = screen.getByText(/elastic-co/i); + const removeBtn = screen.getByTitle(/Click to remove/i); fireEvent.click(removeBtn); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx index 74be565dafd8b..416cab1776b98 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -107,10 +107,8 @@ export function ReportDefinitionCol({ iconSide="right" iconType="cross" color="hollow" - onClick={() => {}} iconOnClick={() => onRemove(field)} iconOnClickAriaLabel={'Click to remove'} - onClickAriaLabel={'Click to remove'} > {labels[field]}: {(rtd?.[field] ?? []).join(', ')} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx index c5b8f1147af54..007f9e7d8c550 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx @@ -14,26 +14,28 @@ import { DEFAULT_TIME } from '../../configurations/constants'; import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; describe('ReportTypesCol', function () { + const seriesId = 'test-series-id'; + mockAppIndexPattern(); it('should render properly', function () { - render(); + render(); screen.getByText('Performance distribution'); screen.getByText('KPI over time'); }); it('should display empty message', function () { - render(); + render(); screen.getByText(SELECTED_DATA_TYPE_FOR_REPORT); }); it('should set series on change', function () { const { setSeries } = mockUrlStorage({}); - render(); + render(); fireEvent.click(screen.getByText(/monitor duration/i)); - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { + expect(setSeries).toHaveBeenCalledWith(seriesId, { breakdown: 'user_agent.name', reportDefinitions: {}, reportType: 'upd', @@ -54,7 +56,7 @@ describe('ReportTypesCol', function () { }, }); - render(); + render(); const button = screen.getByRole('button', { name: /pings histogram/i, @@ -64,7 +66,7 @@ describe('ReportTypesCol', function () { fireEvent.click(button); // undefined on click selected - expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { + expect(setSeries).toHaveBeenCalledWith(seriesId, { dataType: 'synthetics', time: DEFAULT_TIME, }); From 4eb28a74fe99ce4e9abf09bbbce278953f54b64b Mon Sep 17 00:00:00 2001 From: Shahzad Date: Sat, 24 Apr 2021 00:06:50 +0200 Subject: [PATCH 11/17] wip --- .../shared/exploratory_view/components/empty_view.tsx | 7 ++++++- .../shared/exploratory_view/hooks/use_url_storage.tsx | 10 ++++++++-- .../series_editor/columns/filter_value_btn.tsx | 6 ++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx index b54f6f6db00ff..1f444f3747042 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui'; import styled from 'styled-components'; +import { i18n } from '@kbn/i18n'; import { LOADING_VIEW } from '../series_builder/series_builder'; export function EmptyView({ loading, height }: { loading: boolean; height: string }) { @@ -26,7 +27,7 @@ export function EmptyView({ loading, height }: { loading: boolean; height: strin - {LOADING_VIEW} + {loading ? LOADING_VIEW : EMPTY_LABEL}
@@ -42,3 +43,7 @@ const Wrapper = styled.div<{ height: string }>` const FlexGroup = styled(EuiFlexGroup)` height: 100%; `; + +export const EMPTY_LABEL = i18n.translate('xpack.observability.expView.seriesBuilder.emptyview', { + defaultMessage: 'Nothing to display.', +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx index 9e2669206695f..498886cc94410 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_storage.tsx @@ -7,7 +7,13 @@ import React, { createContext, useContext, Context } from 'react'; import { IKbnUrlStateStorage } from '../../../../../../../../src/plugins/kibana_utils/public'; -import type { AppDataType, ReportViewTypeId, SeriesUrl, UrlFilter } from '../types'; +import type { + AppDataType, + ReportViewTypeId, + SeriesUrl, + UrlFilter, + URLReportDefinition, +} from '../types'; import { convertToShortUrl } from '../configurations/utils'; import { OperationType, SeriesType } from '../../../../../../lens/public'; import { URL_KEYS } from '../configurations/constants/url_constants'; @@ -47,7 +53,7 @@ interface ShortUrlSeries { [URL_KEYS.SERIES_TYPE]?: SeriesType; [URL_KEYS.BREAK_DOWN]?: string; [URL_KEYS.FILTERS]?: UrlFilter[]; - [URL_KEYS.REPORT_DEFINITIONS]?: Record; + [URL_KEYS.REPORT_DEFINITIONS]?: URLReportDefinition; time?: { to: string; from: string; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx index 849fb8ffa66ba..ccb9c90a884bb 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx @@ -71,8 +71,10 @@ export function FilterValueButton({ ); - const onNestedChange = (val?: string) => { - setFilter({ field: nestedField!, value: val! }); + const onNestedChange = (valuesN?: string[]) => { + (valuesN ?? []).forEach((valN) => { + setFilter({ field: nestedField!, value: valN! }); + }); setIsNestedOpen({ value: '', negate }); }; From 6dcd4c1202f5581ba6d773c397d08fd33e49d3c9 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Sun, 25 Apr 2021 02:57:30 +0200 Subject: [PATCH 12/17] core web vitals --- .../PageLoadDistribution/index.tsx | 3 +- x-pack/plugins/lens/public/index.ts | 1 + .../configurations/constants/constants.ts | 3 + .../constants/elasticsearch_fieldnames.ts | 1 + .../configurations/default_configs.ts | 3 + .../configurations/lens_attributes.ts | 80 ++++++--- .../rum/core_web_vitals_config.ts | 156 ++++++++++++++++++ .../hooks/use_lens_attributes.ts | 3 +- .../series_builder/columns/chart_types.tsx | 14 +- .../series_builder/columns/data_types_col.tsx | 2 +- .../columns/report_breakdowns.tsx | 8 +- .../columns/report_definition_col.tsx | 19 ++- .../series_builder/custom_report_field.tsx | 11 +- .../series_builder/series_builder.tsx | 1 + .../series_editor/columns/breakdowns.tsx | 33 ++-- .../shared/exploratory_view/types.ts | 15 +- 16 files changed, 300 insertions(+), 53 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index b2e8ca5fda805..37285fc6240c2 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -88,10 +88,11 @@ export function PageLoadDistribution() { const exploratoryViewLink = createExploratoryViewUrl( { [`${serviceName}-page-views`]: { + dataType: 'ux', reportType: 'pld', time: { from: rangeFrom!, to: rangeTo! }, reportDefinitions: { - 'service.name': serviceName?.[0] as string, + 'service.name': serviceName!, }, ...(breakdown ? { breakdown: breakdown.fieldName } : {}), }, diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index fcfed9b9f1fc5..0fdd3bf426232 100644 --- a/x-pack/plugins/lens/public/index.ts +++ b/x-pack/plugins/lens/public/index.ts @@ -20,6 +20,7 @@ export type { ValueLabelConfig, YAxisMode, XYCurveType, + YConfig, } from './xy_visualization/types'; export type { DataType, OperationMetadata } from './types'; export type { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index 0e1e1681373cb..9fd343aab4bc7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -68,3 +68,6 @@ export const ReportToDataTypeMap: Record = { logs: 'infra_logs', cpu: 'infra_metrics', }; + +export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN'; +export const FILTER_RECORDS = 'FILTER_RECORDS'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/elasticsearch_fieldnames.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/elasticsearch_fieldnames.ts index 3faf54fff3140..5ecc5b758de84 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/elasticsearch_fieldnames.ts @@ -119,6 +119,7 @@ export const TRANSACTION_URL = 'url.full'; export const CLIENT_GEO = 'client.geo'; export const USER_AGENT_DEVICE = 'user_agent.device.name'; export const USER_AGENT_OS = 'user_agent.os.name'; +export const USER_AGENT_OS_VERSION = 'user_agent.os.version'; export const TRANSACTION_TIME_TO_FIRST_BYTE = 'transaction.marks.agent.timeToFirstByte'; export const TRANSACTION_DOM_INTERACTIVE = 'transaction.marks.agent.domInteractive'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts index f9637dc653d2c..66420f2e81150 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts @@ -17,6 +17,7 @@ import { getMemoryUsageLensConfig } from './metrics/memory_usage_config'; import { getNetworkActivityLensConfig } from './metrics/network_activity_config'; import { getLogsFrequencyLensConfig } from './logs/logs_frequency_config'; import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns'; +import { getCoreWebVitalsConfig } from './rum/core_web_vitals_config'; interface Props { reportType: keyof typeof ReportViewTypes; @@ -30,6 +31,8 @@ export const getDefaultConfigs = ({ reportType, seriesId, indexPattern }: Props) return getPerformanceDistLensConfig({ seriesId, indexPattern }); case 'kpi-trends': return getKPITrendsLensConfig({ seriesId, indexPattern }); + case 'core-web-vitals': + return getCoreWebVitalsConfig({ seriesId, indexPattern }); case 'uptime-duration': return getMonitorDurationConfig({ seriesId }); case 'uptime-pings': diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index 3e22c4da6115a..89fc9ca5fcc58 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -24,14 +24,15 @@ import { OperationMetadata, FieldBasedIndexPatternColumn, SumIndexPatternColumn, + TermsIndexPatternColumn, } from '../../../../../../lens/public'; import { buildPhraseFilter, buildPhrasesFilter, IndexPattern, } from '../../../../../../../../src/plugins/data/common'; -import { FieldLabels } from './constants'; -import { DataSeries, UrlFilter, URLReportDefinition } from '../types'; +import { FieldLabels, FILTER_RECORDS, USE_BREAK_DOWN_COLUMN } from './constants'; +import { ColumnFilter, DataSeries, UrlFilter, URLReportDefinition } from '../types'; function getLayerReferenceName(layerId: string) { return `indexpattern-datasource-layer-${layerId}`; @@ -53,6 +54,7 @@ export const parseCustomFieldName = ( ) => { let fieldName = sourceField; let columnType; + let columnFilters; const rdf = reportViewConfig.reportDefinitions ?? []; @@ -61,17 +63,21 @@ export const parseCustomFieldName = ( if (customField) { if (selectedDefinitions[fieldName]) { fieldName = selectedDefinitions[fieldName][0]; - if (customField?.options) - columnType = customField?.options?.find(({ field }) => field === fieldName)?.columnType; - } else if (customField.defaultValue) { - fieldName = customField.defaultValue; - } else if (customField.options?.[0].field) { - fieldName = customField.options?.[0].field; + if (customField?.options) { + const currField = customField?.options?.find( + ({ field, id }) => field === fieldName || id === fieldName + ); + columnType = currField?.columnType; + columnFilters = currField?.columnFilters; + } + } else if (customField.options?.[0].field || customField.options?.[0].id) { + fieldName = customField.options?.[0].field || customField.options?.[0].id; columnType = customField.options?.[0].columnType; + columnFilters = customField.options?.[0].columnFilters; } } - return { fieldName, columnType }; + return { fieldName, columnType, columnFilters }; }; export class LensAttributes { @@ -82,6 +88,7 @@ export class LensAttributes { seriesType: SeriesType; reportViewConfig: DataSeries; reportDefinitions: URLReportDefinition; + breakdownSource?: string; constructor( indexPattern: IndexPattern, @@ -89,12 +96,14 @@ export class LensAttributes { seriesType?: SeriesType, filters?: UrlFilter[], operationType?: OperationType, - reportDefinitions?: URLReportDefinition + reportDefinitions?: URLReportDefinition, + breakdownSource?: string ) { this.indexPattern = indexPattern; this.layers = {}; this.filters = filters ?? []; this.reportDefinitions = reportDefinitions ?? {}; + this.breakdownSource = breakdownSource; if (operationType) { reportViewConfig.yAxisColumns.forEach((yAxisColumn) => { @@ -109,10 +118,10 @@ export class LensAttributes { this.visualization = this.getXyState(); } - addBreakdown(sourceField: string) { + getBreakdownColumn(sourceField: string): TermsIndexPatternColumn { const fieldMeta = this.indexPattern.getFieldByName(sourceField); - this.layers.layer1.columns['break-down-column'] = { + return { sourceField, label: `Top values of ${FieldLabels[sourceField]}`, dataType: fieldMeta?.type as DataType, @@ -120,13 +129,22 @@ export class LensAttributes { scale: 'ordinal', isBucketed: true, params: { - size: 3, + size: 10, orderBy: { type: 'column', columnId: 'y-axis-column' }, orderDirection: 'desc', otherBucket: true, missingBucket: false, }, }; + } + + addBreakdown(sourceField: string) { + const { xAxisColumn } = this.reportViewConfig; + if (xAxisColumn?.sourceField === USE_BREAK_DOWN_COLUMN) { + // do nothing since this will be used a x axis source + return; + } + this.layers.layer1.columns['break-down-column'] = this.getBreakdownColumn(sourceField); this.layers.layer1.columnOrder = [ 'x-axis-column', @@ -229,15 +247,27 @@ export class LensAttributes { getXAxis() { const { xAxisColumn } = this.reportViewConfig; + if (xAxisColumn?.sourceField === USE_BREAK_DOWN_COLUMN) { + return this.getBreakdownColumn(this.breakdownSource || this.reportViewConfig.breakdowns[0]); + } + return this.getColumnBasedOnType(xAxisColumn.sourceField!, undefined, xAxisColumn.label); } - getColumnBasedOnType(sourceField: string, operationType?: OperationType, label?: string) { - const { fieldMeta, columnType, fieldName } = this.getFieldMeta(sourceField); + getColumnBasedOnType( + sourceField: string, + operationType?: OperationType, + label?: string, + colIndex?: number + ) { + const { fieldMeta, columnType, fieldName, columnFilters } = this.getFieldMeta(sourceField); const { type: fieldType } = fieldMeta ?? {}; - if (fieldName === 'Records') { - return this.getRecordsColumn(); + if (fieldName === 'Records' || columnType === FILTER_RECORDS) { + return this.getRecordsColumn( + label, + colIndex !== undefined ? columnFilters?.[colIndex] : undefined + ); } if (fieldType === 'date') { @@ -256,11 +286,11 @@ export class LensAttributes { } getFieldMeta(sourceField: string) { - const { fieldName, columnType } = this.getCustomFieldName(sourceField); + const { fieldName, columnType, columnFilters } = this.getCustomFieldName(sourceField); const fieldMeta = this.indexPattern.getFieldByName(fieldName); - return { fieldMeta, fieldName, columnType }; + return { fieldMeta, fieldName, columnType, columnFilters }; } getMainYAxis() { @@ -270,7 +300,7 @@ export class LensAttributes { return this.getRecordsColumn(label); } - return this.getColumnBasedOnType(sourceField!, operationType, label); + return this.getColumnBasedOnType(sourceField!, operationType, label, 0); } getChildYAxises() { @@ -286,13 +316,14 @@ export class LensAttributes { lensColumns[`y-axis-column-${i}`] = this.getColumnBasedOnType( sourceField!, operationType, - label + label, + i ); } return lensColumns; } - getRecordsColumn(label?: string): CountIndexPatternColumn { + getRecordsColumn(label?: string, columnFilter?: ColumnFilter): CountIndexPatternColumn { return { dataType: 'number', isBucketed: false, @@ -300,6 +331,7 @@ export class LensAttributes { operationType: 'count', scale: 'ratio', sourceField: 'Records', + filter: columnFilter, } as CountIndexPatternColumn; } @@ -331,7 +363,9 @@ export class LensAttributes { layerId: 'layer1', seriesType: this.seriesType ?? 'line', palette: this.reportViewConfig.palette, - yConfig: [{ forAccessor: 'y-axis-column', color: 'green' }], + yConfig: this.reportViewConfig.yConfig || [ + { forAccessor: 'y-axis-column', color: 'green' }, + ], xAccessor: 'x-axis-column', }, ], diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts new file mode 100644 index 0000000000000..96cf2fc69bf00 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { euiPaletteForStatus } from '@elastic/eui'; +import { ConfigProps, DataSeries } from '../../types'; +import { FieldLabels, FILTER_RECORDS, USE_BREAK_DOWN_COLUMN } from '../constants'; +import { buildPhraseFilter } from '../utils'; +import { + CLIENT_GEO_COUNTRY_NAME, + CLS_FIELD, + FID_FIELD, + LCP_FIELD, + PROCESSOR_EVENT, + SERVICE_NAME, + TRANSACTION_TYPE, + USER_AGENT_DEVICE, + USER_AGENT_NAME, + USER_AGENT_OS, + USER_AGENT_VERSION, + TRANSACTION_URL, + USER_AGENT_OS_VERSION, + URL_FULL, +} from '../constants/elasticsearch_fieldnames'; + +export function getCoreWebVitalsConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { + const statusPallete = euiPaletteForStatus(3); + + return { + id: seriesId, + defaultSeriesType: 'bar_horizontal_percentage_stacked', + reportType: 'kpi-trends', + seriesTypes: ['bar_horizontal_percentage_stacked'], + xAxisColumn: { + sourceField: USE_BREAK_DOWN_COLUMN, + }, + yAxisColumns: [ + { + sourceField: 'core.web.vitals', + label: 'Good', + }, + { + sourceField: 'core.web.vitals', + label: 'Average', + }, + { + sourceField: 'core.web.vitals', + label: 'Poor', + }, + ], + hasOperationType: false, + defaultFilters: [ + { + field: TRANSACTION_URL, + isNegated: false, + }, + SERVICE_NAME, + { + field: USER_AGENT_OS, + nested: USER_AGENT_OS_VERSION, + }, + CLIENT_GEO_COUNTRY_NAME, + USER_AGENT_DEVICE, + { + field: USER_AGENT_NAME, + nested: USER_AGENT_VERSION, + }, + ], + breakdowns: [ + SERVICE_NAME, + USER_AGENT_NAME, + USER_AGENT_OS, + CLIENT_GEO_COUNTRY_NAME, + USER_AGENT_DEVICE, + URL_FULL, + ], + filters: [ + ...buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern), + ...buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern), + ], + labels: { ...FieldLabels, [SERVICE_NAME]: 'Web Application' }, + reportDefinitions: [ + { + field: 'core.web.vitals', + custom: true, + options: [ + { + id: LCP_FIELD, + label: 'Largest contentful paint', + columnType: FILTER_RECORDS, + columnFilters: [ + { + language: 'kuery', + query: `${LCP_FIELD} < 2500`, + }, + { + language: 'kuery', + query: `${LCP_FIELD} > 2500 and ${LCP_FIELD} < 4000`, + }, + { + language: 'kuery', + query: `${LCP_FIELD} > 4000`, + }, + ], + }, + { + label: 'First input delay', + id: FID_FIELD, + columnType: FILTER_RECORDS, + columnFilters: [ + { + language: 'kuery', + query: `${FID_FIELD} < 100`, + }, + { + language: 'kuery', + query: `${FID_FIELD} > 100 and ${FID_FIELD} < 300`, + }, + { + language: 'kuery', + query: `${FID_FIELD} > 300`, + }, + ], + }, + { + label: 'Cumulative layout shift', + id: CLS_FIELD, + columnType: FILTER_RECORDS, + columnFilters: [ + { + language: 'kuery', + query: `${CLS_FIELD} < 0.1`, + }, + { + language: 'kuery', + query: `${CLS_FIELD} > 0.1 and ${CLS_FIELD} < 0.25`, + }, + { + language: 'kuery', + query: `${CLS_FIELD} > 0.25`, + }, + ], + }, + ], + }, + ], + yConfig: [ + { color: statusPallete[0], forAccessor: 'y-axis-column' }, + { color: statusPallete[1], forAccessor: 'y-axis-column-1' }, + { color: statusPallete[2], forAccessor: 'y-axis-column-2' }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts index 5e356364159db..28a4712c30490 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts @@ -66,7 +66,8 @@ export const useLensAttributes = ({ seriesType, filters, operationType, - reportDefinitions + reportDefinitions, + breakdown ); if (breakdown) { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/chart_types.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/chart_types.tsx index df5b57124f0e7..50750ae924bd2 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/chart_types.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/chart_types.tsx @@ -16,9 +16,11 @@ import { SeriesType } from '../../../../../../../lens/public'; export function SeriesChartTypesSelect({ seriesId, + seriesTypes, defaultChartType, }: { seriesId: string; + seriesTypes?: SeriesType[]; defaultChartType: SeriesType; }) { const { series, setSeries, allSeries } = useUrlStorage(seriesId); @@ -41,7 +43,17 @@ export function SeriesChartTypesSelect({ label={i18n.translate('xpack.observability.expView.chartTypes.label', { defaultMessage: 'Chart type', })} - includeChartTypes={['bar', 'bar_horizontal', 'line', 'area', 'bar_stacked', 'area_stacked']} + includeChartTypes={ + seriesTypes || [ + 'bar', + 'bar_horizontal', + 'line', + 'area', + 'bar_stacked', + 'area_stacked', + 'bar_horizontal_percentage_stacked', + ] + } /> ); } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx index 2fd28c7f0d4c9..c0d17010f4e80 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx @@ -30,7 +30,7 @@ export function DataTypesCol({ seriesId }: { seriesId: string }) { if (!dataType) { removeSeries(seriesId); } else { - setSeries(seriesId, { dataType } as any); + setSeries(seriesId || dataType, { dataType } as any); } }; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx index 162892071dbff..e95cd894df5f2 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx @@ -16,5 +16,11 @@ export function ReportBreakdowns({ dataViewSeries: DataSeries; seriesId: string; }) { - return ; + return ( + + ); } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx index 416cab1776b98..7b7460ec2e097 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; import styled from 'styled-components'; import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; import { useUrlStorage } from '../../hooks/use_url_storage'; @@ -29,7 +29,7 @@ function getColumnType(dataView: DataSeries, selectedDefinition: URLReportDefini return null; } -const MaxWidthStyle = { maxWidth: 250 }; +export const ReportMaxWidthStyle = { maxWidth: 290 }; export function ReportDefinitionCol({ dataViewSeries, @@ -83,8 +83,9 @@ export function ReportDefinitionCol({ + {indexPattern && - reportDefinitions.map(({ field, custom, options, defaultValue }) => ( + reportDefinitions.map(({ field, custom, options }) => ( {!custom ? ( @@ -119,22 +120,26 @@ export function ReportDefinitionCol({ )} ))} {(hasOperationType || columnType === 'operation') && ( - + )} - - + + ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx index b630ee55b5780..1e7599efd8f3e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { EuiSuperSelect } from '@elastic/eui'; import { useUrlStorage } from '../hooks/use_url_storage'; import { ReportDefinition } from '../types'; +import { ReportMaxWidthStyle } from './columns/report_definition_col'; interface Props { field: string; @@ -23,7 +24,7 @@ export function CustomReportField({ field, seriesId, options: opts, defaultValue const { reportDefinitions: rtd = {} } = series; const onChange = (value: string) => { - setSeries(seriesId, { ...series, reportDefinitions: { ...rtd, [field]: value } }); + setSeries(seriesId, { ...series, reportDefinitions: { ...rtd, [field]: [value] } }); }; const { reportDefinitions } = series; @@ -31,15 +32,15 @@ export function CustomReportField({ field, seriesId, options: opts, defaultValue const options = opts ?? []; return ( -
+
({ - value: fd, + options={options.map(({ label, field: fd, id, description }) => ({ + value: fd || id, inputDisplay: label, }))} - valueOfSelected={reportDefinitions?.[field] || defaultValue || options?.[0].field} + valueOfSelected={reportDefinitions?.[field]?.[0] || defaultValue || options?.[0].field} onChange={(value) => onChange(value)} />
diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx index 341959450777a..15e5366b5021f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx @@ -27,6 +27,7 @@ export const ReportTypes: Record ({ id: breakdown, label: FieldLabels[breakdown] })); - items.push({ - id: NO_BREAKDOWN, - label: i18n.translate('xpack.observability.exp.breakDownFilter.noBreakdown', { - defaultMessage: 'No breakdown', - }), - }); + const hasUseBreakdownColumn = reportViewConfig.xAxisColumn.sourceField === USE_BREAK_DOWN_COLUMN; + + const items = breakdowns.map((breakdown) => ({ + id: breakdown, + label: reportViewConfig.labels[breakdown], + })); + + if (!hasUseBreakdownColumn) { + items.push({ + id: NO_BREAKDOWN, + label: i18n.translate('xpack.observability.exp.breakDownFilter.noBreakdown', { + defaultMessage: 'No breakdown', + }), + }); + } const options = items.map(({ id, label }) => ({ inputDisplay: id === NO_BREAKDOWN ? label : {label}, @@ -50,13 +60,16 @@ export function Breakdowns({ seriesId, breakdowns = [] }: Props) { dropdownDisplay: label, })); + const valueOfSelected = + selectedBreakdown || (hasUseBreakdownColumn ? options[0].value : NO_BREAKDOWN); + return (
onOptionChange(value)} data-test-subj={'seriesBreakdown'} /> diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts index b815e7c4b1201..2526233496994 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts @@ -12,6 +12,7 @@ import { FieldBasedIndexPatternColumn, SeriesType, OperationType, + YConfig, } from '../../../../../lens/public'; import { PersistableFilter } from '../../../../../lens/common'; @@ -20,6 +21,7 @@ import { IIndexPattern } from '../../../../../../../src/plugins/data/common/inde export const ReportViewTypes = { pld: 'page-load-dist', kpi: 'kpi-trends', + cwv: 'core-web-vitals', upd: 'uptime-duration', upp: 'uptime-pings', svl: 'service-latency', @@ -36,16 +38,22 @@ export type ReportViewTypeId = keyof typeof ReportViewTypes; export type ReportViewType = ValueOf; +export interface ColumnFilter { + language: 'kuery'; + query: string; +} + export interface ReportDefinition { field: string; required?: boolean; custom?: boolean; - defaultValue?: string; options?: Array<{ - field: string; + id: string; + field?: string; label: string; description?: string; - columnType?: 'range' | 'operation'; + columnType?: 'range' | 'operation' | 'FILTER_RECORDS'; + columnFilters?: ColumnFilter[]; }>; } @@ -65,6 +73,7 @@ export interface DataSeries { hasOperationType: boolean; palette?: PaletteOutput; yTitle?: string; + yConfig?: YConfig[]; } export type URLReportDefinition = Record; From fc6a5531b43aae40c6be52ab597fae5bf016f917 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 19 May 2021 12:27:12 +0200 Subject: [PATCH 13/17] fix issues --- .../configurations/rum/core_web_vitals_config.ts | 8 ++++++++ .../series_builder/columns/report_definition_col.tsx | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts index 96cf2fc69bf00..de9ea12be20cf 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts @@ -24,6 +24,7 @@ import { TRANSACTION_URL, USER_AGENT_OS_VERSION, URL_FULL, + SERVICE_ENVIRONMENT, } from '../constants/elasticsearch_fieldnames'; export function getCoreWebVitalsConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { @@ -83,6 +84,13 @@ export function getCoreWebVitalsConfig({ seriesId, indexPattern }: ConfigProps): ], labels: { ...FieldLabels, [SERVICE_NAME]: 'Web Application' }, reportDefinitions: [ + { + field: SERVICE_NAME, + required: true, + }, + { + field: SERVICE_ENVIRONMENT, + }, { field: 'core.web.vitals', custom: true, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx index 44fe07a4fd563..43be687760fa4 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -6,12 +6,11 @@ */ import React from 'react'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; import styled from 'styled-components'; import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; import { useUrlStorage } from '../../hooks/use_url_storage'; import { CustomReportField } from '../custom_report_field'; -import FieldValueSuggestions from '../../../field_value_suggestions'; import { DataSeries, URLReportDefinition } from '../../types'; import { SeriesChartTypesSelect } from './chart_types'; import { OperationTypeSelect } from './operation_type_select'; @@ -69,7 +68,7 @@ export function ReportDefinitionCol({ {indexPattern && - reportDefinitions.map(({ field, custom, options }) => ( + reportDefinitions.map(({ field, custom, options, defaultValue }) => ( {!custom ? ( )} - + ); From 0fbfb757338cee15b7c56001b8e20890d9b13e32 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 19 May 2021 13:03:45 +0200 Subject: [PATCH 14/17] fix test --- .../configurations/lens_attributes.test.ts | 2 +- .../series_editor/columns/breakdowns.test.tsx | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index a5fdd4971a86f..6976b55921b09 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -342,7 +342,7 @@ describe('Lens Attribute', () => { orderBy: { columnId: 'y-axis-column', type: 'column' }, orderDirection: 'desc', otherBucket: true, - size: 3, + size: 10, }, scale: 'ordinal', sourceField: 'user_agent.name', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx index eff62a60509e3..9d26ec79c31ad 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx @@ -23,7 +23,13 @@ describe('Breakdowns', function () { it('should render properly', async function () { mockUrlStorage({}); - render(); + render( + + ); screen.getAllByText('Browser family'); }); @@ -31,7 +37,13 @@ describe('Breakdowns', function () { it('should call set series on change', function () { const { setSeries } = mockUrlStorage({ breakdown: USER_AGENT_OS }); - render(); + render( + + ); screen.getAllByText('Operating system'); From 48cce605face1df66d5e0cc79b1792031d58b109 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 19 May 2021 13:20:44 +0200 Subject: [PATCH 15/17] fix types --- .../configurations/constants/constants.ts | 1 + .../configurations/rum/kpi_trends_config.ts | 25 +++++++++++-------- .../rum/performance_dist_config.ts | 19 ++++++++------ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index e49f2b2ddf33c..7c80bf4e7afb6 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -109,3 +109,4 @@ export const ReportToDataTypeMap: Record = { export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN'; export const FILTER_RECORDS = 'FILTER_RECORDS'; +export const OPERATION_COLUMN = 'operation'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_trends_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_trends_config.ts index 029fe5534965e..5e2d3440526b5 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_trends_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_trends_config.ts @@ -6,7 +6,7 @@ */ import { ConfigProps, DataSeries } from '../../types'; -import { FieldLabels, RECORDS_FIELD } from '../constants'; +import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD } from '../constants'; import { buildPhraseFilter } from '../utils'; import { CLIENT_GEO_COUNTRY_NAME, @@ -85,20 +85,25 @@ export function getKPITrendsLensConfig({ seriesId, indexPattern }: ConfigProps): { field: 'business.kpi', custom: true, - defaultValue: RECORDS_FIELD, options: [ - { field: RECORDS_FIELD, label: PAGE_VIEWS_LABEL }, - { label: PAGE_LOAD_TIME_LABEL, field: TRANSACTION_DURATION, columnType: 'operation' }, + { field: RECORDS_FIELD, id: RECORDS_FIELD, label: PAGE_VIEWS_LABEL }, + { + label: PAGE_LOAD_TIME_LABEL, + field: TRANSACTION_DURATION, + id: TRANSACTION_DURATION, + columnType: OPERATION_COLUMN, + }, { label: BACKEND_TIME_LABEL, field: TRANSACTION_TIME_TO_FIRST_BYTE, - columnType: 'operation', + id: TRANSACTION_TIME_TO_FIRST_BYTE, + columnType: OPERATION_COLUMN, }, - { label: FCP_LABEL, field: FCP_FIELD, columnType: 'operation' }, - { label: TBT_LABEL, field: TBT_FIELD, columnType: 'operation' }, - { label: LCP_LABEL, field: LCP_FIELD, columnType: 'operation' }, - { label: FID_LABEL, field: FID_FIELD, columnType: 'operation' }, - { label: CLS_LABEL, field: CLS_FIELD, columnType: 'operation' }, + { label: FCP_LABEL, field: FCP_FIELD, id: FCP_FIELD, columnType: OPERATION_COLUMN }, + { label: TBT_LABEL, field: TBT_FIELD, id: TBT_FIELD, columnType: OPERATION_COLUMN }, + { label: LCP_LABEL, field: LCP_FIELD, id: LCP_FIELD, columnType: OPERATION_COLUMN }, + { label: FID_LABEL, field: FID_FIELD, id: FID_FIELD, columnType: OPERATION_COLUMN }, + { label: CLS_LABEL, field: CLS_FIELD, id: CLS_FIELD, columnType: OPERATION_COLUMN }, ], }, ], diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/performance_dist_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/performance_dist_config.ts index af8bd00a69553..0dc582c5683dd 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/performance_dist_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/performance_dist_config.ts @@ -80,15 +80,18 @@ export function getPerformanceDistLensConfig({ seriesId, indexPattern }: ConfigP { field: 'performance.metric', custom: true, - defaultValue: TRANSACTION_DURATION, options: [ - { label: PAGE_LOAD_TIME_LABEL, field: TRANSACTION_DURATION }, - { label: BACKEND_TIME_LABEL, field: TRANSACTION_TIME_TO_FIRST_BYTE }, - { label: FCP_LABEL, field: FCP_FIELD }, - { label: TBT_LABEL, field: TBT_FIELD }, - { label: LCP_LABEL, field: LCP_FIELD }, - { label: FID_LABEL, field: FID_FIELD }, - { label: CLS_LABEL, field: CLS_FIELD }, + { label: PAGE_LOAD_TIME_LABEL, id: TRANSACTION_DURATION, field: TRANSACTION_DURATION }, + { + label: BACKEND_TIME_LABEL, + id: TRANSACTION_TIME_TO_FIRST_BYTE, + field: TRANSACTION_TIME_TO_FIRST_BYTE, + }, + { label: FCP_LABEL, id: FCP_FIELD, field: FCP_FIELD }, + { label: TBT_LABEL, id: TBT_FIELD, field: TBT_FIELD }, + { label: LCP_LABEL, id: LCP_FIELD, field: LCP_FIELD }, + { label: FID_LABEL, id: FID_FIELD, field: FID_FIELD }, + { label: CLS_LABEL, id: CLS_FIELD, field: CLS_FIELD }, ], }, ], From 42991e87a536c96ab98afec177a4f297a523f6ad Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 25 May 2021 15:13:49 +0200 Subject: [PATCH 16/17] fix types --- .../configurations/constants/constants.ts | 3 +++ .../exploratory_view/configurations/constants/labels.ts | 8 ++++++++ .../series_builder/columns/report_definition_col.tsx | 9 ++------- .../series_builder/custom_report_field.tsx | 4 ++-- .../series_editor/chart_edit_options.tsx | 2 +- .../series_editor/columns/breakdowns.tsx | 2 +- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index 7c80bf4e7afb6..e1142a071aab5 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -12,6 +12,7 @@ import { BROWSER_FAMILY_LABEL, BROWSER_VERSION_LABEL, CLS_LABEL, + CORE_WEB_VITALS_LABEL, CPU_USAGE_LABEL, DEVICE_LABEL, ENVIRONMENT_LABEL, @@ -92,6 +93,7 @@ export const DataViewLabels: Record = { logs: LOGS_FREQUENCY_LABEL, mem: MEMORY_USAGE_LABEL, nwk: NETWORK_ACTIVITY_LABEL, + cwv: CORE_WEB_VITALS_LABEL, }; export const ReportToDataTypeMap: Record = { @@ -105,6 +107,7 @@ export const ReportToDataTypeMap: Record = { mem: 'infra_metrics', logs: 'infra_logs', cpu: 'infra_metrics', + cwv: 'ux', }; export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts index ba820a25f868a..92150a76319f8 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts @@ -200,6 +200,14 @@ export const NETWORK_ACTIVITY_LABEL = i18n.translate( defaultMessage: 'Network activity', } ); + +export const CORE_WEB_VITALS_LABEL = i18n.translate( + 'xpack.observability.expView.fieldLabels.coreWebVitals', + { + defaultMessage: 'Core web vitals', + } +); + export const MEMORY_USAGE_LABEL = i18n.translate( 'xpack.observability.expView.fieldLabels.memoryUsage', { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx index 43be687760fa4..ff8b0f7aa578b 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -68,7 +68,7 @@ export function ReportDefinitionCol({ {indexPattern && - reportDefinitions.map(({ field, custom, options, defaultValue }) => ( + reportDefinitions.map(({ field, custom, options }) => ( {!custom ? ( ) : ( - + )} ))} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx index a94664aa7067d..2299d5871a275 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx @@ -17,7 +17,7 @@ interface Props { options: ReportDefinition['options']; } -export function CustomReportField({ field, seriesId, options: opts, defaultValue }: Props) { +export function CustomReportField({ field, seriesId, options: opts }: Props) { const { series, setSeries } = useUrlStorage(seriesId); const { reportDefinitions: rtd = {} } = series; @@ -39,7 +39,7 @@ export function CustomReportField({ field, seriesId, options: opts, defaultValue value: fd || id, inputDisplay: label, }))} - valueOfSelected={reportDefinitions?.[field]?.[0] || defaultValue || options?.[0].field} + valueOfSelected={reportDefinitions?.[field]?.[0] || options?.[0].field} onChange={(value) => onChange(value)} /> ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx index c95d322748607..4bef3e8f71821 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/chart_edit_options.tsx @@ -20,7 +20,7 @@ export function ChartEditOptions({ series, seriesId, breakdowns }: Props) { return ( - + diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx index 2b0da37cc243f..5cf6ac47aa8c7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiSuperSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FieldLabels, USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; +import { USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; import { useUrlStorage } from '../../hooks/use_url_storage'; import { DataSeries } from '../../types'; From 1028588e55537684fea43e246d2241434db543f8 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 28 May 2021 19:00:27 +0200 Subject: [PATCH 17/17] fix selection of default metric --- .../exploratory_view/series_builder/custom_report_field.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx index 2299d5871a275..b41f3a603e5da 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx @@ -39,7 +39,7 @@ export function CustomReportField({ field, seriesId, options: opts }: Props) { value: fd || id, inputDisplay: label, }))} - valueOfSelected={reportDefinitions?.[field]?.[0] || options?.[0].field} + valueOfSelected={reportDefinitions?.[field]?.[0] || options?.[0].field || options?.[0].id} onChange={(value) => onChange(value)} /> );