mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[SecuritySolution] Close field editor when page context is lost (#124378)
* close field editor when context is lost * tests added * typecheck clean * close editor when timeline is unmounted
This commit is contained in:
parent
4f6be55f0e
commit
21710dfb77
9 changed files with 208 additions and 115 deletions
|
@ -33,6 +33,11 @@ jest.mock('../../../timelines/containers', () => ({
|
|||
|
||||
jest.mock('../../components/url_state/normalize_time_range.ts');
|
||||
|
||||
const mockUseCreateFieldButton = jest.fn().mockReturnValue(<></>);
|
||||
jest.mock('../../../timelines/components/create_field_button', () => ({
|
||||
useCreateFieldButton: (...params: unknown[]) => mockUseCreateFieldButton(...params),
|
||||
}));
|
||||
|
||||
const mockUseResizeObserver: jest.Mock = useResizeObserver as jest.Mock;
|
||||
jest.mock('use-resize-observer/polyfilled');
|
||||
mockUseResizeObserver.mockImplementation(() => ({}));
|
||||
|
@ -87,4 +92,22 @@ describe('StatefulEventsViewer', () => {
|
|||
expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test('it closes field editor when unmounted', async () => {
|
||||
const mockCloseEditor = jest.fn();
|
||||
mockUseCreateFieldButton.mockImplementation((_, __, fieldEditorActionsRef) => {
|
||||
fieldEditorActionsRef.current = { closeEditor: mockCloseEditor };
|
||||
return <></>;
|
||||
});
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<StatefulEventsViewer {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockCloseEditor).not.toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
expect(mockCloseEditor).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useMemo, useEffect } from 'react';
|
||||
import React, { useRef, useCallback, useMemo, useEffect } from 'react';
|
||||
import { connect, ConnectedProps, useDispatch } from 'react-redux';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import styled from 'styled-components';
|
||||
|
@ -29,7 +29,10 @@ import { CellValueElementProps } from '../../../timelines/components/timeline/ce
|
|||
import { FIELDS_WITHOUT_CELL_ACTIONS } from '../../lib/cell_actions/constants';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { GraphOverlay } from '../../../timelines/components/graph_overlay';
|
||||
import { useCreateFieldButton } from '../../../timelines/components/create_field_button';
|
||||
import {
|
||||
CreateFieldEditorActions,
|
||||
useCreateFieldButton,
|
||||
} from '../../../timelines/components/create_field_button';
|
||||
|
||||
const EMPTY_CONTROL_COLUMNS: ControlColumnProps[] = [];
|
||||
|
||||
|
@ -121,6 +124,8 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
|
|||
const tGridEventRenderedViewEnabled = useIsExperimentalFeatureEnabled(
|
||||
'tGridEventRenderedViewEnabled'
|
||||
);
|
||||
const editorActionsRef = useRef<CreateFieldEditorActions>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (createTimeline != null) {
|
||||
createTimeline({
|
||||
|
@ -137,6 +142,10 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
|
|||
}
|
||||
return () => {
|
||||
deleteEventQuery({ id, inputId: 'global' });
|
||||
if (editorActionsRef.current) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
editorActionsRef.current.closeEditor();
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
@ -167,7 +176,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
|
|||
}, [id, timelineQuery, globalQuery]);
|
||||
const bulkActions = useMemo(() => ({ onAlertStatusActionSuccess }), [onAlertStatusActionSuccess]);
|
||||
|
||||
const createFieldComponent = useCreateFieldButton(scopeId, id);
|
||||
const createFieldComponent = useCreateFieldButton(scopeId, id, editorActionsRef);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
import { render, fireEvent, act, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { CreateFieldButton } from './index';
|
||||
import React, { MutableRefObject } from 'react';
|
||||
import { CreateFieldButton, CreateFieldEditorActions } from './index';
|
||||
import {
|
||||
indexPatternFieldEditorPluginMock,
|
||||
Start,
|
||||
|
@ -108,4 +108,38 @@ describe('CreateFieldButton', () => {
|
|||
fireEvent.click(screen.getByRole('button'));
|
||||
expect(onClickParam).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("stores 'closeEditor' in the actions ref when editor is open", async () => {
|
||||
const mockCloseEditor = jest.fn();
|
||||
useKibanaMock().services.data.dataViews.get = () => Promise.resolve({} as DataView);
|
||||
useKibanaMock().services.dataViewFieldEditor.openEditor = () => mockCloseEditor;
|
||||
|
||||
const editorActionsRef: MutableRefObject<CreateFieldEditorActions> = React.createRef();
|
||||
await act(async () => {
|
||||
render(
|
||||
<CreateFieldButton
|
||||
selectedDataViewId={'dataViewId'}
|
||||
onClick={() => undefined}
|
||||
timelineId={TimelineId.detectionsPage}
|
||||
editorActionsRef={editorActionsRef}
|
||||
/>,
|
||||
{
|
||||
wrapper: TestProviders,
|
||||
}
|
||||
);
|
||||
await runAllPromises();
|
||||
});
|
||||
|
||||
expect(editorActionsRef?.current).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(mockCloseEditor).not.toHaveBeenCalled();
|
||||
expect(editorActionsRef?.current?.closeEditor).toBeDefined();
|
||||
|
||||
editorActionsRef!.current!.closeEditor();
|
||||
|
||||
expect(mockCloseEditor).toHaveBeenCalled();
|
||||
expect(editorActionsRef!.current).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import React, { MutableRefObject, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
|
||||
|
@ -23,17 +23,21 @@ import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
|||
import { DEFAULT_COLUMN_MIN_WIDTH } from '../timeline/body/constants';
|
||||
import { defaultColumnHeaderType } from '../timeline/body/column_headers/default_headers';
|
||||
|
||||
export type CreateFieldEditorActions = { closeEditor: () => void } | null;
|
||||
type CreateFieldEditorActionsRef = MutableRefObject<CreateFieldEditorActions>;
|
||||
|
||||
interface CreateFieldButtonProps {
|
||||
selectedDataViewId: string;
|
||||
onClick: () => void;
|
||||
timelineId: TimelineId;
|
||||
editorActionsRef?: CreateFieldEditorActionsRef;
|
||||
}
|
||||
const StyledButton = styled(EuiButton)`
|
||||
margin-left: ${({ theme }) => theme.eui.paddingSizes.m};
|
||||
`;
|
||||
|
||||
export const CreateFieldButton = React.memo<CreateFieldButtonProps>(
|
||||
({ selectedDataViewId, onClick: onClickParam, timelineId }) => {
|
||||
({ selectedDataViewId, onClick: onClickParam, timelineId, editorActionsRef }) => {
|
||||
const [dataView, setDataView] = useState<DataView | null>(null);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
@ -52,7 +56,7 @@ export const CreateFieldButton = React.memo<CreateFieldButtonProps>(
|
|||
|
||||
const onClick = useCallback(() => {
|
||||
if (dataView) {
|
||||
dataViewFieldEditor?.openEditor({
|
||||
const closeFieldEditor = dataViewFieldEditor?.openEditor({
|
||||
ctx: { dataView },
|
||||
onSave: async (field: DataViewField) => {
|
||||
// Fetch the updated list of fields
|
||||
|
@ -72,6 +76,14 @@ export const CreateFieldButton = React.memo<CreateFieldButtonProps>(
|
|||
);
|
||||
},
|
||||
});
|
||||
if (editorActionsRef) {
|
||||
editorActionsRef.current = {
|
||||
closeEditor: () => {
|
||||
editorActionsRef.current = null;
|
||||
closeFieldEditor();
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
onClickParam();
|
||||
}, [
|
||||
|
@ -82,6 +94,7 @@ export const CreateFieldButton = React.memo<CreateFieldButtonProps>(
|
|||
selectedDataViewId,
|
||||
dispatch,
|
||||
timelineId,
|
||||
editorActionsRef,
|
||||
]);
|
||||
|
||||
if (
|
||||
|
@ -116,7 +129,8 @@ CreateFieldButton.displayName = 'CreateFieldButton';
|
|||
*/
|
||||
export const useCreateFieldButton = (
|
||||
sourcererScope: SourcererScopeName,
|
||||
timelineId: TimelineId
|
||||
timelineId: TimelineId,
|
||||
editorActionsRef?: CreateFieldEditorActionsRef
|
||||
) => {
|
||||
const scopeIdSelector = useMemo(() => sourcererSelectors.scopeIdSelector(), []);
|
||||
const { missingPatterns, selectedDataViewId } = useDeepEqualSelector((state) =>
|
||||
|
@ -133,9 +147,10 @@ export const useCreateFieldButton = (
|
|||
selectedDataViewId={selectedDataViewId}
|
||||
onClick={onClick}
|
||||
timelineId={timelineId}
|
||||
editorActionsRef={editorActionsRef}
|
||||
/>
|
||||
);
|
||||
|
||||
return CreateFieldButtonComponent;
|
||||
}, [missingPatterns.length, selectedDataViewId, timelineId]);
|
||||
}, [missingPatterns.length, selectedDataViewId, timelineId, editorActionsRef]);
|
||||
};
|
||||
|
|
|
@ -658,6 +658,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
]
|
||||
}
|
||||
onSelectAll={[Function]}
|
||||
show={true}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Sort } from '../sort';
|
|||
import { TestProviders } from '../../../../../common/mock/test_providers';
|
||||
import { useMountAppended } from '../../../../../common/utils/use_mount_appended';
|
||||
|
||||
import { ColumnHeadersComponent } from '.';
|
||||
import { ColumnHeadersComponent, ColumnHeadersComponentProps } from '.';
|
||||
import { cloneDeep } from 'lodash/fp';
|
||||
import { timelineActions } from '../../../../store/timeline';
|
||||
import { TimelineTabs } from '../../../../../../common/types/timeline';
|
||||
|
@ -27,6 +27,11 @@ import { HeaderActions } from '../actions/header_actions';
|
|||
|
||||
jest.mock('../../../../../common/lib/kibana');
|
||||
|
||||
const mockUseCreateFieldButton = jest.fn().mockReturnValue(<></>);
|
||||
jest.mock('../../../create_field_button', () => ({
|
||||
useCreateFieldButton: (...params: unknown[]) => mockUseCreateFieldButton(...params),
|
||||
}));
|
||||
|
||||
const mockDispatch = jest.fn();
|
||||
jest.mock('react-redux', () => {
|
||||
const original = jest.requireActual('react-redux');
|
||||
|
@ -46,33 +51,34 @@ describe('ColumnHeaders', () => {
|
|||
...x,
|
||||
headerCellRender: HeaderActions,
|
||||
}));
|
||||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
const defaultProps: ColumnHeadersComponentProps = {
|
||||
actionsColumnWidth,
|
||||
browserFields: mockBrowserFields,
|
||||
columnHeaders: defaultHeaders,
|
||||
isSelectAllChecked: false,
|
||||
onSelectAll: jest.fn,
|
||||
show: true,
|
||||
showEventsSelect: false,
|
||||
showSelectAllCheckbox: false,
|
||||
sort,
|
||||
tabType: TimelineTabs.query,
|
||||
timelineId,
|
||||
leadingControlColumns,
|
||||
trailingControlColumns: [],
|
||||
};
|
||||
|
||||
describe('rendering', () => {
|
||||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
||||
test('renders correctly against snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={defaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={sort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
/>
|
||||
<ColumnHeadersComponent {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('ColumnHeadersComponent')).toMatchSnapshot();
|
||||
|
@ -81,20 +87,7 @@ describe('ColumnHeaders', () => {
|
|||
test('it renders the field browser', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={defaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={sort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
/>
|
||||
<ColumnHeadersComponent {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -104,20 +97,7 @@ describe('ColumnHeaders', () => {
|
|||
test('it renders every column header', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={defaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={sort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
/>
|
||||
<ColumnHeadersComponent {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -166,18 +146,7 @@ describe('ColumnHeaders', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={mockDefaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={mockSort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
{...{ ...defaultProps, columnHeaders: mockDefaultHeaders, sort: mockSort }}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -210,18 +179,7 @@ describe('ColumnHeaders', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={mockDefaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn()}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={mockSort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
{...{ ...defaultProps, columnHeaders: mockDefaultHeaders, sort: mockSort }}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -249,18 +207,11 @@ describe('ColumnHeaders', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={mockDefaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn()}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={mockSort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={leadingControlColumns}
|
||||
trailingControlColumns={[]}
|
||||
{...{
|
||||
...defaultProps,
|
||||
columnHeaders: mockDefaultHeaders,
|
||||
sort: mockSort,
|
||||
}}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -287,18 +238,13 @@ describe('ColumnHeaders', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent
|
||||
actionsColumnWidth={actionsColumnWidth}
|
||||
browserFields={mockBrowserFields}
|
||||
columnHeaders={mockDefaultHeaders}
|
||||
isSelectAllChecked={false}
|
||||
onSelectAll={jest.fn()}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={false}
|
||||
sort={mockSort}
|
||||
tabType={TimelineTabs.query}
|
||||
timelineId={timelineId}
|
||||
leadingControlColumns={[]}
|
||||
trailingControlColumns={testTrailingControlColumns}
|
||||
{...{
|
||||
...defaultProps,
|
||||
columnHeaders: mockDefaultHeaders,
|
||||
sort: mockSort,
|
||||
leadingControlColumns: [],
|
||||
trailingControlColumns: testTrailingControlColumns,
|
||||
}}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
@ -307,4 +253,43 @@ describe('ColumnHeaders', () => {
|
|||
expect(wrapper.exists('[data-test-subj="test-header-action-cell"]')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Field Editor', () => {
|
||||
test('Closes field editor when the timeline is unmounted', () => {
|
||||
const mockCloseEditor = jest.fn();
|
||||
mockUseCreateFieldButton.mockImplementation((_, __, fieldEditorActionsRef) => {
|
||||
fieldEditorActionsRef.current = { closeEditor: mockCloseEditor };
|
||||
return <></>;
|
||||
});
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockCloseEditor).not.toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
expect(mockCloseEditor).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Closes field editor when the timeline is closed', () => {
|
||||
const mockCloseEditor = jest.fn();
|
||||
mockUseCreateFieldButton.mockImplementation((_, __, fieldEditorActionsRef) => {
|
||||
fieldEditorActionsRef.current = { closeEditor: mockCloseEditor };
|
||||
return <></>;
|
||||
});
|
||||
|
||||
const Proxy = (props: ColumnHeadersComponentProps) => (
|
||||
<TestProviders>
|
||||
<ColumnHeadersComponent {...props} />
|
||||
</TestProviders>
|
||||
);
|
||||
const wrapper = mount(<Proxy {...defaultProps} />);
|
||||
expect(mockCloseEditor).not.toHaveBeenCalled();
|
||||
|
||||
wrapper.setProps({ ...defaultProps, show: false });
|
||||
expect(mockCloseEditor).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
||||
import { Droppable, DraggableChildrenFn } from 'react-beautiful-dnd';
|
||||
|
||||
import { DragEffects } from '../../../../../common/components/drag_and_drop/draggable_wrapper';
|
||||
|
@ -34,15 +34,16 @@ import { Sort } from '../sort';
|
|||
import { ColumnHeader } from './column_header';
|
||||
|
||||
import { SourcererScopeName } from '../../../../../common/store/sourcerer/model';
|
||||
import { useCreateFieldButton } from '../../../create_field_button';
|
||||
import { CreateFieldEditorActions, useCreateFieldButton } from '../../../create_field_button';
|
||||
|
||||
interface Props {
|
||||
export interface ColumnHeadersComponentProps {
|
||||
actionsColumnWidth: number;
|
||||
browserFields: BrowserFields;
|
||||
columnHeaders: ColumnHeaderOptions[];
|
||||
isEventViewer?: boolean;
|
||||
isSelectAllChecked: boolean;
|
||||
onSelectAll: OnSelectAll;
|
||||
show: boolean;
|
||||
showEventsSelect: boolean;
|
||||
showSelectAllCheckbox: boolean;
|
||||
sort: Sort[];
|
||||
|
@ -92,6 +93,7 @@ export const ColumnHeadersComponent = ({
|
|||
isEventViewer = false,
|
||||
isSelectAllChecked,
|
||||
onSelectAll,
|
||||
show,
|
||||
showEventsSelect,
|
||||
showSelectAllCheckbox,
|
||||
sort,
|
||||
|
@ -99,8 +101,24 @@ export const ColumnHeadersComponent = ({
|
|||
timelineId,
|
||||
leadingControlColumns,
|
||||
trailingControlColumns,
|
||||
}: Props) => {
|
||||
}: ColumnHeadersComponentProps) => {
|
||||
const [draggingIndex, setDraggingIndex] = useState<number | null>(null);
|
||||
const fieldEditorActionsRef = useRef<CreateFieldEditorActions>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (fieldEditorActionsRef.current) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
fieldEditorActionsRef.current.closeEditor();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!show && fieldEditorActionsRef.current) {
|
||||
fieldEditorActionsRef.current.closeEditor();
|
||||
}
|
||||
}, [show]);
|
||||
|
||||
const renderClone: DraggableChildrenFn = useCallback(
|
||||
(dragProvided, _dragSnapshot, rubric) => {
|
||||
|
@ -174,7 +192,8 @@ export const ColumnHeadersComponent = ({
|
|||
|
||||
const createFieldComponent = useCreateFieldButton(
|
||||
SourcererScopeName.timeline,
|
||||
timelineId as TimelineId
|
||||
timelineId as TimelineId,
|
||||
fieldEditorActionsRef
|
||||
);
|
||||
|
||||
const LeadingHeaderActions = useMemo(() => {
|
||||
|
@ -300,6 +319,7 @@ export const ColumnHeaders = React.memo(
|
|||
prevProps.isEventViewer === nextProps.isEventViewer &&
|
||||
prevProps.isSelectAllChecked === nextProps.isSelectAllChecked &&
|
||||
prevProps.onSelectAll === nextProps.onSelectAll &&
|
||||
prevProps.show === nextProps.show &&
|
||||
prevProps.showEventsSelect === nextProps.showEventsSelect &&
|
||||
prevProps.showSelectAllCheckbox === nextProps.showSelectAllCheckbox &&
|
||||
deepEqual(prevProps.sort, nextProps.sort) &&
|
||||
|
|
|
@ -146,6 +146,7 @@ describe('Body', () => {
|
|||
selectedEventIds: {},
|
||||
setSelected: jest.fn() as unknown as StatefulBodyProps['setSelected'],
|
||||
sort: mockSort,
|
||||
show: true,
|
||||
showCheckboxes: false,
|
||||
tabType: TimelineTabs.query,
|
||||
totalPages: 1,
|
||||
|
|
|
@ -89,6 +89,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
setSelected,
|
||||
clearSelected,
|
||||
onRuleChange,
|
||||
show,
|
||||
showCheckboxes,
|
||||
refetch,
|
||||
renderCellValue,
|
||||
|
@ -244,6 +245,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
isEventViewer={isEventViewer}
|
||||
isSelectAllChecked={isSelectAllChecked}
|
||||
onSelectAll={onSelectAll}
|
||||
show={show}
|
||||
showEventsSelect={false}
|
||||
showSelectAllCheckbox={showCheckboxes}
|
||||
sort={sort}
|
||||
|
@ -298,7 +300,8 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
|
|||
prevProps.renderCellValue === nextProps.renderCellValue &&
|
||||
prevProps.rowRenderers === nextProps.rowRenderers &&
|
||||
prevProps.showCheckboxes === nextProps.showCheckboxes &&
|
||||
prevProps.tabType === nextProps.tabType
|
||||
prevProps.tabType === nextProps.tabType &&
|
||||
prevProps.show === nextProps.show
|
||||
);
|
||||
|
||||
BodyComponent.displayName = 'BodyComponent';
|
||||
|
@ -321,6 +324,7 @@ const makeMapStateToProps = () => {
|
|||
pinnedEventIds,
|
||||
selectedEventIds,
|
||||
showCheckboxes,
|
||||
show,
|
||||
} = timeline;
|
||||
|
||||
return {
|
||||
|
@ -333,6 +337,7 @@ const makeMapStateToProps = () => {
|
|||
pinnedEventIds,
|
||||
selectedEventIds,
|
||||
showCheckboxes,
|
||||
show,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue