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')); }); }