From 903f11f78238fbb06abe6b83f243226104c1db3a Mon Sep 17 00:00:00 2001 From: TFCMarques Date: Fri, 27 Mar 2026 16:40:32 +0000 Subject: [PATCH 1/5] fix missing highlights on logs profile --- .../components/summary_column/content.tsx | 12 +++-- .../summary_column/summary_column.tsx | 5 +- .../escape_preserve_highlight_tags.test.ts | 34 ++++++++++++-- .../utils/escape_preserve_highlight_tags.ts | 46 ++++++++++++++----- .../content_breakdown/content_breakdown.tsx | 7 ++- 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx index 1b39b8314bc23..a48855927796f 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/content.tsx @@ -100,6 +100,7 @@ export const Content = ({ }: ContentProps) => { // Use OTel fallback version that returns the actual field name used const { field, value } = getMessageFieldWithFallbacks(row.flattened); + const highlightSnippet = field ? row.raw.highlight?.[field]?.[0] : undefined; const { euiTheme } = useEuiTheme(); const isDarkTheme = useKibanaIsDarkMode(); @@ -107,9 +108,14 @@ export const Content = ({ const highlightedValue = useMemo( () => value - ? getHighlightedMessage(escapeAndPreserveHighlightTags(value), row, euiTheme, isDarkTheme) - : value, - [value, row, euiTheme, isDarkTheme] + ? getHighlightedMessage( + escapeAndPreserveHighlightTags(highlightSnippet ?? value), + row, + euiTheme, + isDarkTheme + ) + : undefined, + [value, highlightSnippet, row, euiTheme, isDarkTheme] ); const shouldRenderContent = !!field && !!value && !!highlightedValue; diff --git a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx index 02401aeb7c05c..6c39c5bb9b00d 100644 --- a/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx +++ b/src/platform/packages/shared/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/summary_column.tsx @@ -166,11 +166,14 @@ export const SummaryCellPopover = (props: AllSummaryColumnProps) => { const { field, value, formattedValue } = getMessageFieldWithFallbacks(row.flattened, { includeFormattedValue: true, }); + const highlightSnippet = field ? row.raw.highlight?.[field]?.[0] : undefined; const messageCodeBlockProps = formattedValue ? { language: 'json', children: formattedValue } : { language: 'txt', - dangerouslySetInnerHTML: { __html: escapeAndPreserveHighlightTags(value ?? '') }, + dangerouslySetInnerHTML: { + __html: escapeAndPreserveHighlightTags(highlightSnippet ?? value ?? ''), + }, }; const shouldRenderContent = Boolean(field && value); diff --git a/src/platform/packages/shared/kbn-discover-utils/src/utils/escape_preserve_highlight_tags.test.ts b/src/platform/packages/shared/kbn-discover-utils/src/utils/escape_preserve_highlight_tags.test.ts index ce6812ad357e1..3d8f16a866009 100644 --- a/src/platform/packages/shared/kbn-discover-utils/src/utils/escape_preserve_highlight_tags.test.ts +++ b/src/platform/packages/shared/kbn-discover-utils/src/utils/escape_preserve_highlight_tags.test.ts @@ -13,6 +13,10 @@ import { escapeAndPreserveHighlightTags } from './escape_preserve_highlight_tags const PRE = ''; const POST = ''; +// Must match the tags defined in @kbn/field-formats-plugin (highlight_tags.ts) +const ES_PRE = '@kibana-highlighted-field@'; +const ES_POST = '@/kibana-highlighted-field@'; + describe('escapeAndPreserveHighlightTags', () => { it('escapes HTML when there are no highlight tags', () => { expect(escapeAndPreserveHighlightTags('world')).toBe( @@ -26,15 +30,39 @@ describe('escapeAndPreserveHighlightTags', () => { ); }); - it('returns only escaped text when there are multiple highlight regions', () => { + it('preserves multiple highlight regions', () => { expect(escapeAndPreserveHighlightTags(`${PRE}hello${POST} + ${PRE}world${POST}`)).toBe( - 'hello + world' + `${PRE}hello${POST} + ${PRE}world${POST}` ); }); it('escapes plain tags that do not match the highlight format', () => { expect(escapeAndPreserveHighlightTags('')).toBe( - '<mark><hello>' + '<mark><hello></mark>' + ); + }); + + it('converts ES highlight tags to HTML mark tags with a single match', () => { + expect(escapeAndPreserveHighlightTags(`This is a ${ES_PRE}test${ES_POST} message`)).toBe( + `This is a ${PRE}test${POST} message` + ); + }); + + it('converts ES highlight tags to HTML mark tags with multiple matches', () => { + expect( + escapeAndPreserveHighlightTags(`${ES_PRE}hello${ES_POST} and ${ES_PRE}world${ES_POST}`) + ).toBe(`${PRE}hello${POST} and ${PRE}world${POST}`); + }); + + it('escapes HTML characters in non-highlighted text around ES tags', () => { + expect(escapeAndPreserveHighlightTags(`${ES_PRE}test${ES_POST}`)).toBe( + `<b>${PRE}test${POST}</b>` + ); + }); + + it('escapes HTML characters inside ES highlighted text', () => { + expect(escapeAndPreserveHighlightTags(`${ES_PRE}