From fa47c33140aa24dfde9dc5c3c1c3ebe71e3b68f2 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Tue, 10 Aug 2021 13:56:00 +0100 Subject: [PATCH] [Security Solution] Use alert status actions from timeline plugin (#107928) * use alert status from balk actions * remove unused comment * fix types * fix cypress test --- .../add_endpoint_exception.tsx | 4 +- .../timeline_actions/add_event_filter.tsx | 6 +- .../timeline_actions/add_exception.tsx | 6 +- .../timeline_actions/alert_context_menu.tsx | 61 +++++--- .../alerts_status_actions/close_status.tsx | 4 +- .../in_progress_alert_status.tsx | 4 +- .../open_alert_status.tsx | 4 +- .../use_add_exception_actions.tsx | 20 ++- .../timeline_actions/use_alerts_actions.tsx | 137 ++---------------- .../components/take_action_dropdown/index.tsx | 10 +- .../hooks/use_status_bulk_action_items.tsx | 18 ++- x-pack/plugins/timelines/public/index.ts | 2 +- x-pack/plugins/timelines/public/plugin.ts | 1 + 13 files changed, 104 insertions(+), 173 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_endpoint_exception.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_endpoint_exception.tsx index 23709269a4c13..7be51c4eaa41a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_endpoint_exception.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_endpoint_exception.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import * as i18n from '../translations'; @@ -27,7 +27,7 @@ const AddEndpointExceptionComponent: React.FC = ({ onClick={onClick} disabled={disabled} > - {i18n.ACTION_ADD_ENDPOINT_EXCEPTION} + {i18n.ACTION_ADD_ENDPOINT_EXCEPTION} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_event_filter.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_event_filter.tsx index 1104b3eb83081..9b14c01371c9b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_event_filter.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_event_filter.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import * as i18n from '../translations'; @@ -24,9 +24,7 @@ const AddEventFilterComponent: React.FC = ({ onClick, disab onClick={onClick} disabled={disabled} > - - {i18n.ACTION_ADD_EVENT_FILTER} - + {i18n.ACTION_ADD_EVENT_FILTER} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_exception.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_exception.tsx index 030f67c9e708c..99eef3aefd42c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_exception.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/add_exception.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import * as i18n from '../translations'; @@ -24,9 +24,7 @@ const AddExceptionComponent: React.FC = ({ disabled, onClick onClick={onClick} disabled={disabled} > - - {i18n.ACTION_ADD_EXCEPTION} - + {i18n.ACTION_ADD_EXCEPTION} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index 3a9a4e875369e..2dae69fec43e1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -7,8 +7,7 @@ import React, { useCallback, useMemo, useState } from 'react'; -import { EuiButtonIcon, EuiContextMenu, EuiPopover, EuiToolTip } from '@elastic/eui'; -import styled from 'styled-components'; +import { EuiButtonIcon, EuiContextMenuPanel, EuiPopover, EuiToolTip } from '@elastic/eui'; import { indexOf } from 'lodash'; import { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; @@ -31,8 +30,10 @@ import { useAlertsActions } from './use_alerts_actions'; import { useExceptionModal } from './use_add_exception_modal'; import { useExceptionActions } from './use_add_exception_actions'; import { useEventFilterModal } from './use_event_filter_modal'; -import { useEventFilterAction } from './use_event_filter_action'; import { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { AddEventFilter } from './add_event_filter'; +import { AddException } from './add_exception'; +import { AddEndpointException } from './add_endpoint_exception'; interface AlertContextMenuProps { ariaLabel?: string; @@ -112,7 +113,7 @@ const AlertContextMenuComponent: React.FC = ({ onAddEventFilterClick, } = useEventFilterModal(); - const { statusActions } = useAlertsActions({ + const { actionItems } = useAlertsActions({ alertStatus, eventId: ecsRowData?._id, timelineId, @@ -132,23 +133,41 @@ const AlertContextMenuComponent: React.FC = ({ closePopover(); }, [closePopover, onAddEventFilterClick]); - const exceptionActions = useExceptionActions({ + const { + disabledAddEndpointException, + disabledAddException, + handleEndpointExceptionModal, + handleDetectionExceptionModal, + } = useExceptionActions({ isEndpointAlert, onAddExceptionTypeClick: handleOnAddExceptionTypeClick, }); - const eventFilterActions = useEventFilterAction({ - onAddEventFilterClick: handleOnAddEventFilterClick, - }); - - const panels = useMemo( - () => [ - { - id: 0, - items: !isEvent && ruleId ? [...statusActions, ...exceptionActions] : [eventFilterActions], - }, - ], - [eventFilterActions, exceptionActions, isEvent, ruleId, statusActions] + const items = useMemo( + () => + !isEvent && ruleId + ? [ + ...actionItems, + , + , + ] + : [], + [ + actionItems, + disabledAddEndpointException, + disabledAddException, + handleDetectionExceptionModal, + handleEndpointExceptionModal, + handleOnAddEventFilterClick, + isEvent, + ruleId, + ] ); return ( @@ -164,7 +183,7 @@ const AlertContextMenuComponent: React.FC = ({ anchorPosition="downLeft" repositionOnScroll > - + @@ -191,12 +210,6 @@ const AlertContextMenuComponent: React.FC = ({ ); }; -const ContextMenuPanel = styled(EuiContextMenu)` - font-size: ${({ theme }) => theme.eui.euiFontSizeS}; -`; - -ContextMenuPanel.displayName = 'ContextMenuPanel'; - export const AlertContextMenu = React.memo(AlertContextMenuComponent); type AddExceptionModalWrapperProps = Omit< diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/close_status.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/close_status.tsx index 038d58c38a013..28a34c549ef16 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/close_status.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/close_status.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import { FILTER_CLOSED } from '../../alerts_filter_group'; import * as i18n from '../../translations'; @@ -25,7 +25,7 @@ const CloseAlertActionComponent: React.FC = ({ onClick, d onClick={onClick} disabled={disabled} > - {i18n.ACTION_CLOSE_ALERT} + {i18n.ACTION_CLOSE_ALERT} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/in_progress_alert_status.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/in_progress_alert_status.tsx index 2bca569032827..f273833c1c1b3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/in_progress_alert_status.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/in_progress_alert_status.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import { FILTER_IN_PROGRESS } from '../../alerts_filter_group'; import * as i18n from '../../translations'; @@ -28,7 +28,7 @@ const InProgressAlertStatusComponent: React.FC = ({ onClick={onClick} disabled={disabled} > - {i18n.ACTION_IN_PROGRESS_ALERT} + {i18n.ACTION_IN_PROGRESS_ALERT} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/open_alert_status.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/open_alert_status.tsx index 34832ee07ea75..2042acea4d604 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/open_alert_status.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alerts_status_actions/open_alert_status.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiContextMenuItem, EuiText } from '@elastic/eui'; +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; import { FILTER_OPEN } from '../../alerts_filter_group'; import * as i18n from '../../translations'; @@ -25,7 +25,7 @@ const OpenAlertStatusComponent: React.FC = ({ onClick, dis onClick={onClick} disabled={disabled} > - {i18n.ACTION_OPEN_ALERT} + {i18n.ACTION_OPEN_ALERT} ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx index 0f8fa00a3ac40..9f1f699241e21 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_exception_actions.tsx @@ -11,12 +11,20 @@ import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { useUserData } from '../../user_info'; import { ACTION_ADD_ENDPOINT_EXCEPTION, ACTION_ADD_EXCEPTION } from '../translations'; -interface UseExceptionActions { +interface ExceptionActions { name: string; onClick: () => void; disabled: boolean; } +interface UseExceptionActions { + disabledAddEndpointException: boolean; + disabledAddException: boolean; + exceptionActions: ExceptionActions[]; + handleEndpointExceptionModal: () => void; + handleDetectionExceptionModal: () => void; +} + interface UseExceptionActionProps { isEndpointAlert: boolean; onAddExceptionTypeClick: (type: ExceptionListType) => void; @@ -25,7 +33,7 @@ interface UseExceptionActionProps { export const useExceptionActions = ({ isEndpointAlert, onAddExceptionTypeClick, -}: UseExceptionActionProps): UseExceptionActions[] => { +}: UseExceptionActionProps): UseExceptionActions => { const [{ canUserCRUD, hasIndexWrite }] = useUserData(); const handleDetectionExceptionModal = useCallback(() => { @@ -62,5 +70,11 @@ export const useExceptionActions = ({ ] ); - return exceptionActions; + return { + disabledAddEndpointException, + disabledAddException, + exceptionActions, + handleEndpointExceptionModal, + handleDetectionExceptionModal, + }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx index 855eb2dd5fef4..4fdebee6e1f4d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alerts_actions.tsx @@ -5,14 +5,12 @@ * 2.0. */ -import { useCallback, useMemo } from 'react'; +import { useCallback } from 'react'; import { useDispatch } from 'react-redux'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; import { timelineActions } from '../../../../timelines/store/timeline'; -import { FILTER_OPEN, FILTER_CLOSED, FILTER_IN_PROGRESS } from '../alerts_filter_group'; -import { updateAlertStatusAction } from '../actions'; import { SetEventsDeletedProps, SetEventsLoadingProps } from '../types'; import * as i18nCommon from '../../../../common/translations'; import * as i18n from '../translations'; @@ -22,12 +20,12 @@ import { displaySuccessToast, displayErrorToast, } from '../../../../common/components/toasters'; -import { useUserData } from '../../user_info'; +import { useStatusBulkActionItems } from '../../../../../../timelines/public'; interface Props { - alertStatus?: string; + alertStatus?: Status; closePopover: () => void; - eventId: string | null | undefined; + eventId: string; timelineId: string; } @@ -37,10 +35,9 @@ export const useAlertsActions = ({ alertStatus, closePopover, eventId, timelineI const { addWarning } = useAppToasts(); - const [{ canUserCRUD, hasIndexMaintenance, hasIndexUpdateDelete }] = useUserData(); - const onAlertStatusUpdateSuccess = useCallback( (updated: number, conflicts: number, newStatus: Status) => { + closePopover(); if (conflicts > 0) { // Partial failure addWarning({ @@ -63,12 +60,14 @@ export const useAlertsActions = ({ alertStatus, closePopover, eventId, timelineI displaySuccessToast(title, dispatchToaster); } }, - [addWarning, dispatchToaster] + [addWarning, closePopover, dispatchToaster] ); const onAlertStatusUpdateFailure = useCallback( (newStatus: Status, error: Error) => { let title: string; + closePopover(); + switch (newStatus) { case 'closed': title = i18n.CLOSED_ALERT_FAILED_TOAST; @@ -81,7 +80,7 @@ export const useAlertsActions = ({ alertStatus, closePopover, eventId, timelineI } displayErrorToast(title, [error.message], dispatchToaster); }, - [dispatchToaster] + [closePopover, dispatchToaster] ); const setEventsLoading = useCallback( @@ -98,120 +97,16 @@ export const useAlertsActions = ({ alertStatus, closePopover, eventId, timelineI [dispatch, timelineId] ); - const openAlertActionOnClick = useCallback(() => { - if (eventId) { - updateAlertStatusAction({ - alertIds: [eventId], - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, - setEventsDeleted, - setEventsLoading, - selectedStatus: FILTER_OPEN, - }); - } - closePopover(); - }, [ - closePopover, - eventId, - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, - setEventsDeleted, - setEventsLoading, - ]); - - const closeAlertActionClick = useCallback(() => { - if (eventId) { - updateAlertStatusAction({ - alertIds: [eventId], - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, - setEventsDeleted, - setEventsLoading, - selectedStatus: FILTER_CLOSED, - }); - } - - closePopover(); - }, [ - closePopover, - eventId, - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, - setEventsDeleted, + const actionItems = useStatusBulkActionItems({ + eventIds: [eventId], + currentStatus: alertStatus, setEventsLoading, - ]); - - const inProgressAlertActionClick = useCallback(() => { - if (eventId) { - updateAlertStatusAction({ - alertIds: [eventId], - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, - setEventsDeleted, - setEventsLoading, - selectedStatus: FILTER_IN_PROGRESS, - }); - } - - closePopover(); - }, [ - closePopover, - eventId, - onAlertStatusUpdateFailure, - onAlertStatusUpdateSuccess, setEventsDeleted, - setEventsLoading, - ]); - - const disabledInProgressAlertAction = !canUserCRUD || !hasIndexUpdateDelete; - - const inProgressAlertAction = useMemo(() => { - return { - name: i18n.ACTION_IN_PROGRESS_ALERT, - disabled: disabledInProgressAlertAction, - onClick: inProgressAlertActionClick, - [`data-test-subj`]: 'in-progress-alert-status', - }; - }, [disabledInProgressAlertAction, inProgressAlertActionClick]); - - const disabledCloseAlertAction = !hasIndexUpdateDelete && !hasIndexMaintenance; - const closeAlertAction = useMemo(() => { - return { - name: i18n.ACTION_CLOSE_ALERT, - disabled: disabledCloseAlertAction, - onClick: closeAlertActionClick, - [`data-test-subj`]: 'close-alert-status', - }; - }, [disabledCloseAlertAction, closeAlertActionClick]); - - const disabledOpenAlertAction = !hasIndexUpdateDelete && !hasIndexMaintenance; - const openAlertAction = useMemo(() => { - return { - name: i18n.ACTION_OPEN_ALERT, - disabled: disabledOpenAlertAction, - onClick: openAlertActionOnClick, - [`data-test-subj`]: 'open-alert-status', - }; - }, [disabledOpenAlertAction, openAlertActionOnClick]); - - const statusActions = useMemo(() => { - if (!alertStatus) { - return []; - } - - switch (alertStatus) { - case 'open': - return [inProgressAlertAction, closeAlertAction]; - case 'in-progress': - return [openAlertAction, closeAlertAction]; - case 'closed': - return [openAlertAction, inProgressAlertAction]; - default: - return []; - } - }, [alertStatus, inProgressAlertAction, closeAlertAction, openAlertAction]); + onUpdateSuccess: onAlertStatusUpdateSuccess, + onUpdateFailure: onAlertStatusUpdateFailure, + }); return { - statusActions, + actionItems, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index d0f26894bf7d2..ffaea216f3fe3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useCallback, useMemo } from 'react'; -import { EuiContextMenu, EuiButton, EuiPopover } from '@elastic/eui'; +import { EuiContextMenu, EuiContextMenuPanel, EuiButton, EuiPopover } from '@elastic/eui'; import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations'; @@ -135,7 +135,7 @@ export const TakeActionDropdown = React.memo( [onAddExceptionTypeClick] ); - const exceptionActions = useExceptionActions({ + const { exceptionActions } = useExceptionActions({ isEndpointAlert, onAddExceptionTypeClick: handleOnAddExceptionTypeClick, }); @@ -149,7 +149,7 @@ export const TakeActionDropdown = React.memo( onAddEventFilterClick: handleOnAddEventFilterClick, }); - const { statusActions } = useAlertsActions({ + const { actionItems } = useAlertsActions({ alertStatus: actionsData.alertStatus, eventId: actionsData.eventId, timelineId, @@ -191,7 +191,7 @@ export const TakeActionDropdown = React.memo( { id: 1, title: CHANGE_ALERT_STATUS, - items: statusActions, + content: , }, /* Todo: Uncomment case action after getAddToCaseAction is split into action and modal { @@ -210,7 +210,7 @@ export const TakeActionDropdown = React.memo( ), },*/ ], - [alertsActionItems, hostIsolationAction, investigateInTimelineAction, statusActions] + [actionItems, alertsActionItems, hostIsolationAction, investigateInTimelineAction] ); const takeActionButton = useMemo(() => { diff --git a/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx b/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx index 335953e7ee43e..69d7ad36324de 100644 --- a/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx +++ b/x-pack/plugins/timelines/public/hooks/use_status_bulk_action_items.tsx @@ -83,21 +83,33 @@ export const useStatusBulkActionItems = ({ const actionItems = []; if (currentStatus !== FILTER_OPEN) { actionItems.push( - onClickUpdate(FILTER_OPEN)}> + onClickUpdate(FILTER_OPEN)} + > {i18n.BULK_ACTION_OPEN_SELECTED} ); } if (currentStatus !== FILTER_IN_PROGRESS) { actionItems.push( - onClickUpdate(FILTER_IN_PROGRESS)}> + onClickUpdate(FILTER_IN_PROGRESS)} + > {i18n.BULK_ACTION_IN_PROGRESS_SELECTED} ); } if (currentStatus !== FILTER_CLOSED) { actionItems.push( - onClickUpdate(FILTER_CLOSED)}> + onClickUpdate(FILTER_CLOSED)} + > {i18n.BULK_ACTION_CLOSE_SELECTED} ); diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts index 6f4de1dd2559e..d31e80de7d285 100644 --- a/x-pack/plugins/timelines/public/index.ts +++ b/x-pack/plugins/timelines/public/index.ts @@ -52,7 +52,7 @@ export { getTimelineIdFromColumnDroppableId, } from './components/drag_and_drop/helpers'; export { StatefulFieldsBrowser } from './components/t_grid/toolbar/fields_browser'; - +export { useStatusBulkActionItems } from './hooks/use_status_bulk_action_items'; // This exports static code and TypeScript types, // as well as, Kibana Platform `plugin()` initializer. export function plugin(initializerContext: PluginInitializerContext) { diff --git a/x-pack/plugins/timelines/public/plugin.ts b/x-pack/plugins/timelines/public/plugin.ts index 24bc99e59aaf0..2ec35ef1a51f3 100644 --- a/x-pack/plugins/timelines/public/plugin.ts +++ b/x-pack/plugins/timelines/public/plugin.ts @@ -27,6 +27,7 @@ import { tGridReducer } from './store/t_grid/reducer'; import { useDraggableKeyboardWrapper } from './components/drag_and_drop/draggable_keyboard_wrapper_hook'; import { useAddToTimeline, useAddToTimelineSensor } from './hooks/use_add_to_timeline'; import { getHoverActions } from './components/hover_actions'; + export class TimelinesPlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} private _store: Store | undefined;