diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/preview_table_cell_renderer.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/preview_table_cell_renderer.tsx index 68d40cd18128b..096346312e193 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/preview_table_cell_renderer.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/preview_table_cell_renderer.tsx @@ -5,23 +5,47 @@ * 2.0. */ -import type { ComponentProps } from 'react'; import React from 'react'; import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import { TableId } from '@kbn/securitysolution-data-table'; +import type { LegacyField } from '@kbn/alerting-types'; import type { CellValueElementProps } from '../../../../../common/types'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { CellValue } from '../../../../detections/configurations/security_solution_detections'; export const PreviewRenderCellValue: React.FC< EuiDataGridCellValueElementProps & CellValueElementProps -> = (props) => { +> = ({ + data, + ecsData, + setCellProps, + isExpandable, + isExpanded, + isDetails, + rowIndex, + colIndex, + columnId, + rowRenderers, + isDraggable, + truncate, +}) => { return ( )} - asPlainText={true} - scopeId={SourcererScopeName.detections} tableType={TableId.rulePreview} + scopeId={SourcererScopeName.detections} + legacyAlert={(data ?? []) as LegacyField[]} + ecsAlert={ecsData} + asPlainText={true} + setCellProps={setCellProps} + isExpandable={isExpandable} + isExpanded={isExpanded} + isDetails={isDetails} + rowIndex={rowIndex} + colIndex={colIndex} + columnId={columnId} + rowRenderers={rowRenderers} + isDraggable={isDraggable} + truncate={truncate} /> ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/types.ts b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/types.ts index 5422e78f1b80b..ee75ba69cc747 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/types.ts @@ -86,9 +86,9 @@ export type AlertTableContextMenuItem = EuiContextMenuPanelItemDescriptorEntry; export interface SecurityAlertsTableContext { tableType: TableId; - rowRenderers: RowRenderer[]; + rowRenderers?: RowRenderer[]; isDetails: boolean; - truncate: boolean; + truncate?: boolean; isDraggable: boolean; leadingControlColumn: ControlColumnProps; userProfiles: AlertsUserProfilesData; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx b/x-pack/solutions/security/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx index 05ed6114ea2f7..857265b6c7d62 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx @@ -5,8 +5,8 @@ * 2.0. */ +import React, { useMemo, memo, type ComponentProps } from 'react'; import { EuiIcon, EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { useMemo, memo } from 'react'; import { find, getOr } from 'lodash/fp'; import type { TimelineNonEcsData } from '@kbn/timelines-plugin/common'; import { tableDefaults, dataTableSelectors } from '@kbn/securitysolution-data-table'; @@ -35,157 +35,171 @@ import type { GetSecurityAlertsTableProp } from '../../components/alerts_table/t * from the TGrid */ -export const CellValue: GetSecurityAlertsTableProp<'renderCellValue'> = memo( - function RenderCellValue(props) { - const { - columnId, - rowIndex, - scopeId, - tableId, - tableType, - header, - legacyAlert, - ecsAlert, - linkValues, - rowRenderers, - isDetails, - isExpandable, - isDraggable = false, - isExpanded, - colIndex, - eventId, - setCellProps, - truncate, - context, - } = props; - const isTourAnchor = useMemo( - () => - columnId === SIGNAL_RULE_NAME_FIELD_NAME && - isDetectionsAlertsTable(tableType) && - rowIndex === 0 && - !props.isDetails, - [columnId, props.isDetails, rowIndex, tableType] - ); - const { browserFields } = useSourcererDataView(scopeId); - const browserFieldsByName = useMemo(() => getAllFieldsByName(browserFields), [browserFields]); - const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []); - const license = useLicense(); - const viewMode = - useDeepEqualSelector((state) => (getTable(state, tableId ?? '') ?? tableDefaults).viewMode) ?? - tableDefaults.viewMode; +type RenderCellValueProps = Pick< + ComponentProps>, + | 'columnId' + | 'rowIndex' + | 'tableId' + | 'tableType' + | 'legacyAlert' + | 'ecsAlert' + | 'rowRenderers' + | 'isDetails' + | 'isExpandable' + | 'isDraggable' + | 'isExpanded' + | 'colIndex' + | 'setCellProps' + | 'truncate' +> & + Record; - const gridColumns = useMemo(() => { - return getColumns(license); - }, [license]); +export const CellValue = memo(function RenderCellValue({ + columnId, + rowIndex, + scopeId, + tableId, + tableType, + header, + legacyAlert, + ecsAlert, + linkValues, + rowRenderers, + isDetails, + isExpandable, + isDraggable = false, + isExpanded, + colIndex, + eventId, + setCellProps, + truncate, + context, +}: RenderCellValueProps) { + const isTourAnchor = useMemo( + () => + columnId === SIGNAL_RULE_NAME_FIELD_NAME && + isDetectionsAlertsTable(tableType) && + rowIndex === 0 && + !isDetails, + [columnId, isDetails, rowIndex, tableType] + ); + const { browserFields } = useSourcererDataView(scopeId); + const browserFieldsByName = useMemo(() => getAllFieldsByName(browserFields), [browserFields]); + const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []); + const license = useLicense(); + const viewMode = + useDeepEqualSelector((state) => (getTable(state, tableId ?? '') ?? tableDefaults).viewMode) ?? + tableDefaults.viewMode; - const columnHeaders = useMemo(() => { - return viewMode === VIEW_SELECTION.gridView ? gridColumns : eventRenderedViewColumns; - }, [gridColumns, viewMode]); + const gridColumns = useMemo(() => { + return getColumns(license); + }, [license]); - /** - * There is difference between how `triggers actions` fetched data v/s - * how security solution fetches data via timelineSearchStrategy - * - * _id and _index fields are array in timelineSearchStrategy but not in - * ruleStrategy - * - * - */ + const columnHeaders = useMemo(() => { + return viewMode === VIEW_SELECTION.gridView ? gridColumns : eventRenderedViewColumns; + }, [gridColumns, viewMode]); - const finalData = useMemo(() => { - return (legacyAlert as TimelineNonEcsData[]).map((field) => { - if (['_id', '_index'].includes(field.field)) { - const newValue = field.value ?? ''; - return { - field: field.field, - value: Array.isArray(newValue) ? newValue : [newValue], - }; - } else { - return field; - } - }); - }, [legacyAlert]); + /** + * There is difference between how `triggers actions` fetched data v/s + * how security solution fetches data via timelineSearchStrategy + * + * _id and _index fields are array in timelineSearchStrategy but not in + * ruleStrategy + * + * + */ - const actualSuppressionCount = useMemo(() => { - // We check both ecsAlert and data for the suppression count because it could be in either one, - // depending on where RenderCellValue is being used - when used in cases, data is populated, - // whereas in the regular security alerts table it's in ecsAlert - const ecsSuppressionCount = ecsAlert?.kibana?.alert.suppression?.docs_count?.[0]; - const dataSuppressionCount = find( - { field: 'kibana.alert.suppression.docs_count' }, - legacyAlert - )?.value?.[0] as number | undefined; - return ecsSuppressionCount ? parseInt(ecsSuppressionCount, 10) : dataSuppressionCount; - }, [ecsAlert, legacyAlert]); + const finalData = useMemo(() => { + return (legacyAlert as TimelineNonEcsData[]).map((field) => { + if (['_id', '_index'].includes(field.field)) { + const newValue = field.value ?? ''; + return { + field: field.field, + value: Array.isArray(newValue) ? newValue : [newValue], + }; + } else { + return field; + } + }); + }, [legacyAlert]); - const Renderer = useMemo(() => { - const myHeader = header ?? { id: columnId, ...browserFieldsByName[columnId] }; - const colHeader = columnHeaders.find((col) => col.id === columnId); - const localLinkValues = getOr([], colHeader?.linkField ?? '', ecsAlert); - return ( - - - - ); - }, [ - header, - columnId, - browserFieldsByName, - columnHeaders, - ecsAlert, - isTourAnchor, - browserFields, - finalData, - eventId, - isDetails, - isDraggable, - isExpandable, - isExpanded, - linkValues, - rowIndex, - colIndex, - rowRenderers, - setCellProps, - scopeId, - truncate, - context, - ]); + const actualSuppressionCount = useMemo(() => { + // We check both ecsAlert and data for the suppression count because it could be in either one, + // depending on where RenderCellValue is being used - when used in cases, data is populated, + // whereas in the regular security alerts table it's in ecsAlert + const ecsSuppressionCount = ecsAlert?.kibana?.alert.suppression?.docs_count?.[0]; + const dataSuppressionCount = find({ field: 'kibana.alert.suppression.docs_count' }, legacyAlert) + ?.value?.[0] as number | undefined; + return ecsSuppressionCount ? parseInt(ecsSuppressionCount, 10) : dataSuppressionCount; + }, [ecsAlert, legacyAlert]); - return columnId === SIGNAL_RULE_NAME_FIELD_NAME && actualSuppressionCount ? ( - - - - - - - {Renderer} - - ) : ( - <>{Renderer} + const Renderer = useMemo(() => { + const myHeader = header ?? { id: columnId, ...browserFieldsByName[columnId] }; + const colHeader = columnHeaders.find((col) => col.id === columnId); + const localLinkValues = getOr([], colHeader?.linkField ?? '', ecsAlert); + return ( + + + ); - } -); + }, [ + header, + columnId, + browserFieldsByName, + columnHeaders, + ecsAlert, + isTourAnchor, + browserFields, + finalData, + eventId, + isDetails, + isDraggable, + isExpandable, + isExpanded, + linkValues, + rowIndex, + colIndex, + rowRenderers, + setCellProps, + scopeId, + truncate, + context, + ]); + + return columnId === SIGNAL_RULE_NAME_FIELD_NAME && actualSuppressionCount ? ( + + + + + + + {Renderer} + + ) : ( + <>{Renderer} + ); +});