From 98471eef9a695936cb08c8eefa95c9026b1b170e Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 2 Jun 2021 12:41:44 +0200 Subject: [PATCH] [Exploratory view] Core web vitals (#100320) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/lens/public/index.ts | 1 + .../configurations/constants/constants.ts | 7 + .../constants/elasticsearch_fieldnames.ts | 1 + .../configurations/constants/labels.ts | 8 + .../configurations/default_configs.ts | 3 + .../configurations/lens_attributes.test.ts | 2 +- .../configurations/lens_attributes.ts | 80 ++++++--- .../rum/core_web_vitals_config.ts | 164 ++++++++++++++++++ .../configurations/rum/kpi_trends_config.ts | 25 +-- .../rum/performance_dist_config.ts | 19 +- .../hooks/use_lens_attributes.ts | 3 +- .../series_builder/columns/chart_types.tsx | 14 +- .../columns/report_breakdowns.tsx | 8 +- .../columns/report_definition_col.tsx | 18 +- .../series_builder/custom_report_field.tsx | 8 +- .../series_builder/series_builder.tsx | 1 + .../series_editor/chart_edit_options.tsx | 2 +- .../series_editor/columns/breakdowns.test.tsx | 16 +- .../series_editor/columns/breakdowns.tsx | 33 ++-- .../shared/exploratory_view/types.ts | 15 +- 20 files changed, 354 insertions(+), 74 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/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index fcfed9b9f1fc5d..0fdd3bf4262325 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 220ae197a15bb1..e1142a071aab5a 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,4 +107,9 @@ 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'; +export const FILTER_RECORDS = 'FILTER_RECORDS'; +export const OPERATION_COLUMN = 'operation'; 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 3faf54fff31404..5ecc5b758de842 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/constants/labels.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/labels.ts index ba820a25f868ac..92150a76319f8a 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/configurations/default_configs.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts index c6089b23167841..797ee0c2e09777 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, indexPattern }); case 'uptime-pings': 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 a5fdd4971a86ff..6976b55921b090 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/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index 3e22c4da6115a9..89fc9ca5fcc58e 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 00000000000000..de9ea12be20cf7 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/core_web_vitals_config.ts @@ -0,0 +1,164 @@ +/* + * 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, + SERVICE_ENVIRONMENT, +} 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: SERVICE_NAME, + required: true, + }, + { + field: SERVICE_ENVIRONMENT, + }, + { + 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/configurations/rum/kpi_trends_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_trends_config.ts index 029fe5534965ed..5e2d3440526b54 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 af8bd00a695539..0dc582c5683dda 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 }, ], }, ], 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 dc6b4bd0ec8796..ea6f4354604018 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 @@ -67,7 +67,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 3943ae3710209c..a296d2520db349 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 @@ -20,9 +20,11 @@ const CHART_TYPE_LABEL = i18n.translate('xpack.observability.expView.chartTypes. export function SeriesChartTypesSelect({ seriesId, + seriesTypes, defaultChartType, }: { seriesId: string; + seriesTypes?: SeriesType[]; defaultChartType: SeriesType; }) { const { series, setSeries, allSeries } = useUrlStorage(seriesId); @@ -42,8 +44,18 @@ export function SeriesChartTypesSelect({ onChange={onChange} value={seriesType} excludeChartTypes={['bar_percentage_stacked']} + includeChartTypes={ + seriesTypes || [ + 'bar', + 'bar_horizontal', + 'line', + 'area', + 'bar_stacked', + 'area_stacked', + 'bar_horizontal_percentage_stacked', + ] + } label={CHART_TYPE_LABEL} - includeChartTypes={['bar', 'bar_horizontal', 'line', 'area', 'bar_stacked', 'area_stacked']} /> ); } 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 162892071dbffd..e95cd894df5f23 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 717309e064ba32..ff8b0f7aa578b7 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 { EuiFlexGroup, EuiFlexItem } 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'; @@ -66,8 +66,9 @@ export function ReportDefinitionCol({ + {indexPattern && - reportDefinitions.map(({ field, custom, options, defaultValue }) => ( + reportDefinitions.map(({ field, custom, options }) => ( {!custom ? ( ) : ( - + )} ))} @@ -95,7 +91,11 @@ export function ReportDefinitionCol({ )} - + ); 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 6b74ad45b2c070..b41f3a603e5da8 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; @@ -35,11 +35,11 @@ export function CustomReportField({ field, seriesId, options: opts, defaultValue fullWidth compressed prepend={'Metric'} - options={options.map(({ label, field: fd }) => ({ - value: fd, + options={options.map(({ label, field: fd, id }) => ({ + value: fd || id, inputDisplay: label, }))} - valueOfSelected={reportDefinitions?.[field]?.[0] || defaultValue || options?.[0].field} + valueOfSelected={reportDefinitions?.[field]?.[0] || options?.[0].field || options?.[0].id} 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 5e270524b18804..1944bb281598bc 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 - + 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 eff62a60509e39..9d26ec79c31ad4 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'); 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 5561779daa8c43..5cf6ac47aa8c74 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,15 +8,17 @@ import React from 'react'; import { EuiSuperSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FieldLabels } from '../../configurations/constants'; +import { USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; import { useUrlStorage } from '../../hooks/use_url_storage'; +import { DataSeries } from '../../types'; interface Props { seriesId: string; breakdowns: string[]; + reportViewConfig: DataSeries; } -export function Breakdowns({ seriesId, breakdowns = [] }: Props) { +export function Breakdowns({ reportViewConfig, seriesId, breakdowns = [] }: Props) { const { setSeries, series } = useUrlStorage(seriesId); const selectedBreakdown = series.breakdown; @@ -36,13 +38,21 @@ export function Breakdowns({ seriesId, breakdowns = [] }: Props) { } }; - const items = breakdowns.map((breakdown) => ({ 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 7b9278352925e9..c3dd824e441a8b 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'; @@ -21,6 +22,7 @@ import { ExistsFilter } from '../../../../../../../src/plugins/data/common/es_qu export const ReportViewTypes = { pld: 'page-load-dist', kpi: 'kpi-trends', + cwv: 'core-web-vitals', upd: 'uptime-duration', upp: 'uptime-pings', svl: 'service-latency', @@ -37,16 +39,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[]; }>; } @@ -66,6 +74,7 @@ export interface DataSeries { hasOperationType: boolean; palette?: PaletteOutput; yTitle?: string; + yConfig?: YConfig[]; } export type URLReportDefinition = Record;