Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@ export interface UseAlertTagsActionsProps {
}

export const RUN_WORKFLOW_PANEL_ID = 'RUN_WORKFLOW_PANEL_ID';
export const RUN_WORKFLOW_BULK_PANEL_ID = 'BULK_RUN_WORKFLOW_PANEL_ID';

export interface AlertWorkflowAlertId {
_id: string;
_index: string;
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AlertWorkflowAlertId requires _index: string, but callers are currently constructing _index values via ?? '' (i.e., potentially passing an empty string). This weakens the contract and makes it unclear whether _index is truly required. Consider either (a) making _index optional in the type and handling missing values before mutation, or (b) enforcing non-empty _index at the call sites (e.g., filter/guard and surface a user-facing error).

Suggested change
_index: string;
_index?: string;

Copilot uses AI. Check for mistakes.
}

export interface AlertWorkflowsPanelProps {
closePopover: () => void;
ecsRowData: Ecs;
alertIds: AlertWorkflowAlertId[];
onClose: () => void;
}

export const AlertWorkflowsPanel = ({ closePopover, ecsRowData }: AlertWorkflowsPanelProps) => {
export const AlertWorkflowsPanel = ({ alertIds, onClose }: AlertWorkflowsPanelProps) => {
const {
services: { application, rendering },
} = useKibana<{ application: ApplicationStart }>();
Expand All @@ -54,7 +60,7 @@ export const AlertWorkflowsPanel = ({ closePopover, ecsRowData }: AlertWorkflows
const inputsPayload: AlertTriggerInput = {
event: {
triggerType: 'alert',
alertIds: [{ _id: ecsRowData._id, _index: ecsRowData._index ?? '' }],
alertIds,
},
};

Expand Down Expand Up @@ -94,7 +100,7 @@ export const AlertWorkflowsPanel = ({ closePopover, ecsRowData }: AlertWorkflows
},
onSettled: () => {
setIsLoading(false);
closePopover();
onClose();
},
}
);
Expand All @@ -105,8 +111,8 @@ export const AlertWorkflowsPanel = ({ closePopover, ecsRowData }: AlertWorkflows
workflowTriggerSuccess,
workflowTriggerFailed,
rendering,
closePopover,
ecsRowData,
onClose,
alertIds,
]);

const isAlertWorkflow = (workflows: WorkflowListDto['results']): WorkflowListDto['results'] => {
Expand Down Expand Up @@ -168,7 +174,6 @@ export const useRunAlertWorkflowPanel = ({
'aria-label': i18n.CONTEXT_MENU_RUN_WORKFLOW,
'data-test-subj': 'run-workflow-action',
key: 'run-workflow-action',
onClick: () => {},
size: 's',
name: i18n.CONTEXT_MENU_RUN_WORKFLOW,
panel: RUN_WORKFLOW_PANEL_ID,
Expand All @@ -183,7 +188,12 @@ export const useRunAlertWorkflowPanel = ({
id: RUN_WORKFLOW_PANEL_ID,
title: i18n.SELECT_WORKFLOW_PANEL_TITLE,
'data-test-subj': 'alert-workflow-context-menu-panel',
content: <AlertWorkflowsPanel closePopover={closePopover} ecsRowData={ecsRowData} />,
content: (
<AlertWorkflowsPanel
alertIds={[{ _id: ecsRowData._id, _index: ecsRowData._index ?? '' }]}
onClose={closePopover}
/>
),
},
],
[closePopover, ecsRowData]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
BulkActionsPanelConfig,
ItemsPanelConfig,
} from '@kbn/response-ops-alerts-table/types';
import { useBulkRunAlertWorkflowPanel } from './use_bulk_run_alert_workflow_panel';
import { PageScope } from '../../../data_view_manager/constants';
import { useBulkAlertAssigneesItems } from '../../../common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items';
import { useBulkAlertTagsItems } from '../../../common/components/toolbar/bulk_actions/use_bulk_alert_tags_items';
Expand Down Expand Up @@ -132,10 +133,25 @@ export const useBulkActionsByTableType = (

const { alertTagsItems, alertTagsPanels } = useBulkAlertTagsItems(bulkAlertTagParams);

const { runWorkflowItems, runWorkflowPanels } = useBulkRunAlertWorkflowPanel();

const items = useMemo(() => {
return [...alertActions, ...timelineActions, ...alertTagsItems, ...alertAssigneesItems];
}, [alertActions, alertTagsItems, timelineActions, alertAssigneesItems]);
return [
...alertActions,
...runWorkflowItems,
...timelineActions,
...alertTagsItems,
...alertAssigneesItems,
];
}, [alertActions, alertTagsItems, timelineActions, alertAssigneesItems, runWorkflowItems]);

return useMemo(() => {
return [{ id: 0, items }, ...alertActionsPanels, ...alertTagsPanels, ...alertAssigneesPanels];
}, [alertActionsPanels, alertTagsPanels, items, alertAssigneesPanels]);
return [
{ id: 0, items },
...alertActionsPanels,
...runWorkflowPanels,
...alertTagsPanels,
...alertAssigneesPanels,
];
}, [alertActionsPanels, alertTagsPanels, items, alertAssigneesPanels, runWorkflowPanels]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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 type {
BulkActionsConfig,
ContentPanelConfig,
RenderContentPanelProps,
} from '@kbn/response-ops-alerts-table/types';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { ApplicationStart } from '@kbn/core-application-browser';
import { WORKFLOWS_UI_SETTING_ID } from '@kbn/workflows';
import React, { useCallback, useMemo } from 'react';
import * as i18n from '../../components/alerts_table/translations';
import { useAlertsPrivileges } from '../../containers/detection_engine/alerts/use_alerts_privileges';
import {
AlertWorkflowsPanel,
RUN_WORKFLOW_BULK_PANEL_ID,
} from '../../components/alerts_table/timeline_actions/use_run_alert_workflow_panel';

export const useBulkRunAlertWorkflowPanel = (): {
runWorkflowItems: BulkActionsConfig[];
runWorkflowPanels: ContentPanelConfig[];
} => {
const {
services: { uiSettings, application },
} = useKibana<{ application: ApplicationStart }>();

const workflowUIEnabled = uiSettings?.get<boolean>(WORKFLOWS_UI_SETTING_ID, false) ?? false;
const canExecuteWorkflow = application.capabilities.workflowsManagement?.executeWorkflow ?? false;
const { hasIndexWrite } = useAlertsPrivileges();

const renderContent = useCallback((props: RenderContentPanelProps) => {
const alertIds = props.alertItems.map((item) => ({
_id: item._id,
_index: item._index ?? '',
}));
Comment on lines +37 to +40
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_index is being defaulted to an empty string when missing. If the workflow trigger expects a valid {_id, _index} pair, sending '' can cause execution failures or incorrect behavior. Prefer filtering out items without _index (and optionally showing a toast), or change the alertId type/payload to allow an optional _index and handle that case explicitly before calling runWorkflow.

Suggested change
const alertIds = props.alertItems.map((item) => ({
_id: item._id,
_index: item._index ?? '',
}));
const alertIds = props.alertItems
.filter((item) => Boolean(item._index))
.map((item) => ({
_id: item._id,
_index: item._index!,
}));

Copilot uses AI. Check for mistakes.
return <AlertWorkflowsPanel alertIds={alertIds} onClose={props.closePopoverMenu} />;
}, []);

const runWorkflowItems = useMemo(
() =>
hasIndexWrite && workflowUIEnabled && canExecuteWorkflow
? [
{
key: 'bulk-run-alert-workflow',
'data-test-subj': 'bulk-run-alert-workflow-action',
label: i18n.CONTEXT_MENU_RUN_WORKFLOW,
name: i18n.CONTEXT_MENU_RUN_WORKFLOW,
panel: RUN_WORKFLOW_BULK_PANEL_ID,
disableOnQuery: false,
},
]
: [],
[hasIndexWrite, workflowUIEnabled, canExecuteWorkflow]
);

const runWorkflowPanels = useMemo(
() =>
hasIndexWrite && workflowUIEnabled && canExecuteWorkflow
? [
{
id: RUN_WORKFLOW_BULK_PANEL_ID,
title: i18n.SELECT_WORKFLOW_PANEL_TITLE,
'data-test-subj': 'bulk-alert-workflow-context-menu-panel',
renderContent,
},
]
: [],
[hasIndexWrite, workflowUIEnabled, canExecuteWorkflow, renderContent]
);
Comment on lines +44 to +74
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enablement condition hasIndexWrite && workflowUIEnabled && canExecuteWorkflow is duplicated across both memos. Consider extracting a single isRunWorkflowEnabled boolean (memoized or derived) and using it in both places to reduce duplication and prevent future drift between item/panel gating logic.

Copilot uses AI. Check for mistakes.

return { runWorkflowItems, runWorkflowPanels };
};
Loading