diff --git a/packages/kbn-unified-data-table/src/types.ts b/packages/kbn-unified-data-table/src/types.ts
index 8f5d5e9a4035d..5914fa03f8827 100644
--- a/packages/kbn-unified-data-table/src/types.ts
+++ b/packages/kbn-unified-data-table/src/types.ts
@@ -6,12 +6,12 @@
* Side Public License, v 1.
*/
-import React from 'react';
-import { EuiDataGridCellValueElementProps, type EuiDataGridColumn } from '@elastic/eui';
+import type { ReactElement } from 'react';
+import type { EuiDataGridCellValueElementProps, EuiDataGridColumn } from '@elastic/eui';
import type { DataTableRecord } from '@kbn/discover-utils/src/types';
import type { DataView } from '@kbn/data-views-plugin/common';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
-import { EuiDataGridControlColumn } from '@elastic/eui/src/components/datagrid/data_grid_types';
+import type { EuiDataGridControlColumn } from '@elastic/eui/src/components/datagrid/data_grid_types';
import type { DatatableColumnMeta } from '@kbn/expressions-plugin/common';
/**
@@ -57,7 +57,7 @@ export type DataGridCellValueElementProps = EuiDataGridCellValueElementProps & {
export type CustomCellRenderer = Record<
string,
- (props: DataGridCellValueElementProps) => React.ReactNode
+ (props: DataGridCellValueElementProps) => ReactElement
>;
export interface CustomGridColumnProps {
diff --git a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx
index 35234bdb58d8f..6a10b0950946d 100644
--- a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx
+++ b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx
@@ -78,22 +78,24 @@ export const getRenderCellValueFn = ({
return -;
}
- if (!!externalCustomRenderers && !!externalCustomRenderers[columnId]) {
+ const CustomCellRenderer = externalCustomRenderers?.[columnId];
+
+ if (CustomCellRenderer) {
return (
- {externalCustomRenderers[columnId]({
- rowIndex,
- columnId,
- isDetails,
- setCellProps,
- isExpandable,
- isExpanded,
- colIndex,
- row,
- dataView,
- fieldFormats,
- closePopover,
- })}
+
);
}
diff --git a/src/plugins/discover/common/data_types/logs/constants.ts b/src/plugins/discover/common/data_types/logs/constants.ts
index 5726bf8439b8f..560692395a6a8 100644
--- a/src/plugins/discover/common/data_types/logs/constants.ts
+++ b/src/plugins/discover/common/data_types/logs/constants.ts
@@ -63,3 +63,5 @@ export const FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT = [
export const DEFAULT_ALLOWED_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat'];
export const DEFAULT_ALLOWED_LOGS_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat'];
+
+export const LOG_LEVEL_FIELDS = ['log.level', 'log_level'];
diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx
new file mode 100644
index 0000000000000..01ef28c46abfd
--- /dev/null
+++ b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx
@@ -0,0 +1,63 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { buildDataTableRecord, DataTableRecord } from '@kbn/discover-utils';
+import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
+import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks';
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { getLogLevelBadgeCell } from './log_level_badge_cell';
+
+const renderCell = (logLevelField: string, record: DataTableRecord) => {
+ const LogLevelBadgeCell = getLogLevelBadgeCell(logLevelField);
+ render(
+ {}}
+ closePopover={() => {}}
+ />
+ );
+};
+
+describe('getLogLevelBadgeCell', () => {
+ it('renders badge with color based on provided logLevelField', () => {
+ const record = buildDataTableRecord({ fields: { 'log.level': 'info' } }, dataViewMock);
+ renderCell('log.level', record);
+ const badge = screen.getByTestId('logLevelBadgeCell-info');
+ expect(badge).toBeInTheDocument();
+ expect(badge).toHaveTextContent('info');
+ expect(getComputedStyle(badge).getPropertyValue('--euiBadgeBackgroundColor')).toEqual(
+ '#90b0d1'
+ );
+ });
+
+ it('renders unknown badge if logLevelField is not recognized', () => {
+ const record = buildDataTableRecord({ fields: { 'log.level': 'unknown_level' } }, dataViewMock);
+ renderCell('log.level', record);
+ const badge = screen.getByTestId('logLevelBadgeCell-unknown');
+ expect(badge).toBeInTheDocument();
+ expect(badge).toHaveTextContent('unknown_level');
+ expect(getComputedStyle(badge).getPropertyValue('--euiBadgeBackgroundColor')).toEqual('');
+ });
+
+ it('renders empty if no matching logLevelField is found', () => {
+ const record = buildDataTableRecord({ fields: { 'log.level': 'info' } }, dataViewMock);
+ renderCell('log_level', record);
+ const badge = screen.getByTestId('logLevelBadgeCell-empty');
+ expect(badge).toBeInTheDocument();
+ expect(badge).toHaveTextContent('-');
+ });
+});
diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx
new file mode 100644
index 0000000000000..ea567b93f9a12
--- /dev/null
+++ b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx
@@ -0,0 +1,42 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { EuiBadge, mathWithUnits, useEuiTheme } from '@elastic/eui';
+import type { CSSObject } from '@emotion/react';
+import { getLogLevelCoalescedValue, getLogLevelColor } from '@kbn/discover-utils';
+import { euiThemeVars } from '@kbn/ui-theme';
+import type { DataGridCellValueElementProps } from '@kbn/unified-data-table';
+import React from 'react';
+
+const badgeCss: CSSObject = {
+ marginTop: '-4px',
+ maxWidth: mathWithUnits(euiThemeVars.euiSize, (size) => size * 7.5),
+};
+
+export const getLogLevelBadgeCell =
+ (logLevelField: string) => (props: DataGridCellValueElementProps) => {
+ const { euiTheme } = useEuiTheme();
+ const value = props.row.flattened[logLevelField];
+
+ if (!value) {
+ return -;
+ }
+
+ const coalescedValue = getLogLevelCoalescedValue(value);
+ const color = coalescedValue ? getLogLevelColor(coalescedValue, euiTheme) : undefined;
+
+ if (!color || !coalescedValue) {
+ return {value};
+ }
+
+ return (
+
+ {value}
+
+ );
+ };
diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.ts b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx
similarity index 96%
rename from src/plugins/discover/public/context_awareness/__mocks__/index.ts
rename to src/plugins/discover/public/context_awareness/__mocks__/index.tsx
index fbdb13a2e5648..9e94c4b9b4857 100644
--- a/src/plugins/discover/public/context_awareness/__mocks__/index.ts
+++ b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx
@@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
+import React from 'react';
import { getDataTableRecords } from '../../__fixtures__/real_hits';
import { dataViewWithTimefieldMock } from '../../__mocks__/data_view_with_timefield';
import {
@@ -30,7 +31,7 @@ export const createContextAwarenessMocks = ({
profile: {
getCellRenderers: jest.fn((prev) => () => ({
...prev(),
- rootProfile: () => 'root-profile',
+ rootProfile: () => <>root-profile>,
})),
},
resolve: jest.fn(() => ({
@@ -46,7 +47,7 @@ export const createContextAwarenessMocks = ({
profile: {
getCellRenderers: jest.fn((prev) => () => ({
...prev(),
- rootProfile: () => 'data-source-profile',
+ rootProfile: () => <>data-source-profile>,
})),
},
resolve: jest.fn(() => ({
diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx
new file mode 100644
index 0000000000000..c9c75dfdb0cd5
--- /dev/null
+++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx
@@ -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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { LOG_LEVEL_FIELDS } from '../../../../../common/data_types/logs/constants';
+import { getLogLevelBadgeCell } from '../../../../components/data_types/logs/log_level_badge_cell';
+import type { DataSourceProfileProvider } from '../../../profiles';
+
+export const getCellRenderers: DataSourceProfileProvider['profile']['getCellRenderers'] =
+ (prev) => () => ({
+ ...prev(),
+ ...LOG_LEVEL_FIELDS.reduce(
+ (acc, field) => ({
+ ...acc,
+ [field]: getLogLevelBadgeCell(field),
+ [`${field}.keyword`]: getLogLevelBadgeCell(`${field}.keyword`),
+ }),
+ {}
+ ),
+ });
diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts
index 7980453181377..4edaa1311624b 100644
--- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts
+++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts
@@ -12,10 +12,9 @@ import {
getLogLevelColor,
} from '@kbn/discover-utils';
import type { UnifiedDataTableProps } from '@kbn/unified-data-table';
+import { LOG_LEVEL_FIELDS } from '../../../../../common/data_types/logs/constants';
import type { DataSourceProfileProvider } from '../../../profiles';
-const LOG_LEVEL_FIELDS = ['log.level', 'log_level'];
-
export const getRowIndicatorProvider: DataSourceProfileProvider['profile']['getRowIndicatorProvider'] =
() =>
diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts
index cf544aa298093..12522bbf915c6 100644
--- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts
+++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts
@@ -7,3 +7,4 @@
*/
export { getRowIndicatorProvider } from './get_row_indicator_provider';
+export { getCellRenderers } from './get_cell_renderers';
diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts
index 793af0a16e1b6..fe93ea90d0fd7 100644
--- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts
+++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts
@@ -78,32 +78,32 @@ describe('logsDataSourceProfileProvider', () => {
).toEqual(RESOLUTION_MISMATCH);
});
- describe('getRowIndicator', () => {
- const dataViewWithLogLevel = createStubIndexPattern({
- spec: {
- title: VALID_INDEX_PATTERN,
- fields: {
- 'log.level': {
- name: 'log.level',
- type: 'string',
- esTypes: ['keyword'],
- aggregatable: true,
- searchable: true,
- count: 0,
- readFromDocValues: false,
- scripted: false,
- isMapped: true,
- },
+ const dataViewWithLogLevel = createStubIndexPattern({
+ spec: {
+ title: VALID_INDEX_PATTERN,
+ fields: {
+ 'log.level': {
+ name: 'log.level',
+ type: 'string',
+ esTypes: ['keyword'],
+ aggregatable: true,
+ searchable: true,
+ count: 0,
+ readFromDocValues: false,
+ scripted: false,
+ isMapped: true,
},
},
- });
+ },
+ });
- const dataViewWithoutLogLevel = createStubIndexPattern({
- spec: {
- title: VALID_INDEX_PATTERN,
- },
- });
+ const dataViewWithoutLogLevel = createStubIndexPattern({
+ spec: {
+ title: VALID_INDEX_PATTERN,
+ },
+ });
+ describe('getRowIndicator', () => {
it('should return the correct color for a given log level', () => {
const row = buildDataTableRecord({ fields: { 'log.level': 'info' } });
const euiTheme = { euiTheme: { colors: {} } } as unknown as EuiThemeComputed;
@@ -140,4 +140,17 @@ describe('logsDataSourceProfileProvider', () => {
expect(getRowIndicator).toBeUndefined();
});
});
+
+ describe('getCellRenderers', () => {
+ it('should return cell renderers for log level fields', () => {
+ const getCellRenderers = logsDataSourceProfileProvider.profile.getCellRenderers?.(() => ({}));
+ const cellRenderers = getCellRenderers?.();
+
+ expect(cellRenderers).toBeDefined();
+ expect(cellRenderers?.['log.level']).toBeDefined();
+ expect(cellRenderers?.['log.level.keyword']).toBeDefined();
+ expect(cellRenderers?.log_level).toBeDefined();
+ expect(cellRenderers?.['log_level.keyword']).toBeDefined();
+ });
+ });
});
diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts
index f32af6df8dc75..17f53f30f397b 100644
--- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts
+++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts
@@ -16,6 +16,7 @@ import {
} from '../../profiles';
import { ProfileProviderServices } from '../profile_provider_services';
import { getRowIndicatorProvider } from './accessors';
+import { getCellRenderers } from './accessors';
export const createLogsDataSourceProfileProvider = (
services: ProfileProviderServices
@@ -23,6 +24,7 @@ export const createLogsDataSourceProfileProvider = (
profileId: 'logs-data-source-profile',
profile: {
getRowIndicatorProvider,
+ getCellRenderers,
},
resolve: (params) => {
const indexPattern = extractIndexPatternFrom(params);
diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts
new file mode 100644
index 0000000000000..eadb9db7fd708
--- /dev/null
+++ b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts
@@ -0,0 +1,98 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import kbnRison from '@kbn/rison';
+import expect from '@kbn/expect';
+import type { FtrProviderContext } from '../../ftr_provider_context';
+
+export default function ({ getService, getPageObjects }: FtrProviderContext) {
+ const PageObjects = getPageObjects(['common', 'discover', 'unifiedFieldList']);
+ const esArchiver = getService('esArchiver');
+ const testSubjects = getService('testSubjects');
+ const dataGrid = getService('dataGrid');
+ const dataViews = getService('dataViews');
+ const queryBar = getService('queryBar');
+
+ describe('extension getCellRenderers', () => {
+ before(async () => {
+ await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
+ });
+
+ after(async () => {
+ await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional');
+ });
+
+ describe('ES|QL mode', () => {
+ it('should render log.level badge cell', async () => {
+ const state = kbnRison.encode({
+ dataSource: { type: 'esql' },
+ query: {
+ esql: 'from my-example-logs,logstash* | sort @timestamp desc | where `log.level` is not null',
+ },
+ });
+ await PageObjects.common.navigateToApp('discover', {
+ hash: `/?_a=${state}`,
+ });
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0);
+ const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-');
+ expect(await logLevelBadge.getVisibleText()).to.be('debug');
+ expect(await logLevelBadge.getComputedStyle('background-color')).to.be(
+ 'rgba(190, 207, 227, 1)'
+ );
+ });
+
+ it("should not render log.level badge cell if it's not a logs data source", async () => {
+ const state = kbnRison.encode({
+ dataSource: { type: 'esql' },
+ query: {
+ esql: 'from my-example* | sort @timestamp desc | where `log.level` is not null',
+ },
+ });
+ await PageObjects.common.navigateToApp('discover', {
+ hash: `/?_a=${state}`,
+ });
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0);
+ expect(await firstCell.getVisibleText()).to.be('debug');
+ await testSubjects.missingOrFail('*logLevelBadgeCell-');
+ });
+ });
+
+ describe('data view mode', () => {
+ it('should render log.level badge cell', async () => {
+ await PageObjects.common.navigateToApp('discover');
+ await dataViews.switchTo('my-example-logs,logstash*');
+ await queryBar.setQuery('log.level:*');
+ await queryBar.submitQuery();
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1);
+ const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-');
+ expect(await logLevelBadge.getVisibleText()).to.be('debug');
+ expect(await logLevelBadge.getComputedStyle('background-color')).to.be(
+ 'rgba(190, 207, 227, 1)'
+ );
+ });
+
+ it("should not render log.level badge cell if it's not a logs data source", async () => {
+ await PageObjects.common.navigateToApp('discover');
+ await dataViews.switchTo('my-example-*');
+ await queryBar.setQuery('log.level:*');
+ await queryBar.submitQuery();
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1);
+ expect(await firstCell.getVisibleText()).to.be('debug');
+ await testSubjects.missingOrFail('*logLevelBadgeCell-');
+ });
+ });
+ });
+}
diff --git a/test/functional/apps/discover/context_awareness/index.ts b/test/functional/apps/discover/context_awareness/index.ts
index b642bcbce7476..3fdd8ab799266 100644
--- a/test/functional/apps/discover/context_awareness/index.ts
+++ b/test/functional/apps/discover/context_awareness/index.ts
@@ -37,5 +37,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid
loadTestFile(require.resolve('./_data_source_profile'));
loadTestFile(require.resolve('./extensions/_get_row_indicator_provider'));
loadTestFile(require.resolve('./extensions/_get_doc_viewer'));
+ loadTestFile(require.resolve('./extensions/_get_cell_renderers'));
});
}
diff --git a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json
index a4a086afc11ce..96388bf2cd384 100644
--- a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json
+++ b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json
@@ -71,4 +71,29 @@
"updated_at": "2024-06-12T22:23:21.331Z",
"updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0",
"version": "WzEwLDFc"
+}
+
+{
+ "attributes": {
+ "allowHidden": false,
+ "fieldAttrs": "{}",
+ "fieldFormatMap": "{}",
+ "fields": "[]",
+ "name": "my-example-logs,logstash*",
+ "runtimeFieldMap": "{}",
+ "sourceFilters": "[]",
+ "timeFieldName": "@timestamp",
+ "title": "my-example-logs,logstash*"
+ },
+ "coreMigrationVersion": "8.8.0",
+ "created_at": "2024-06-12T22:23:41.331Z",
+ "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0",
+ "id": "795df528-add1-491a-8e25-72a862c4bf4e",
+ "managed": false,
+ "references": [],
+ "type": "index-pattern",
+ "typeMigrationVersion": "8.0.0",
+ "updated_at": "2024-06-12T22:23:41.331Z",
+ "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0",
+ "version": "WzEwLDFd"
}
\ No newline at end of file
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx
index 545a198593fe8..bd0c01019d63c 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx
@@ -6,6 +6,7 @@
*/
import type { EuiDataGridCellValueElementProps } from '@elastic/eui';
+import type { ReactElement } from 'react';
import React from 'react';
import type { ColumnHeaderOptions, TimelineItem } from '@kbn/timelines-plugin/common';
@@ -23,7 +24,7 @@ export const getFormattedFields = ({
}) => {
return headers.reduce(
(
- obj: Record React.ReactNode>,
+ obj: Record ReactElement>,
header: ColumnHeaderOptions
) => {
obj[header.id] = function UnifiedFieldRender(props: EuiDataGridCellValueElementProps) {
diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts
new file mode 100644
index 0000000000000..2a81561199f47
--- /dev/null
+++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts
@@ -0,0 +1,97 @@
+/*
+ * 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 kbnRison from '@kbn/rison';
+import expect from '@kbn/expect';
+import type { FtrProviderContext } from '../../../../../ftr_provider_context';
+
+export default function ({ getService, getPageObjects }: FtrProviderContext) {
+ const PageObjects = getPageObjects(['common', 'discover', 'unifiedFieldList']);
+ const esArchiver = getService('esArchiver');
+ const testSubjects = getService('testSubjects');
+ const dataGrid = getService('dataGrid');
+ const dataViews = getService('dataViews');
+ const queryBar = getService('queryBar');
+
+ describe('extension getCellRenderers', () => {
+ before(async () => {
+ await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
+ });
+
+ after(async () => {
+ await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional');
+ });
+
+ describe('ES|QL mode', () => {
+ it('should render log.level badge cell', async () => {
+ const state = kbnRison.encode({
+ dataSource: { type: 'esql' },
+ query: {
+ esql: 'from my-example-logs,logstash* | sort @timestamp desc | where `log.level` is not null',
+ },
+ });
+ await PageObjects.common.navigateToApp('discover', {
+ hash: `/?_a=${state}`,
+ });
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0);
+ const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-');
+ expect(await logLevelBadge.getVisibleText()).to.be('debug');
+ expect(await logLevelBadge.getComputedStyle('background-color')).to.be(
+ 'rgba(190, 207, 227, 1)'
+ );
+ });
+
+ it("should not render log.level badge cell if it's not a logs data source", async () => {
+ const state = kbnRison.encode({
+ dataSource: { type: 'esql' },
+ query: {
+ esql: 'from my-example* | sort @timestamp desc | where `log.level` is not null',
+ },
+ });
+ await PageObjects.common.navigateToApp('discover', {
+ hash: `/?_a=${state}`,
+ });
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0);
+ expect(await firstCell.getVisibleText()).to.be('debug');
+ await testSubjects.missingOrFail('*logLevelBadgeCell-');
+ });
+ });
+
+ describe('data view mode', () => {
+ it('should render log.level badge cell', async () => {
+ await PageObjects.common.navigateToApp('discover');
+ await dataViews.switchTo('my-example-logs,logstash*');
+ await queryBar.setQuery('log.level:*');
+ await queryBar.submitQuery();
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1);
+ const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-');
+ expect(await logLevelBadge.getVisibleText()).to.be('debug');
+ expect(await logLevelBadge.getComputedStyle('background-color')).to.be(
+ 'rgba(190, 207, 227, 1)'
+ );
+ });
+
+ it("should not render log.level badge cell if it's not a logs data source", async () => {
+ await PageObjects.common.navigateToApp('discover');
+ await dataViews.switchTo('my-example-*');
+ await queryBar.setQuery('log.level:*');
+ await queryBar.submitQuery();
+ await PageObjects.discover.waitUntilSearchingHasFinished();
+ await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level');
+ const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1);
+ expect(await firstCell.getVisibleText()).to.be('debug');
+ await testSubjects.missingOrFail('*logLevelBadgeCell-');
+ });
+ });
+ });
+}
diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts
index d5bd7a44f2c98..49a046a73dbe3 100644
--- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts
+++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts
@@ -40,5 +40,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid
loadTestFile(require.resolve('./_data_source_profile'));
loadTestFile(require.resolve('./extensions/_get_row_indicator_provider'));
loadTestFile(require.resolve('./extensions/_get_doc_viewer'));
+ loadTestFile(require.resolve('./extensions/_get_cell_renderers'));
});
}