diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts index ca2ad09cb446..34dd2d53daf8 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ux_overview_fetchers.ts @@ -38,18 +38,20 @@ export const fetchUxOverviewDate = async ({ }; }; -export async function hasRumData({ - absoluteTime, -}: HasDataParams): Promise { +export async function hasRumData( + params: HasDataParams +): Promise { return await callApmApi({ endpoint: 'GET /api/apm/observability_overview/has_rum_data', signal: null, params: { - query: { - start: new Date(absoluteTime.start).toISOString(), - end: new Date(absoluteTime.end).toISOString(), - uiFilters: '', - }, + query: params?.absoluteTime + ? { + start: new Date(params.absoluteTime.start).toISOString(), + end: new Date(params.absoluteTime.end).toISOString(), + uiFilters: '', + } + : undefined, }, }); } diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index d7f91adc0d68..c723f2c266ca 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -263,7 +263,7 @@ const rumJSErrors = createApmServerRoute({ const rumHasDataRoute = createApmServerRoute({ endpoint: 'GET /api/apm/observability_overview/has_rum_data', - params: t.type({ + params: t.partial({ query: t.intersection([uiFiltersRt, rangeRt]), }), options: { tags: ['access:apm'] }, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx index 37597e0ce513..c042ba9d0bcf 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx @@ -7,11 +7,13 @@ import React from 'react'; import { fireEvent, screen, waitFor } from '@testing-library/react'; -import { mockIndexPattern, render } from '../rtl_helpers'; +import { mockAppIndexPattern, mockIndexPattern, render } from '../rtl_helpers'; import { buildFilterLabel, FilterLabel } from './filter_label'; import * as useSeriesHook from '../hooks/use_series_filters'; describe('FilterLabel', function () { + mockAppIndexPattern(); + const invertFilter = jest.fn(); jest.spyOn(useSeriesHook, 'useSeriesFilters').mockReturnValue({ invertFilter, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx index 3d6dc5b3f2bf..d67c93146b15 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { injectI18n } from '@kbn/i18n/react'; import { esFilters, Filter, IndexPattern } from '../../../../../../../../src/plugins/data/public'; -import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; import { useSeriesFilters } from '../hooks/use_series_filters'; @@ -58,7 +58,7 @@ export function FilterLabel({ }: Props) { const FilterItem = injectI18n(esFilters.FilterItem); - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); const filter = buildFilterLabel({ field, value, label, indexPattern, negate }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/field_formats.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/field_formats.ts new file mode 100644 index 000000000000..8d33dfbab2c6 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/field_formats.ts @@ -0,0 +1,24 @@ +/* + * 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 { FieldFormat } from '../../types'; +import { TRANSACTION_DURATION } from '../constants/elasticsearch_fieldnames'; + +export const apmFieldFormats: FieldFormat[] = [ + { + field: TRANSACTION_DURATION, + format: { + id: 'duration', + params: { + inputFormat: 'microseconds', + outputFormat: 'asMilliseconds', + outputPrecision: 0, + showSuffix: true, + }, + }, + }, +]; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_latency_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_latency_config.ts index 7af325258481..3959860b9c53 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_latency_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_latency_config.ts @@ -8,6 +8,7 @@ import { ConfigProps, DataSeries } from '../../types'; import { FieldLabels } from '../constants'; import { buildPhraseFilter } from '../utils'; +import { TRANSACTION_DURATION } from '../constants/elasticsearch_fieldnames'; export function getServiceLatencyLensConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { return { @@ -37,7 +38,7 @@ export function getServiceLatencyLensConfig({ seriesId, indexPattern }: ConfigPr 'user_agent.device.name', ], filters: buildPhraseFilter('transaction.type', 'request', indexPattern), - labels: { ...FieldLabels }, + labels: { ...FieldLabels, [TRANSACTION_DURATION]: 'Latency' }, reportDefinitions: [ { field: 'service.name', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_throughput_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_throughput_config.ts index 7b1d472ac8bb..d4a44a5c95a0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_throughput_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/apm/service_throughput_config.ts @@ -8,6 +8,7 @@ import { ConfigProps, DataSeries } from '../../types'; import { FieldLabels } from '../constants/constants'; import { buildPhraseFilter } from '../utils'; +import { TRANSACTION_DURATION } from '../constants/elasticsearch_fieldnames'; export function getServiceThroughputLensConfig({ seriesId, @@ -40,7 +41,7 @@ export function getServiceThroughputLensConfig({ 'user_agent.device.name', ], filters: buildPhraseFilter('transaction.type', 'request', indexPattern), - labels: { ...FieldLabels }, + labels: { ...FieldLabels, [TRANSACTION_DURATION]: 'Throughput' }, reportDefinitions: [ { field: 'service.name', 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 14cd24c42e6a..5c09dbcff2d9 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 @@ -61,10 +61,10 @@ export const ReportToDataTypeMap: Record = { upp: 'synthetics', tpt: 'apm', svl: 'apm', - kpi: 'rum', - pld: 'rum', - nwk: 'metrics', - mem: 'metrics', - logs: 'logs', - cpu: 'metrics', + kpi: 'ux', + pld: 'ux', + nwk: 'infra_metrics', + mem: 'infra_metrics', + logs: 'infra_logs', + cpu: 'infra_metrics', }; 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 0de78c45041d..56c20289669f 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 @@ -6,12 +6,14 @@ */ import { LensAttributes } from './lens_attributes'; -import { mockIndexPattern } from '../rtl_helpers'; +import { mockAppIndexPattern, mockIndexPattern } from '../rtl_helpers'; import { getDefaultConfigs } from './default_configs'; import { sampleAttribute } from './test_data/sample_attribute'; import { LCP_FIELD, SERVICE_NAME, USER_AGENT_NAME } from './constants/elasticsearch_fieldnames'; describe('Lens Attribute', () => { + mockAppIndexPattern(); + const reportViewConfig = getDefaultConfigs({ reportType: 'pld', indexPattern: mockIndexPattern, @@ -53,7 +55,6 @@ describe('Lens Attribute', () => { readFromDocValues: true, }, fieldName: 'transaction.type', - columnType: null, }) ); }); @@ -72,7 +73,6 @@ describe('Lens Attribute', () => { readFromDocValues: true, }, fieldName: 'transaction.duration.us', - columnType: null, }) ); }); 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 12a5b19fb02f..01d74dc2ac36 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 @@ -45,6 +45,34 @@ function buildNumberColumn(sourceField: string) { }; } +export const parseCustomFieldName = ( + sourceField: string, + reportViewConfig: DataSeries, + selectedDefinitions: Record +) => { + let fieldName = sourceField; + let columnType; + + const rdf = reportViewConfig.reportDefinitions ?? []; + + const customField = rdf.find(({ field }) => field === fieldName); + + if (customField) { + if (selectedDefinitions[fieldName]) { + fieldName = selectedDefinitions[fieldName]; + 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; + columnType = customField.options?.[0].columnType; + } + } + + return { fieldName, columnType }; +}; + export class LensAttributes { indexPattern: IndexPattern; layers: Record; @@ -124,6 +152,18 @@ export class LensAttributes { }; } + getNumberColumn(sourceField: string, columnType?: string, operationType?: string) { + if (columnType === 'operation' || operationType) { + if (operationType === 'median' || operationType === 'average') { + return this.getNumberOperationColumn(sourceField, operationType); + } + if (operationType?.includes('th')) { + return this.getPercentileNumberColumn(sourceField, operationType); + } + } + return this.getNumberRangeColumn(sourceField); + } + getNumberOperationColumn( sourceField: string, operationType: 'average' | 'median' @@ -149,7 +189,7 @@ export class LensAttributes { ...buildNumberColumn(sourceField), label: i18n.translate('xpack.observability.expView.columns.label', { defaultMessage: '{percentileValue} percentile of {sourceField}', - values: { sourceField, percentileValue }, + values: { sourceField: this.reportViewConfig.labels[sourceField], percentileValue }, }), operationType: 'percentile', params: { percentile: Number(percentileValue.split('th')[0]) }, @@ -186,15 +226,7 @@ export class LensAttributes { return this.getDateHistogramColumn(fieldName); } if (fieldType === 'number') { - if (columnType === 'operation' || operationType) { - if (operationType === 'median' || operationType === 'average') { - return this.getNumberOperationColumn(fieldName, operationType); - } - if (operationType?.includes('th')) { - return this.getPercentileNumberColumn(sourceField, operationType); - } - } - return this.getNumberRangeColumn(fieldName); + return this.getNumberColumn(fieldName, columnType, operationType); } // FIXME review my approach again @@ -202,27 +234,7 @@ export class LensAttributes { } getCustomFieldName(sourceField: string) { - let fieldName = sourceField; - let columnType = null; - - const rdf = this.reportViewConfig.reportDefinitions ?? []; - - const customField = rdf.find(({ field }) => field === fieldName); - - if (customField) { - if (this.reportDefinitions[fieldName]) { - fieldName = this.reportDefinitions[fieldName]; - 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; - columnType = customField.options?.[0].columnType; - } - } - - return { fieldName, columnType }; + return parseCustomFieldName(sourceField, this.reportViewConfig, this.reportDefinitions); } getFieldMeta(sourceField: string) { 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 cd38d912850c..6e8413b342ce 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 @@ -25,6 +25,7 @@ import { USER_AGENT_OS, USER_AGENT_VERSION, TRANSACTION_TIME_TO_FIRST_BYTE, + TRANSACTION_URL, } from '../constants/elasticsearch_fieldnames'; export function getKPITrendsLensConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { @@ -42,6 +43,10 @@ export function getKPITrendsLensConfig({ seriesId, indexPattern }: ConfigProps): }, hasOperationType: false, defaultFilters: [ + { + field: TRANSACTION_URL, + isNegated: false, + }, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE, 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 4b6d5dd6e741..847e7db18757 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 @@ -21,6 +21,7 @@ import { TRANSACTION_DURATION, TRANSACTION_TIME_TO_FIRST_BYTE, TRANSACTION_TYPE, + TRANSACTION_URL, USER_AGENT_DEVICE, USER_AGENT_NAME, USER_AGENT_OS, @@ -42,6 +43,10 @@ export function getPerformanceDistLensConfig({ seriesId, indexPattern }: ConfigP }, hasOperationType: false, defaultFilters: [ + { + field: TRANSACTION_URL, + isNegated: false, + }, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/monitor_duration_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/monitor_duration_config.ts index efbc3d14441c..3b55f5b8eabc 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/monitor_duration_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/monitor_duration_config.ts @@ -42,6 +42,6 @@ export function getMonitorDurationConfig({ seriesId }: Props): DataSeries { field: 'monitor.id', }, ], - labels: { ...FieldLabels }, + labels: { ...FieldLabels, 'monitor.duration.us': 'Monitor duration' }, }; } 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 257eb3a739f0..375c021bc9b5 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 @@ -7,12 +7,14 @@ import React from 'react'; import { fireEvent, screen, waitFor } from '@testing-library/dom'; -import { render, mockUrlStorage, mockCore } from './rtl_helpers'; +import { render, mockUrlStorage, mockCore, mockAppIndexPattern } from './rtl_helpers'; import { ExploratoryView } from './exploratory_view'; import { getStubIndexPattern } from '../../../../../../../src/plugins/data/public/test_utils'; import * as obsvInd from './utils/observability_index_patterns'; describe('ExploratoryView', () => { + mockAppIndexPattern(); + beforeEach(() => { const indexPattern = getStubIndexPattern( 'apm-*', 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 6bc069aafa5b..7b5dde852cf9 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 @@ -15,6 +15,8 @@ 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'; export function ExploratoryView() { const { @@ -25,6 +27,8 @@ export function ExploratoryView() { null ); + const { loadIndexPattern } = useAppIndexPatternContext(); + const LensComponent = lens?.EmbeddableComponent; const { firstSeriesId: seriesId, firstSeries: series } = useUrlStorage(); @@ -33,13 +37,19 @@ export function ExploratoryView() { seriesId, }); + useEffect(() => { + if (series?.reportType || series?.dataType) { + loadIndexPattern({ dataType: series?.dataType ?? ReportToDataTypeMap[series?.reportType] }); + } + }, [series?.reportType, series?.dataType, loadIndexPattern]); + useEffect(() => { setLensAttributes(lensAttributesT); // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(lensAttributesT ?? {}), series?.reportType, series?.time?.from]); return ( - + {lens ? ( <> diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx new file mode 100644 index 000000000000..77d0d54ec5a7 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx @@ -0,0 +1,115 @@ +/* + * 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, { createContext, useContext, Context, useState, useCallback, useMemo } from 'react'; +import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; +import { AppDataType } from '../types'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../../plugin'; +import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; +import { getDataHandler } from '../../../../data_handler'; +import { UXHasDataResponse } from '../../../../typings/fetch_overview_data'; + +export interface IIndexPatternContext { + loading: boolean; + selectedApp: AppDataType; + indexPatterns: IndexPatternState; + hasAppData: HasAppDataState; + loadIndexPattern: (params: { dataType: AppDataType }) => void; +} + +export const IndexPatternContext = createContext>({}); + +interface ProviderProps { + children: JSX.Element; +} + +type HasAppDataState = Record; +type IndexPatternState = Record; + +export function IndexPatternContextProvider({ children }: ProviderProps) { + const [loading, setLoading] = useState(false); + const [selectedApp, setSelectedApp] = useState(); + const [indexPatterns, setIndexPatterns] = useState({} as IndexPatternState); + const [hasAppData, setHasAppData] = useState({ + infra_metrics: null, + infra_logs: null, + synthetics: null, + ux: null, + apm: null, + } as HasAppDataState); + + const { + services: { data }, + } = useKibana(); + + const checkIfAppHasData = async (dataType: AppDataType) => { + const handler = getDataHandler(dataType === 'synthetics' ? 'uptime' : dataType); + return handler?.hasData(); + }; + + const loadIndexPattern: IIndexPatternContext['loadIndexPattern'] = useCallback( + async ({ dataType }) => { + setSelectedApp(dataType); + + if (hasAppData[dataType] === null) { + setLoading(true); + try { + let hasDataT = await checkIfAppHasData(dataType); + + if (dataType === 'ux') { + hasDataT = (hasDataT as UXHasDataResponse).hasData as boolean; + } + + setHasAppData((prevState) => ({ ...prevState, [dataType]: hasDataT })); + + if (hasDataT || hasAppData?.[dataType]) { + const obsvIndexP = new ObservabilityIndexPatterns(data); + const indPattern = await obsvIndexP.getIndexPattern(dataType); + + setIndexPatterns((prevState) => ({ ...prevState, [dataType]: indPattern })); + } + setLoading(false); + } catch (e) { + setLoading(false); + } + } + }, + [data, hasAppData] + ); + + return ( + + {children} + + ); +} + +export const useAppIndexPatternContext = () => { + const { selectedApp, loading, hasAppData, loadIndexPattern, indexPatterns } = useContext( + (IndexPatternContext as unknown) as Context + ); + + return useMemo(() => { + return { + hasAppData, + selectedApp, + loading, + indexPattern: indexPatterns?.[selectedApp], + hasData: hasAppData?.[selectedApp], + loadIndexPattern, + }; + }, [hasAppData, indexPatterns, loadIndexPattern, loading, selectedApp]); +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx deleted file mode 100644 index c5a4d0249266..000000000000 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { createContext, useContext, Context, useState, useEffect } from 'react'; -import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; -import { AppDataType } from '../types'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; -import { ObservabilityPublicPluginsStart } from '../../../../plugin'; -import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; - -export interface IIndexPatternContext { - indexPattern: IndexPattern; - loadIndexPattern: (dataType: AppDataType) => void; -} - -export const IndexPatternContext = createContext>({}); - -interface ProviderProps { - indexPattern?: IndexPattern; - children: JSX.Element; -} - -export function IndexPatternContextProvider({ - children, - indexPattern: initialIndexPattern, -}: ProviderProps) { - const [indexPattern, setIndexPattern] = useState(initialIndexPattern); - - useEffect(() => { - setIndexPattern(initialIndexPattern); - }, [initialIndexPattern]); - - const { - services: { data }, - } = useKibana(); - - const loadIndexPattern = async (dataType: AppDataType) => { - setIndexPattern(undefined); - const obsvIndexP = new ObservabilityIndexPatterns(data); - const indPattern = await obsvIndexP.getIndexPattern(dataType); - setIndexPattern(indPattern!); - }; - - return ( - - {children} - - ); -} - -export const useIndexPatternContext = () => { - return useContext((IndexPatternContext as unknown) as Context); -}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts deleted file mode 100644 index de4343b29011..000000000000 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { useFetcher } from '../../../..'; -import { IKbnUrlStateStorage } from '../../../../../../../../src/plugins/kibana_utils/public'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; -import { ObservabilityPublicPluginsStart } from '../../../../plugin'; -import { AllShortSeries } from './use_url_storage'; -import { ReportToDataTypeMap } from '../configurations/constants'; -import { DataType, ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; - -export const useInitExploratoryView = (storage: IKbnUrlStateStorage) => { - const { - services: { data }, - } = useKibana(); - - const allSeriesKey = 'sr'; - - const allSeries = storage.get(allSeriesKey) ?? {}; - - const allSeriesIds = Object.keys(allSeries); - - const firstSeriesId = allSeriesIds?.[0]; - - const firstSeries = allSeries[firstSeriesId]; - - let dataType: DataType = firstSeries?.dataType ?? 'rum'; - - if (firstSeries?.rt) { - dataType = ReportToDataTypeMap[firstSeries?.rt]; - } - - const { data: indexPattern, error } = useFetcher(() => { - const obsvIndexP = new ObservabilityIndexPatterns(data); - - return obsvIndexP.getIndexPattern(dataType); - }, [dataType, data]); - - if (error) { - throw error; - } - - return indexPattern; -}; 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 555b21618c4b..a5fce74c4a2f 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 @@ -12,7 +12,7 @@ import { useUrlStorage } from './use_url_storage'; import { getDefaultConfigs } from '../configurations/default_configs'; import { DataSeries, SeriesUrl, UrlFilter } from '../types'; -import { useIndexPatternContext } from './use_default_index_pattern'; +import { useAppIndexPatternContext } from './use_app_index_pattern'; interface Props { seriesId: string; @@ -43,7 +43,7 @@ export const useLensAttributes = ({ const { breakdown, seriesType, operationType, reportType, reportDefinitions = {} } = series ?? {}; - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); return useMemo(() => { if (!indexPattern || !reportType) { 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 a4fe15025245..139b7faac4a3 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 @@ -56,7 +56,7 @@ interface ShortUrlSeries { export type AllShortSeries = Record; export type AllSeries = Record; -export const NEW_SERIES_KEY = 'newSeriesKey'; +export const NEW_SERIES_KEY = 'new-series-key'; export function useUrlStorage(seriesId?: string) { const allSeriesKey = 'sr'; 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 f903c4d7d44f..9fe133098549 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 @@ -13,13 +13,12 @@ import { ExploratoryView } from './exploratory_view'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { useBreadcrumbs } from '../../../hooks/use_breadcrumbs'; -import { IndexPatternContextProvider } from './hooks/use_default_index_pattern'; +import { IndexPatternContextProvider } from './hooks/use_app_index_pattern'; import { createKbnUrlStateStorage, withNotifyOnErrors, } from '../../../../../../../src/plugins/kibana_utils/public/'; import { UrlStorageContextProvider } from './hooks/use_url_storage'; -import { useInitExploratoryView } from './hooks/use_init_exploratory_view'; import { WithHeaderLayout } from '../../app/layout/with_header'; export function ExploratoryViewPage() { @@ -45,20 +44,16 @@ export function ExploratoryViewPage() { ...withNotifyOnErrors(notifications!.toasts), }); - const indexPattern = useInitExploratoryView(kbnUrlStateStorage); - return ( - {indexPattern ? ( - - - - - - ) : null} + + + + + ); } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx index b826409dd9e3..7763e8ad7122 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx @@ -22,7 +22,7 @@ import { import { ObservabilityPublicPluginsStart } from '../../../plugin'; import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common'; import { lensPluginMock } from '../../../../../lens/public/mocks'; -import { IndexPatternContextProvider } from './hooks/use_default_index_pattern'; +import { IndexPatternContextProvider } from './hooks/use_app_index_pattern'; import { AllSeries, UrlStorageContextProvider } from './hooks/use_url_storage'; import { withNotifyOnErrors, @@ -33,6 +33,7 @@ import * as useUrlHook from './hooks/use_url_storage'; import * as useSeriesFilterHook from './hooks/use_series_filters'; import * as useHasDataHook from '../../../hooks/use_has_data'; import * as useValuesListHook from '../../../hooks/use_values_list'; +import * as useAppIndexPatternHook from './hooks/use_app_index_pattern'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { getStubIndexPattern } from '../../../../../../../src/plugins/data/public/index_patterns/index_pattern.stub'; @@ -148,7 +149,7 @@ export function MockKibanaProvider>({ - + {children} @@ -234,6 +235,19 @@ export const mockUseHasData = () => { return { spy, onRefreshTimeRange }; }; +export const mockAppIndexPattern = () => { + const loadIndexPattern = jest.fn(); + const spy = jest.spyOn(useAppIndexPatternHook, 'useAppIndexPatternContext').mockReturnValue({ + indexPattern: mockIndexPattern, + selectedApp: 'ux', + hasData: true, + loading: false, + hasAppData: { ux: true } as any, + loadIndexPattern, + }); + return { spy, loadIndexPattern }; +}; + export const mockUseValuesList = (values?: string[]) => { const onRefreshTimeRange = jest.fn(); const spy = jest.spyOn(useValuesListHook, 'useValuesList').mockReturnValue({ 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 029c39df13aa..df5b57124f0e 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 @@ -66,7 +66,7 @@ export function XYChartTypesSelect({ const { data = [], loading } = useFetcher(() => lens.getXyVisTypes(), [lens]); - let vizTypes = data ?? []; + let vizTypes = data; if ((excludeChartTypes ?? []).length > 0) { vizTypes = vizTypes.filter(({ id }) => !excludeChartTypes?.includes(id as SeriesType)); @@ -95,6 +95,7 @@ export function XYChartTypesSelect({ return ( ); @@ -28,11 +30,11 @@ describe('DataTypesCol', function () { fireEvent.click(screen.getByText(/user experience\(rum\)/i)); expect(setSeries).toHaveBeenCalledTimes(1); - expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { dataType: 'rum' }); + expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { dataType: 'ux' }); }); it('should set series on change on already selected', function () { - const { removeSeries } = mockUrlStorage({ + mockUrlStorage({ data: { [NEW_SERIES_KEY]: { dataType: 'synthetics', @@ -50,10 +52,5 @@ describe('DataTypesCol', function () { }); expect(button.classList).toContain('euiButton--fill'); - - fireEvent.click(button); - - // undefined on click selected - expect(removeSeries).toHaveBeenCalledWith('newSeriesKey'); }); }); 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 d7e90d34a259..79008d91b294 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 @@ -7,27 +7,25 @@ import React from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; import { AppDataType } from '../../types'; -import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_storage'; export const dataTypes: Array<{ id: AppDataType; label: string }> = [ { id: 'synthetics', label: 'Synthetic Monitoring' }, - { id: 'rum', label: 'User Experience(RUM)' }, - { id: 'logs', label: 'Logs' }, - { id: 'metrics', label: 'Metrics' }, - { id: 'apm', label: 'APM' }, + { id: 'ux', label: 'User Experience(RUM)' }, + // { id: 'infra_logs', label: 'Logs' }, + // { id: 'infra_metrics', label: 'Metrics' }, + // { id: 'apm', label: 'APM' }, ]; export function DataTypesCol() { const { series, setSeries, removeSeries } = useUrlStorage(NEW_SERIES_KEY); - const { loadIndexPattern, indexPattern } = useIndexPatternContext(); + const { loading } = useAppIndexPatternContext(); const onDataTypeChange = (dataType?: AppDataType) => { - if (dataType) { - loadIndexPattern(dataType); - } if (!dataType) { removeSeries(NEW_SERIES_KEY); } else { @@ -38,7 +36,7 @@ export function DataTypesCol() { const selectedDataType = series.dataType; return ( - + {dataTypes.map(({ id: dataTypeId, label }) => ( { - onDataTypeChange(dataTypeId === selectedDataType ? undefined : dataTypeId); + onDataTypeChange(dataTypeId); }} > {label} ))} - + ); } + +const FlexGroup = styled(EuiFlexGroup)` + width: 100%; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/date_picker_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/date_picker_col.tsx new file mode 100644 index 000000000000..a245d39cee08 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/date_picker_col.tsx @@ -0,0 +1,20 @@ +/* + * 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 { SeriesDatePicker } from '../../series_date_picker'; + +interface Props { + seriesId: string; +} +export function DatePickerCol({ seriesId }: Props) { + return ( +
+ +
+ ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/operation_type_select.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/operation_type_select.tsx index 46167af0b244..b33671f78bfe 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/operation_type_select.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/operation_type_select.tsx @@ -29,7 +29,9 @@ export function OperationTypeSelect({ useEffect(() => { setSeries(seriesId, { ...series, operationType: operationType || defaultOperationType }); - }, [defaultOperationType, seriesId, operationType, setSeries, series]); + // We only want to call this when defaultOperationType changes + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [defaultOperationType]); const options = [ { @@ -72,6 +74,7 @@ export function OperationTypeSelect({ return ( ) { + const { reportDefinitions } = dataView; + const customColumn = reportDefinitions.find((item) => item.custom); + if (customColumn?.field && selectedDefinition[customColumn?.field]) { + const { columnType } = parseCustomFieldName(customColumn.field, dataView, selectedDefinition); + + return columnType; + } + return null; +} + +const MaxWidthStyle = { maxWidth: 250 }; export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSeries }) { - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); const { series, setSeries } = useUrlStorage(NEW_SERIES_KEY); @@ -54,14 +70,19 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe }); }; + const columnType = getColumnType(dataViewSeries, rtd); + return ( - + + + + {indexPattern && reportDefinitions.map(({ field, custom, options, defaultValue }) => ( {!custom ? ( - - + + onChange(field, val)} filters={(filters ?? []).map(({ query }) => query)} time={series.time} - width={200} + fullWidth={true} /> {rtd?.[field] && ( @@ -100,17 +121,21 @@ export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSe )} ))} - - - - {hasOperationType && ( - + {(hasOperationType || columnType === 'operation') && ( + )} - + + + + ); } + +const FlexGroup = styled(EuiFlexGroup)` + width: 100%; +`; 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 f845bf9885af..c5b8f1147af5 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 @@ -7,14 +7,17 @@ import React from 'react'; import { fireEvent, screen } from '@testing-library/react'; -import { mockUrlStorage, render } from '../../rtl_helpers'; +import { mockAppIndexPattern, mockUrlStorage, render } from '../../rtl_helpers'; import { ReportTypesCol, SELECTED_DATA_TYPE_FOR_REPORT } from './report_types_col'; import { ReportTypes } from '../series_builder'; import { DEFAULT_TIME } from '../../configurations/constants'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_storage'; describe('ReportTypesCol', function () { + mockAppIndexPattern(); + it('should render properly', function () { - render(); + render(); screen.getByText('Performance distribution'); screen.getByText('KPI over time'); }); @@ -30,7 +33,7 @@ describe('ReportTypesCol', function () { fireEvent.click(screen.getByText(/monitor duration/i)); - expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { breakdown: 'user_agent.name', reportDefinitions: {}, reportType: 'upd', @@ -42,7 +45,7 @@ describe('ReportTypesCol', function () { it('should set selected as filled', function () { const { setSeries } = mockUrlStorage({ data: { - newSeriesKey: { + [NEW_SERIES_KEY]: { dataType: 'synthetics', reportType: 'upp', breakdown: 'monitor.status', @@ -61,7 +64,7 @@ describe('ReportTypesCol', function () { fireEvent.click(button); // undefined on click selected - expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + expect(setSeries).toHaveBeenCalledWith(NEW_SERIES_KEY, { dataType: 'synthetics', time: DEFAULT_TIME, }); 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 a8f98b98026b..b8ab1c80009d 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 @@ -7,11 +7,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; +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 { DEFAULT_TIME } from '../../configurations/constants'; -import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; interface Props { reportTypes: Array<{ id: ReportViewTypeId; label: string }>; @@ -23,19 +25,29 @@ export function ReportTypesCol({ reportTypes }: Props) { setSeries, } = useUrlStorage(NEW_SERIES_KEY); - const { indexPattern } = useIndexPatternContext(); + const { loading, hasData, selectedApp } = useAppIndexPatternContext(); + + if (!loading && !hasData && selectedApp) { + return ( + + ); + } return reportTypes?.length > 0 ? ( - + {reportTypes.map(({ id: reportType, label }) => ( { if (reportType === selectedReportType) { setSeries(NEW_SERIES_KEY, { @@ -56,7 +68,7 @@ export function ReportTypesCol({ reportTypes }: Props) { ))} - + ) : ( {SELECTED_DATA_TYPE_FOR_REPORT} ); @@ -66,3 +78,7 @@ export const SELECTED_DATA_TYPE_FOR_REPORT = i18n.translate( 'xpack.observability.expView.reportType.noDataType', { defaultMessage: 'Select a data type to start building a series.' } ); + +const FlexGroup = styled(EuiFlexGroup)` + width: 100%; +`; 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 4d5033eca241..b630ee55b578 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 @@ -28,18 +28,18 @@ export function CustomReportField({ field, seriesId, options: opts, defaultValue const { reportDefinitions } = series; - const NO_SELECT = 'no_select'; - - const options = [{ label: 'Select metric', field: NO_SELECT }, ...(opts ?? [])]; + const options = opts ?? []; return ( -
+
({ value: fd, inputDisplay: label, }))} - valueOfSelected={reportDefinitions?.[field] || defaultValue || NO_SELECT} + valueOfSelected={reportDefinitions?.[field] || 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 2280109fdacd..5831b8be04c3 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,11 +5,10 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButton, EuiBasicTable, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import styled from 'styled-components'; import { AppDataType, ReportViewTypeId, ReportViewTypes, SeriesUrl } from '../types'; import { DataTypesCol } from './columns/data_types_col'; import { ReportTypesCol } from './columns/report_types_col'; @@ -17,7 +16,7 @@ import { ReportDefinitionCol } from './columns/report_definition_col'; import { ReportFilters } from './columns/report_filters'; import { ReportBreakdowns } from './columns/report_breakdowns'; import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_storage'; -import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; import { getDefaultConfigs } from '../configurations/default_configs'; export const ReportTypes: Record> = { @@ -25,7 +24,7 @@ export const ReportTypes: Record { return getDefaultConfigs({ @@ -70,19 +71,23 @@ export function SeriesBuilder() { }); }; + useEffect(() => { + setIsFlyoutVisible(!!series.dataType); + }, [series.dataType]); + const columns = [ { name: i18n.translate('xpack.observability.expView.seriesBuilder.dataType', { defaultMessage: 'Data Type', }), - width: '20%', + width: '15%', render: (val: string) => , }, { name: i18n.translate('xpack.observability.expView.seriesBuilder.report', { defaultMessage: 'Report', }), - width: '20%', + width: '15%', render: (val: string) => ( ), @@ -92,16 +97,25 @@ export function SeriesBuilder() { defaultMessage: 'Definition', }), width: '30%', - render: (val: string) => - reportType && indexPattern ? ( - - ) : null, + render: (val: string) => { + if (dataType && hasData) { + return loading ? ( + INITIATING_VIEW + ) : reportType ? ( + + ) : ( + SELECT_REPORT_TYPE + ); + } + + return null; + }, }, { name: i18n.translate('xpack.observability.expView.seriesBuilder.filters', { defaultMessage: 'Filters', }), - width: '25%', + width: '20%', render: (val: string) => reportType && indexPattern ? : null, }, @@ -109,7 +123,7 @@ export function SeriesBuilder() { name: i18n.translate('xpack.observability.expView.seriesBuilder.breakdown', { defaultMessage: 'Breakdowns', }), - width: '25%', + width: '20%', field: 'id', render: (val: string) => reportType && indexPattern ? ( @@ -126,14 +140,15 @@ export function SeriesBuilder() { ReportViewTypes[reportType] }`; - const newSeriesN = { + const newSeriesN: SeriesUrl = { + time, + filters, + breakdown, reportType, seriesType, - filters, - reportDefinitions, operationType, - time: { from: 'now-30m', to: 'now' }, - } as SeriesUrl; + reportDefinitions, + }; setSeries(newSeriesId, newSeriesN).then(() => { removeSeries(NEW_SERIES_KEY); @@ -148,7 +163,7 @@ export function SeriesBuilder() { if (isFlyoutVisible) { flyout = ( - + <> - + {i18n.translate('xpack.observability.expView.seriesBuilder.add', { defaultMessage: 'Add', })} @@ -165,6 +187,7 @@ export function SeriesBuilder() { { @@ -178,7 +201,7 @@ export function SeriesBuilder() { - + ); } @@ -205,6 +228,13 @@ export function SeriesBuilder() { ); } -const BottomFlyout = styled.div` - height: 300px; -`; +const INITIATING_VIEW = i18n.translate('xpack.observability.expView.seriesBuilder.initView', { + defaultMessage: 'Initiating view ...', +}); + +const SELECT_REPORT_TYPE = i18n.translate( + 'xpack.observability.expView.seriesBuilder.selectReportType', + { + defaultMessage: 'Select a report type to define visualization.', + } +); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_options.tsx similarity index 95% rename from x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx rename to x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_options.tsx index fe54262e1384..975817a8417d 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_options.tsx @@ -15,7 +15,7 @@ interface Props { series: DataSeries; } -export function ActionsCol({ series }: Props) { +export function ChartOptions({ series }: Props) { return ( 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 3e6d7890f4c8..5f5c99ca796c 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 @@ -13,7 +13,8 @@ import { EuiLoadingSpinner, EuiFilterGroup, } from '@elastic/eui'; -import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import styled from 'styled-components'; +import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; import { useUrlStorage } from '../../hooks/use_url_storage'; import { UrlFilter } from '../../types'; import { FilterValueButton } from './filter_value_btn'; @@ -23,12 +24,13 @@ interface Props { seriesId: string; label: string; field: string; + isNegated?: boolean; goBack: () => void; nestedField?: string; } -export function FilterExpanded({ seriesId, field, label, goBack, nestedField }: Props) { - const { indexPattern } = useIndexPatternContext(); +export function FilterExpanded({ seriesId, field, label, goBack, nestedField, isNegated }: Props) { + const { indexPattern } = useAppIndexPatternContext(); const [value, setValue] = useState(''); @@ -37,9 +39,10 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField }: const { series } = useUrlStorage(seriesId); const { values, loading } = useValuesList({ + query: value, + indexPattern, sourceField: field, time: series.time, - indexPattern, }); const filters = series?.filters ?? []; @@ -51,7 +54,7 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField }: ); return ( - <> + goBack()}> {label} @@ -71,16 +74,18 @@ export function FilterExpanded({ seriesId, field, label, goBack, nestedField }: {displayValues.map((opt) => ( - + {isNegated !== false && ( + + )} ))} - + ); } + +const Wrapper = styled.div` + max-width: 400px; +`; 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 efccb351c261..849fb8ffa66b 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 @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; import { EuiFilterButton, hexToRgb } from '@elastic/eui'; -import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern'; import { useUrlStorage } from '../../hooks/use_url_storage'; import { useSeriesFilters } from '../../hooks/use_series_filters'; import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; @@ -39,7 +39,7 @@ export function FilterValueButton({ }: Props) { const { series } = useUrlStorage(seriesId); - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); const { setFilter, removeFilter } = useSeriesFilters({ seriesId }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx index aaaa02c7c569..ba2cdc545fbe 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx @@ -8,18 +8,17 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { EuiButtonIcon } from '@elastic/eui'; -import { DataSeries } from '../../types'; import { useUrlStorage } from '../../hooks/use_url_storage'; interface Props { - series: DataSeries; + seriesId: string; } -export function RemoveSeries({ series }: Props) { +export function RemoveSeries({ seriesId }: Props) { const { removeSeries } = useUrlStorage(); const onClick = () => { - removeSeries(series.id); + removeSeries(seriesId); }; return ( { + removeSeries(seriesId); + setSeries(NEW_SERIES_KEY, { ...series, dataType: ReportToDataTypeMap[series.reportType] }); + }; + + return ( + + + + + + + + + ); +} 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 c9bb44cfd8cc..88cb53826341 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 @@ -32,6 +32,7 @@ export interface Field { label: string; field: string; nested?: string; + isNegated?: boolean; } export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: Props) { @@ -39,11 +40,17 @@ export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: P const [selectedField, setSelectedField] = useState(); - const options = defaultFilters.map((field) => { + const options: Field[] = defaultFilters.map((field) => { if (typeof field === 'string') { return { label: FieldLabels[field], field }; } - return { label: FieldLabels[field.field], field: field.field, nested: field.nested }; + + return { + label: FieldLabels[field.field], + field: field.field, + nested: field.nested, + isNegated: field.isNegated, + }; }); const disabled = seriesId === NEW_SERIES_KEY && !isNew; @@ -92,6 +99,7 @@ export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: P field={selectedField.field} label={selectedField.label} nestedField={selectedField.nested} + isNegated={selectedField.isNegated} goBack={() => { setSelectedField(undefined); }} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx index a38b50d610c7..30844a3f78a7 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx @@ -7,13 +7,15 @@ import React from 'react'; import { screen, waitFor } from '@testing-library/react'; -import { mockIndexPattern, mockUrlStorage, render } from '../rtl_helpers'; +import { mockAppIndexPattern, mockIndexPattern, mockUrlStorage, render } from '../rtl_helpers'; import { SelectedFilters } from './selected_filters'; import { getDefaultConfigs } from '../configurations/default_configs'; import { NEW_SERIES_KEY } from '../hooks/use_url_storage'; import { USER_AGENT_NAME } from '../configurations/constants/elasticsearch_fieldnames'; describe('SelectedFilters', function () { + mockAppIndexPattern(); + const dataViewSeries = getDefaultConfigs({ reportType: 'pld', indexPattern: mockIndexPattern, 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 34e69f688eaa..4055a592c75d 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 @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_storage'; import { FilterLabel } from '../components/filter_label'; import { DataSeries, UrlFilter } from '../types'; -import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern'; import { useSeriesFilters } from '../hooks/use_series_filters'; import { getFiltersFromDefs } from '../hooks/use_lens_attributes'; @@ -37,7 +37,7 @@ export function SelectedFilters({ seriesId, isNew, series: dataSeries }: Props) const { removeFilter } = useSeriesFilters({ seriesId }); - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); return (filters.length > 0 || definitionFilters.length > 0) && indexPattern ? ( @@ -45,7 +45,7 @@ export function SelectedFilters({ seriesId, isNew, series: dataSeries }: Props) {filters.map(({ field, values, notValues }) => ( {(values ?? []).map((val) => ( - + ))} {(notValues ?? []).map((val) => ( - + ( {' '} - {val === NEW_SERIES_KEY ? 'new-series-preview' : val} + {val === NEW_SERIES_KEY ? 'series-preview' : val} ), }, @@ -63,34 +64,30 @@ export function SeriesEditor() { align: 'center' as const, width: '15%', field: 'id', - render: (val: string, item: DataSeries) => , + render: (val: string, item: DataSeries) => , + }, + { + name: ( +
+ +
+ ), + width: '20%', + field: 'id', + align: 'right' as const, + render: (val: string, item: DataSeries) => , }, - ] - : []), - { - name: ( -
- {i18n.translate('xpack.observability.expView.seriesEditor.time', { - defaultMessage: 'Time', - })} -
- ), - width: '20%', - field: 'id', - align: 'right' as const, - render: (val: string, item: DataSeries) => , - }, - - ...(firstSeriesId !== NEW_SERIES_KEY - ? [ { name: i18n.translate('xpack.observability.expView.seriesEditor.actions', { defaultMessage: 'Actions', }), align: 'center' as const, - width: '5%', + width: '8%', field: 'id', - render: (val: string, item: DataSeries) => , + render: (val: string, item: DataSeries) => , }, ] : []), @@ -100,7 +97,7 @@ export function SeriesEditor() { const items: DataSeries[] = []; - const { indexPattern } = useIndexPatternContext(); + const { indexPattern } = useAppIndexPatternContext(); allSeriesKeys.forEach((seriesKey) => { const series = allSeries[seriesKey]; 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 141dcecd0ba5..bd908661365c 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 @@ -57,7 +57,7 @@ export interface DataSeries { breakdowns: string[]; defaultSeriesType: SeriesType; - defaultFilters: Array; + defaultFilters: Array; seriesTypes: SeriesType[]; filters?: PersistableFilter[]; reportDefinitions: ReportDefinition[]; @@ -91,7 +91,7 @@ export interface ConfigProps { indexPattern: IIndexPattern; } -export type AppDataType = 'synthetics' | 'rum' | 'logs' | 'metrics' | 'apm'; +export type AppDataType = 'synthetics' | 'ux' | 'infra_logs' | 'infra_metrics' | 'apm'; type FormatType = 'duration' | 'number'; type InputFormat = 'microseconds' | 'milliseconds' | 'seconds'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts index b6f544db2a31..f1347e1d21cc 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts @@ -40,17 +40,17 @@ const fieldFormats = { describe('ObservabilityIndexPatterns', function () { const { data } = mockCore(); data!.indexPatterns.get = jest.fn().mockReturnValue({ title: 'index-*' }); - data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: indexPatternList.rum }); + data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: indexPatternList.ux }); data!.indexPatterns.updateSavedObject = jest.fn(); it('should return index pattern for app', async function () { const obsv = new ObservabilityIndexPatterns(data!); - const indexP = await obsv.getIndexPattern('rum'); + const indexP = await obsv.getIndexPattern('ux'); expect(indexP).toEqual({ title: 'index-*' }); - expect(data?.indexPatterns.get).toHaveBeenCalledWith(indexPatternList.rum); + expect(data?.indexPatterns.get).toHaveBeenCalledWith(indexPatternList.ux); expect(data?.indexPatterns.get).toHaveBeenCalledTimes(1); }); @@ -61,9 +61,9 @@ describe('ObservabilityIndexPatterns', function () { const obsv = new ObservabilityIndexPatterns(data!); - const indexP = await obsv.getIndexPattern('rum'); + const indexP = await obsv.getIndexPattern('ux'); - expect(indexP).toEqual({ id: indexPatternList.rum }); + expect(indexP).toEqual({ id: indexPatternList.ux }); expect(data?.indexPatterns.createAndSave).toHaveBeenCalledWith({ fieldFormats, @@ -77,7 +77,7 @@ describe('ObservabilityIndexPatterns', function () { it('should return getFieldFormats', function () { const obsv = new ObservabilityIndexPatterns(data!); - expect(obsv.getFieldFormats('rum')).toEqual(fieldFormats); + expect(obsv.getFieldFormats('ux')).toEqual(fieldFormats); }); it('should validate field formats', async function () { @@ -85,7 +85,7 @@ describe('ObservabilityIndexPatterns', function () { const obsv = new ObservabilityIndexPatterns(data!); - await obsv.validateFieldFormats('rum', mockIndexPattern); + await obsv.validateFieldFormats('ux', mockIndexPattern); expect(data?.indexPatterns.updateSavedObject).toHaveBeenCalledTimes(1); expect(data?.indexPatterns.updateSavedObject).toHaveBeenCalledWith( diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts index 527ef48364d2..b890df69d993 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts @@ -14,36 +14,35 @@ import { } from '../../../../../../../../src/plugins/data/public'; import { rumFieldFormats } from '../configurations/rum/field_formats'; import { syntheticsFieldFormats } from '../configurations/synthetics/field_formats'; -import { FieldFormat, FieldFormatParams } from '../types'; +import { AppDataType, FieldFormat, FieldFormatParams } from '../types'; +import { apmFieldFormats } from '../configurations/apm/field_formats'; -const appFieldFormats: Record = { - rum: rumFieldFormats, - apm: null, - logs: null, - metrics: null, +const appFieldFormats: Record = { + infra_logs: null, + infra_metrics: null, + ux: rumFieldFormats, + apm: apmFieldFormats, synthetics: syntheticsFieldFormats, }; -function getFieldFormatsForApp(app: DataType) { +function getFieldFormatsForApp(app: AppDataType) { return appFieldFormats[app]; } -export type DataType = 'synthetics' | 'apm' | 'logs' | 'metrics' | 'rum'; - -export const indexPatternList: Record = { +export const indexPatternList: Record = { synthetics: 'synthetics_static_index_pattern_id', apm: 'apm_static_index_pattern_id', - rum: 'rum_static_index_pattern_id', - logs: 'logs_static_index_pattern_id', - metrics: 'metrics_static_index_pattern_id', + ux: 'rum_static_index_pattern_id', + infra_logs: 'infra_logs_static_index_pattern_id', + infra_metrics: 'infra_metrics_static_index_pattern_id', }; -const appToPatternMap: Record = { +const appToPatternMap: Record = { synthetics: '(synthetics-data-view)*,heartbeat-*,synthetics-*', apm: 'apm-*', - rum: '(rum-data-view)*,apm-*', - logs: 'logs-*,filebeat-*', - metrics: 'metrics-*,metricbeat-*', + ux: '(rum-data-view)*,apm-*', + infra_logs: 'logs-*,filebeat-*', + infra_metrics: 'metrics-*,metricbeat-*', }; export function isParamsSame(param1: IFieldFormat['_params'], param2: FieldFormatParams) { @@ -66,7 +65,7 @@ export class ObservabilityIndexPatterns { this.data = data; } - async createIndexPattern(app: DataType) { + async createIndexPattern(app: AppDataType) { if (!this.data) { throw new Error('data is not defined'); } @@ -81,7 +80,7 @@ export class ObservabilityIndexPatterns { }); } // we want to make sure field formats remain same - async validateFieldFormats(app: DataType, indexPattern: IndexPattern) { + async validateFieldFormats(app: AppDataType, indexPattern: IndexPattern) { const defaultFieldFormats = getFieldFormatsForApp(app); if (defaultFieldFormats && defaultFieldFormats.length > 0) { let isParamsDifferent = false; @@ -99,7 +98,7 @@ export class ObservabilityIndexPatterns { } } - getFieldFormats(app: DataType) { + getFieldFormats(app: AppDataType) { const fieldFormatMap: IndexPatternSpec['fieldFormats'] = {}; (appFieldFormats?.[app] ?? []).forEach(({ field, format }) => { @@ -109,7 +108,7 @@ export class ObservabilityIndexPatterns { return fieldFormatMap; } - async getIndexPattern(app: DataType): Promise { + async getIndexPattern(app: AppDataType): Promise { if (!this.data) { throw new Error('data is not defined'); } 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 8e95d8e711ad..ae91e1a43918 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 @@ -12,7 +12,8 @@ import { CoreStart } from 'src/core/public'; import { text } from '@storybook/addon-knobs'; import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common'; import { createKibanaReactContext } from '../../../../../../../../src/plugins/kibana_react/public'; -import { FieldValueSelection, FieldValueSelectionProps } from '../field_value_selection'; +import { FieldValueSelectionProps } from '../types'; +import { FieldValueSelection } from '../field_value_selection'; const KibanaReactContext = createKibanaReactContext(({ uiSettings: { get: () => {}, get$: () => new Observable() }, 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 d14039ba173a..d7e075d7fc3f 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 @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FormEvent, Fragment, useEffect, useState, Dispatch, SetStateAction } from 'react'; +import React, { FormEvent, useEffect, useState } from 'react'; import { EuiButton, EuiPopover, @@ -15,20 +15,8 @@ import { EuiSelectableOption, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { PopoverAnchorPosition } from '@elastic/eui/src/components/popover/popover'; - -export interface FieldValueSelectionProps { - value?: string; - label: string; - loading?: boolean; - onChange: (val?: string) => void; - values?: string[]; - setQuery: Dispatch>; - anchorPosition?: PopoverAnchorPosition; - forceOpen?: boolean; - button?: JSX.Element; - width?: number; -} +import styled from 'styled-components'; +import { FieldValueSelectionProps } from './types'; const formatOptions = (values?: string[], value?: string): EuiSelectableOption[] => { return (values ?? []).map((val) => ({ @@ -38,6 +26,7 @@ const formatOptions = (values?: string[], value?: string): EuiSelectableOption[] }; export function FieldValueSelection({ + fullWidth, label, value, loading, @@ -47,6 +36,7 @@ export function FieldValueSelection({ width, forceOpen, anchorPosition, + singleSelection, onChange: onSelectionChange, }: FieldValueSelectionProps) { const [options, setOptions] = useState(formatOptions(values, value)); @@ -81,13 +71,14 @@ export function FieldValueSelection({ iconSide="right" onClick={onButtonClick} data-test-subj={'fieldValueSelectionBtn'} + fullWidth={fullWidth} > {label} ); return ( - + - + ); } + +const Wrapper = styled.div` + &&& { + div.euiPopover__anchor { + width: 100%; + max-width: 250px; + .euiButton { + width: 100%; + } + } + } +`; 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 9ffe2584c8d7..a3bfd8daac7d 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 @@ -8,27 +8,12 @@ import React, { useState } from 'react'; import { useDebounce } from 'react-use'; -import { PopoverAnchorPosition } from '@elastic/eui/src/components/popover/popover'; import { useValuesList } from '../../../hooks/use_values_list'; -import { IndexPattern } from '../../../../../../../src/plugins/data/common'; import { FieldValueSelection } from './field_value_selection'; -import { ESFilter } from '../../../../../../../typings/elasticsearch'; - -export interface FieldValueSuggestionsProps { - value?: string; - label: string; - indexPattern: IndexPattern; - sourceField: string; - onChange: (val?: string) => void; - filters: ESFilter[]; - anchorPosition?: PopoverAnchorPosition; - time?: { from: string; to: string }; - forceOpen?: boolean; - button?: JSX.Element; - width?: number; -} +import { FieldValueSuggestionsProps } from './types'; export function FieldValueSuggestions({ + fullWidth, sourceField, label, indexPattern, @@ -39,6 +24,7 @@ export function FieldValueSuggestions({ width, forceOpen, anchorPosition, + singleSelection, onChange: onSelectionChange, }: FieldValueSuggestionsProps) { const [query, setQuery] = useState(''); @@ -56,6 +42,8 @@ export function FieldValueSuggestions({ return ( void; + filters: ESFilter[]; + time?: { from: string; to: string }; +}; + +export type FieldValueSelectionProps = CommonProps & { + loading?: boolean; + onChange: (val?: string) => void; + values?: string[]; + setQuery: Dispatch>; +}; diff --git a/x-pack/plugins/observability/public/components/shared/index.tsx b/x-pack/plugins/observability/public/components/shared/index.tsx index 976139fdc121..d4d7521a6b09 100644 --- a/x-pack/plugins/observability/public/components/shared/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/index.tsx @@ -7,7 +7,7 @@ import React, { lazy, Suspense } from 'react'; import type { CoreVitalProps, HeaderMenuPortalProps } from './types'; -import type { FieldValueSuggestionsProps } from './field_value_suggestions'; +import type { FieldValueSuggestionsProps } from './field_value_suggestions/types'; const CoreVitalsLazy = lazy(() => import('./core_web_vitals/index')); diff --git a/x-pack/plugins/observability/public/typings/fetch_overview_data/index.ts b/x-pack/plugins/observability/public/typings/fetch_overview_data/index.ts index 726c83d0c225..ae3e2eb8c270 100644 --- a/x-pack/plugins/observability/public/typings/fetch_overview_data/index.ts +++ b/x-pack/plugins/observability/public/typings/fetch_overview_data/index.ts @@ -125,6 +125,7 @@ export interface ObservabilityFetchDataResponse { apm: ApmFetchDataResponse; infra_metrics: MetricsFetchDataResponse; infra_logs: LogsFetchDataResponse; + synthetics: UptimeFetchDataResponse; uptime: UptimeFetchDataResponse; ux: UxFetchDataResponse; } @@ -134,5 +135,6 @@ export interface ObservabilityHasDataResponse { infra_metrics: boolean; infra_logs: boolean; uptime: boolean; + synthetics: boolean; ux: UXHasDataResponse; } diff --git a/x-pack/plugins/observability/typings/common.ts b/x-pack/plugins/observability/typings/common.ts index 0d0b2af85170..81477d0a7f81 100644 --- a/x-pack/plugins/observability/typings/common.ts +++ b/x-pack/plugins/observability/typings/common.ts @@ -9,7 +9,9 @@ export type ObservabilityApp = | 'infra_metrics' | 'infra_logs' | 'apm' + // we will remove uptime in future to replace to be replace by synthetics | 'uptime' + | 'synthetics' | 'observability-overview' | 'stack_monitoring' | 'ux';