Skip to content

Commit a5826f3

Browse files
[9.1] [Discover][APM] Infer field types for summary overview fields correctly (elastic#226055) (elastic#226416)
# Backport This will backport the following commits from `main` to `9.1`: - [[Discover][APM] Infer field types for summary overview fields correctly (elastic#226055)](elastic#226055) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Gonçalo Rica Pais da Silva","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-07-03T13:05:27Z","message":"[Discover][APM] Infer field types for summary overview fields correctly (elastic#226055)\n\n## Summary\n\nThis PR adds in a new hook to help build a map of fields with their\ninferred field type from either `dataView` or `columnsMeta`. This then\nis used to feed the field type information into the fields actions, so\nthat when a filter is applied to the ES|QL query, it doesn't try to cast\nthe field to a string if it doesn't have an explicit mapping.\n\nCloses elastic#220626\n\n\n![image](https://github.com/user-attachments/assets/943e0344-1f8c-4216-91f1-c819ba6c3d64)\n\n## How to test\n\n\n- Set the space to Observability mode, go to Discover, select ES|QL and\nwrite a query to target a `traces-*` index that has documents with\nunmapped non-string fields. (For example, remote_cluster:traces-* when\nusing edge-oblt-ccs)\n- Click on a span document to open the document overview, hover over\nStatus Code to click to add it as a WHERE clause to the query.\n- Click on a client.ip field where possible to check string casting\nworks when encountering special/non-primitive field types.\n- Every clause added to the query should not result in an error.","sha":"ebff918b4d4f3c8b06b1e4dda6228e18b33babea","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:obs-ux-infra_services","backport:version","v9.1.0","v8.19.0","v9.2.0"],"title":"[Discover][APM] Infer field types for summary overview fields correctly","number":226055,"url":"https://github.com/elastic/kibana/pull/226055","mergeCommit":{"message":"[Discover][APM] Infer field types for summary overview fields correctly (elastic#226055)\n\n## Summary\n\nThis PR adds in a new hook to help build a map of fields with their\ninferred field type from either `dataView` or `columnsMeta`. This then\nis used to feed the field type information into the fields actions, so\nthat when a filter is applied to the ES|QL query, it doesn't try to cast\nthe field to a string if it doesn't have an explicit mapping.\n\nCloses elastic#220626\n\n\n![image](https://github.com/user-attachments/assets/943e0344-1f8c-4216-91f1-c819ba6c3d64)\n\n## How to test\n\n\n- Set the space to Observability mode, go to Discover, select ES|QL and\nwrite a query to target a `traces-*` index that has documents with\nunmapped non-string fields. (For example, remote_cluster:traces-* when\nusing edge-oblt-ccs)\n- Click on a span document to open the document overview, hover over\nStatus Code to click to add it as a WHERE clause to the query.\n- Click on a client.ip field where possible to check string casting\nworks when encountering special/non-primitive field types.\n- Every clause added to the query should not result in an error.","sha":"ebff918b4d4f3c8b06b1e4dda6228e18b33babea"}},"sourceBranch":"main","suggestedTargetBranches":["9.1","8.19"],"targetPullRequestStates":[{"branch":"9.1","label":"v9.1.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/226055","number":226055,"mergeCommit":{"message":"[Discover][APM] Infer field types for summary overview fields correctly (elastic#226055)\n\n## Summary\n\nThis PR adds in a new hook to help build a map of fields with their\ninferred field type from either `dataView` or `columnsMeta`. This then\nis used to feed the field type information into the fields actions, so\nthat when a filter is applied to the ES|QL query, it doesn't try to cast\nthe field to a string if it doesn't have an explicit mapping.\n\nCloses elastic#220626\n\n\n![image](https://github.com/user-attachments/assets/943e0344-1f8c-4216-91f1-c819ba6c3d64)\n\n## How to test\n\n\n- Set the space to Observability mode, go to Discover, select ES|QL and\nwrite a query to target a `traces-*` index that has documents with\nunmapped non-string fields. (For example, remote_cluster:traces-* when\nusing edge-oblt-ccs)\n- Click on a span document to open the document overview, hover over\nStatus Code to click to add it as a WHERE clause to the query.\n- Click on a client.ip field where possible to check string casting\nworks when encountering special/non-primitive field types.\n- Every clause added to the query should not result in an error.","sha":"ebff918b4d4f3c8b06b1e4dda6228e18b33babea"}}]}] BACKPORT--> Co-authored-by: Gonçalo Rica Pais da Silva <[email protected]>
1 parent ac4adf1 commit a5826f3

File tree

11 files changed

+96
-10
lines changed

11 files changed

+96
-10
lines changed

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/field_with_actions/field_hover_popover_action.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import {
1717
PopoverAnchorPosition,
1818
type EuiPopoverProps,
1919
} from '@elastic/eui';
20+
import { DataViewField } from '@kbn/data-views-plugin/common';
2021
import { useUIFieldActions } from '../../../../../hooks/use_field_actions';
2122

2223
interface HoverPopoverActionProps {
2324
children: React.ReactChild;
2425
field: string;
26+
fieldMapping?: DataViewField;
2527
value: unknown;
2628
formattedValue?: string;
2729
title: string;
@@ -33,14 +35,15 @@ export const FieldHoverActionPopover = ({
3335
children,
3436
title,
3537
field,
38+
fieldMapping: mapping,
3639
value,
3740
formattedValue,
3841
anchorPosition = 'upCenter',
3942
display = 'inline-block',
4043
}: HoverPopoverActionProps) => {
4144
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
4245
const leaveTimer = useRef<NodeJS.Timeout | null>(null);
43-
const uiFieldActions = useUIFieldActions({ field, value, formattedValue });
46+
const uiFieldActions = useUIFieldActions({ field, value, formattedValue, mapping });
4447

4548
const clearTimeoutIfExists = () => {
4649
if (leaveTimer.current) {

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/field_with_actions/field_with_actions.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiLoadingSpinner, EuiTitle } from '@elastic/eui';
1111
import React from 'react';
1212
import { PartialFieldMetadataPlain } from '@kbn/fields-metadata-plugin/common';
13+
import { DataViewField } from '@kbn/data-views-plugin/common';
1314
import { FieldHoverActionPopover } from './field_hover_popover_action';
1415

1516
export interface FieldWithActionsProps {
1617
field: string;
1718
fieldMetadata?: PartialFieldMetadataPlain;
19+
fieldMapping?: DataViewField;
1820
formattedValue: string;
1921
label: string;
2022
value: string;
@@ -26,6 +28,7 @@ export interface FieldWithActionsProps {
2628
export function FieldWithActions({
2729
field,
2830
fieldMetadata,
31+
fieldMapping,
2932
formattedValue,
3033
label,
3134
value,
@@ -72,7 +75,12 @@ export function FieldWithActions({
7275

7376
<EuiFlexItem grow={2}>
7477
{showActions ? (
75-
<FieldHoverActionPopover title={value} value={value} field={field}>
78+
<FieldHoverActionPopover
79+
title={value}
80+
value={value}
81+
field={field}
82+
fieldMapping={fieldMapping}
83+
>
7684
{fieldContent}
7785
</FieldHoverActionPopover>
7886
) : (

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { EmbeddableRenderer } from '@kbn/embeddable-plugin/public';
1212
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle, EuiButtonIcon } from '@elastic/eui';
1313
import { i18n } from '@kbn/i18n';
1414
import { DocViewRenderProps } from '@kbn/unified-doc-viewer/types';
15+
import { DataViewField } from '@kbn/data-views-plugin/common';
1516
import { spanTraceFields } from '../doc_viewer_span_overview/resources/fields';
1617
import { transactionTraceFields } from '../doc_viewer_transaction_overview/resources/fields';
1718
import { SpanSummaryField } from '../doc_viewer_span_overview/sub_components/span_summary_field';
@@ -22,6 +23,7 @@ import { FullScreenWaterfall } from './full_screen_waterfall';
2223

2324
export interface TraceProps {
2425
fields: Record<string, FieldConfiguration>;
26+
fieldMappings: Record<string, DataViewField | undefined>;
2527
traceId: string;
2628
displayType: 'span' | 'transaction';
2729
docId: string;
@@ -34,6 +36,7 @@ export interface TraceProps {
3436
export const Trace = ({
3537
traceId,
3638
fields,
39+
fieldMappings,
3740
displayType,
3841
docId,
3942
dataView,
@@ -67,6 +70,7 @@ export const Trace = ({
6770
key={fieldId}
6871
fieldId={fieldId}
6972
fieldConfiguration={fields[fieldId]}
73+
fieldMapping={fieldMappings[fieldId]}
7074
showActions={showActions}
7175
/>
7276
))
@@ -75,6 +79,7 @@ export const Trace = ({
7579
key={fieldId}
7680
fieldId={fieldId}
7781
fieldConfiguration={fields[fieldId]}
82+
fieldMapping={fieldMappings[fieldId]}
7883
showActions={showActions}
7984
/>
8085
));

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_span_overview/resources/fields.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ export const spanFields = [
2828
];
2929

3030
export const spanTraceFields = [TRACE_ID_FIELD, TRANSACTION_NAME_FIELD];
31+
32+
export const allSpanFields = [...spanFields, ...spanTraceFields];

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_span_overview/span_overview.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ import { getFlattenedSpanDocumentOverview } from '@kbn/discover-utils/src';
2222
import { DocViewRenderProps } from '@kbn/unified-doc-viewer/types';
2323
import React, { useMemo } from 'react';
2424
import { FieldActionsProvider } from '../../../../hooks/use_field_actions';
25+
import { useDataViewFields } from '../../../../hooks/use_data_view_fields';
2526
import { getUnifiedDocViewerServices } from '../../../../plugin';
2627
import { Trace } from '../components/trace';
2728
import { RootSpanProvider } from './hooks/use_root_span';
28-
import { spanFields } from './resources/fields';
29+
import { spanFields, allSpanFields } from './resources/fields';
2930
import { getSpanFieldConfiguration } from './resources/get_span_field_configuration';
3031
import { SpanDurationSummary } from './sub_components/span_duration_summary';
3132
import { SpanSummaryField } from './sub_components/span_summary_field';
@@ -55,6 +56,7 @@ export function SpanOverview({
5556
showWaterfall = true,
5657
showActions = true,
5758
dataView,
59+
columnsMeta,
5860
}: SpanOverviewProps) {
5961
const { fieldFormats } = getUnifiedDocViewerServices();
6062
const { formattedDoc, flattenedDoc } = useMemo(
@@ -64,6 +66,7 @@ export function SpanOverview({
6466
}),
6567
[dataView, fieldFormats, hit]
6668
);
69+
const { dataViewFields } = useDataViewFields({ fields: allSpanFields, dataView, columnsMeta });
6770
const fieldConfigurations = useMemo(
6871
() => getSpanFieldConfiguration({ attributes: formattedDoc, flattenedDoc }),
6972
[formattedDoc, flattenedDoc]
@@ -110,6 +113,7 @@ export function SpanOverview({
110113
<SpanSummaryField
111114
key={fieldId}
112115
fieldId={fieldId}
116+
fieldMapping={dataViewFields[fieldId]}
113117
fieldConfiguration={fieldConfigurations[fieldId]}
114118
showActions={showActions}
115119
/>
@@ -130,6 +134,7 @@ export function SpanOverview({
130134
<EuiFlexItem>
131135
<Trace
132136
fields={fieldConfigurations}
137+
fieldMappings={dataViewFields}
133138
traceId={flattenedDoc[TRACE_ID_FIELD]}
134139
docId={flattenedDoc[SPAN_ID_FIELD]}
135140
displayType="span"

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_span_overview/sub_components/span_summary_field.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@
99

1010
import { TRANSACTION_NAME_FIELD } from '@kbn/discover-utils';
1111
import { EuiHorizontalRule } from '@elastic/eui';
12+
import type { DataViewField } from '@kbn/data-views-plugin/common';
1213
import React, { useState, useEffect } from 'react';
1314
import { FieldWithActions } from '../../components/field_with_actions/field_with_actions';
1415
import { useRootSpanContext } from '../hooks/use_root_span';
1516
import { FieldConfiguration } from '../../resources/get_field_configuration';
1617
export interface SpanSummaryFieldProps {
1718
fieldId: string;
1819
fieldConfiguration: FieldConfiguration;
20+
fieldMapping?: DataViewField;
1921
showActions?: boolean;
2022
}
2123

2224
export function SpanSummaryField({
2325
fieldConfiguration,
2426
fieldId,
27+
fieldMapping,
2528
showActions = true,
2629
}: SpanSummaryFieldProps) {
2730
const { trace, loading } = useRootSpanContext();
@@ -50,6 +53,7 @@ export function SpanSummaryField({
5053
field={fieldId}
5154
value={fieldValue as string}
5255
formattedValue={fieldValue as string}
56+
fieldMapping={fieldMapping}
5357
fieldMetadata={fieldConfiguration.fieldMetadata}
5458
loading={isTransactionNameFieldWithoutValue && loading}
5559
showActions={showActions}

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_transaction_overview/resources/fields.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ export const transactionFields = [
2525
];
2626

2727
export const transactionTraceFields = [TRACE_ID_FIELD];
28+
29+
export const allTransactionFields = [...transactionFields, ...transactionTraceFields];

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_transaction_overview/sub_components/transaction_summary_field.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@
99

1010
import { EuiHorizontalRule } from '@elastic/eui';
1111
import React from 'react';
12+
import { DataViewField } from '@kbn/data-views-plugin/common';
1213
import { FieldConfiguration } from '../../resources/get_field_configuration';
1314
import { FieldWithActions } from '../../components/field_with_actions/field_with_actions';
1415

1516
export interface TransactionSummaryFieldProps {
1617
fieldId: string;
1718
fieldConfiguration: FieldConfiguration;
19+
fieldMapping?: DataViewField;
1820
showActions?: boolean;
1921
}
2022

2123
export function TransactionSummaryField({
2224
fieldConfiguration,
2325
fieldId,
26+
fieldMapping,
2427
showActions = true,
2528
}: TransactionSummaryFieldProps) {
2629
if (!fieldConfiguration.value) {
@@ -33,6 +36,7 @@ export function TransactionSummaryField({
3336
data-test-subj={`unifiedDocViewerObservabilityTracesAttribute-${fieldId}`}
3437
label={fieldConfiguration.title}
3538
field={fieldId}
39+
fieldMapping={fieldMapping}
3640
value={fieldConfiguration.value as string}
3741
formattedValue={fieldConfiguration.value as string}
3842
fieldMetadata={fieldConfiguration.fieldMetadata}

src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/doc_viewer_transaction_overview/transaction_overview.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import {
2020
TRANSACTION_ID_FIELD,
2121
} from '@kbn/discover-utils';
2222
import { getFlattenedTransactionDocumentOverview } from '@kbn/discover-utils/src';
23+
import { useDataViewFields } from '../../../../hooks/use_data_view_fields';
2324
import { FieldActionsProvider } from '../../../../hooks/use_field_actions';
24-
import { transactionFields } from './resources/fields';
25+
import { transactionFields, allTransactionFields } from './resources/fields';
2526
import { getTransactionFieldConfiguration } from './resources/get_transaction_field_configuration';
2627
import { TransactionSummaryField } from './sub_components/transaction_summary_field';
2728
import { TransactionDurationSummary } from './sub_components/transaction_duration_summary';
@@ -53,6 +54,7 @@ export function TransactionOverview({
5354
showWaterfall = true,
5455
showActions = true,
5556
dataView,
57+
columnsMeta,
5658
}: TransactionOverviewProps) {
5759
const { fieldFormats } = getUnifiedDocViewerServices();
5860
const { formattedDoc, flattenedDoc } = useMemo(
@@ -62,7 +64,11 @@ export function TransactionOverview({
6264
}),
6365
[dataView, fieldFormats, hit]
6466
);
65-
67+
const { dataViewFields } = useDataViewFields({
68+
fields: allTransactionFields,
69+
dataView,
70+
columnsMeta,
71+
});
6672
const transactionDuration = flattenedDoc[TRANSACTION_DURATION_FIELD];
6773
const fieldConfigurations = useMemo(
6874
() => getTransactionFieldConfiguration({ attributes: formattedDoc, flattenedDoc }),
@@ -98,6 +104,7 @@ export function TransactionOverview({
98104
<TransactionSummaryField
99105
key={fieldId}
100106
fieldId={fieldId}
107+
fieldMapping={dataViewFields[fieldId]}
101108
fieldConfiguration={fieldConfigurations[fieldId]}
102109
showActions={showActions}
103110
/>
@@ -117,6 +124,7 @@ export function TransactionOverview({
117124
{traceId && transactionId && (
118125
<Trace
119126
fields={fieldConfigurations}
127+
fieldMappings={dataViewFields}
120128
traceId={traceId}
121129
docId={transactionId}
122130
displayType="transaction"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
import { useMemo } from 'react';
10+
import type { DataView, DataViewField } from '@kbn/data-views-plugin/common';
11+
import type { DataTableColumnsMeta } from '@kbn/discover-utils/types';
12+
import { getDataViewFieldOrCreateFromColumnMeta } from '@kbn/data-view-utils';
13+
14+
interface UseFieldTypesProps {
15+
fields: string[];
16+
dataView: DataView;
17+
columnsMeta?: DataTableColumnsMeta;
18+
}
19+
20+
export const useDataViewFields = ({
21+
fields,
22+
dataView,
23+
columnsMeta,
24+
}: UseFieldTypesProps): { dataViewFields: Record<string, DataViewField | undefined> } => {
25+
const dataViewFields = useMemo(
26+
() =>
27+
fields.reduce((acc, fieldName) => {
28+
acc[fieldName] = getDataViewFieldOrCreateFromColumnMeta({
29+
fieldName,
30+
dataView,
31+
columnMeta: columnsMeta?.[fieldName],
32+
});
33+
34+
return acc;
35+
}, {} as Record<string, DataViewField | undefined>),
36+
[fields, dataView, columnsMeta]
37+
);
38+
39+
return { dataViewFields };
40+
};

0 commit comments

Comments
 (0)