mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[SecuritySolution][Timeline] Remove timeline.isLoading (#198616)
## Summary Trying to answer the question of: "Do we still need `timeline.isLoading`?" `timeline.isSaving` should be the only indicator for "loading" states of timeline itself. All other pieces of state that are associated with timeline that could have a loading state, have their own loading indicators (e.g. data providers, alert list etc). Therefore, this PR removes all references to `timeline.isLoading` and parts of the UI that depended on it. Places that `timeline.isLoading` was used ([context](https://github.com/elastic/kibana/pull/38185)): - Blocking drag/drop on data providers - This is not necessary anymore. Drag/drop works while the underlying query is being executed. - Showing a loading state for the alerts table & data provider changes - Both components have their own loading state, so no extra loading state is necessary ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c14c1205ed
commit
47100291a8
28 changed files with 15 additions and 480 deletions
|
@ -15,7 +15,6 @@ interface Props {
|
|||
children?: React.ReactNode;
|
||||
droppableId: string;
|
||||
height?: string;
|
||||
isDropDisabled?: boolean;
|
||||
type?: string;
|
||||
render?: ({ isDraggingOver }: { isDraggingOver: boolean }) => React.ReactNode;
|
||||
renderClone?: DraggableChildrenFn;
|
||||
|
@ -90,15 +89,7 @@ const ReactDndDropTarget = styled.div<{ isDraggingOver: boolean; height: string
|
|||
ReactDndDropTarget.displayName = 'ReactDndDropTarget';
|
||||
|
||||
export const DroppableWrapper = React.memo<Props>(
|
||||
({
|
||||
children = null,
|
||||
droppableId,
|
||||
height = '100%',
|
||||
isDropDisabled = false,
|
||||
type,
|
||||
render = null,
|
||||
renderClone,
|
||||
}) => {
|
||||
({ children = null, droppableId, height = '100%', type, render = null, renderClone }) => {
|
||||
const DroppableContent = useCallback<DroppableProps['children']>(
|
||||
(provided, snapshot) => (
|
||||
<ReactDndDropTarget
|
||||
|
@ -116,7 +107,6 @@ export const DroppableWrapper = React.memo<Props>(
|
|||
|
||||
return (
|
||||
<Droppable
|
||||
isDropDisabled={isDropDisabled}
|
||||
droppableId={droppableId}
|
||||
direction={'horizontal'}
|
||||
type={type}
|
||||
|
|
|
@ -358,7 +358,6 @@ export const mockGlobalState: State = {
|
|||
historyIds: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
kqlMode: 'filter',
|
||||
kqlQuery: { filterQuery: null },
|
||||
loadingEventIds: [],
|
||||
|
|
|
@ -1899,7 +1899,6 @@ export const mockTimelineModel: TimelineModel = {
|
|||
indexNames: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isSelectAllChecked: false,
|
||||
kqlMode: 'filter',
|
||||
|
@ -2084,7 +2083,6 @@ export const defaultTimelineProps: CreateTimelineProps = {
|
|||
indexNames: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isSelectAllChecked: false,
|
||||
itemsPerPage: 25,
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
mockGetOneTimelineResult,
|
||||
mockTimelineData,
|
||||
} from '../../../common/mock';
|
||||
import type { CreateTimeline, UpdateTimelineLoading } from './types';
|
||||
import type { CreateTimeline } from './types';
|
||||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import type { DataProvider } from '../../../../common/types/timeline';
|
||||
import { TimelineTypeEnum, TimelineStatusEnum } from '../../../../common/api/timeline';
|
||||
|
@ -127,7 +127,6 @@ describe('alert actions', () => {
|
|||
const anchor = '2020-03-01T17:59:46.349Z';
|
||||
const unix = moment(anchor).valueOf();
|
||||
let createTimeline: CreateTimeline;
|
||||
let updateTimelineIsLoading: UpdateTimelineLoading;
|
||||
let searchStrategyClient: jest.Mocked<ISearchStart>;
|
||||
let clock: sinon.SinonFakeTimers;
|
||||
let mockKibanaServices: jest.Mock;
|
||||
|
@ -270,7 +269,6 @@ describe('alert actions', () => {
|
|||
mockGetExceptionFilter = jest.fn().mockResolvedValue(undefined);
|
||||
|
||||
createTimeline = jest.fn() as jest.Mocked<CreateTimeline>;
|
||||
updateTimelineIsLoading = jest.fn() as jest.Mocked<UpdateTimelineLoading>;
|
||||
mockKibanaServices = KibanaServices.get as jest.Mock;
|
||||
|
||||
fetchMock = jest.fn();
|
||||
|
@ -296,28 +294,10 @@ describe('alert actions', () => {
|
|||
|
||||
describe('sendAlertToTimelineAction', () => {
|
||||
describe('timeline id is NOT empty string and apollo client exists', () => {
|
||||
test('it invokes updateTimelineIsLoading to set to true', async () => {
|
||||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: mockEcsDataWithAlert,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(updateTimelineIsLoading).toHaveBeenCalledTimes(1);
|
||||
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('it invokes createTimeline with designated timeline template if "timelineTemplate" exists', async () => {
|
||||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: mockEcsDataWithAlert,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -407,7 +387,6 @@ describe('alert actions', () => {
|
|||
indexNames: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isSelectAllChecked: false,
|
||||
itemsPerPage: 25,
|
||||
|
@ -477,7 +456,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: mockEcsDataWithAlert,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -496,7 +474,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: mockEcsDataWithAlert,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -505,14 +482,6 @@ describe('alert actions', () => {
|
|||
delete defaultTimelinePropsWithoutNote.ruleNote;
|
||||
delete defaultTimelinePropsWithoutNote.ruleAuthor;
|
||||
|
||||
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: false,
|
||||
});
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith({
|
||||
|
@ -544,7 +513,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMock,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -552,7 +520,6 @@ describe('alert actions', () => {
|
|||
const expectedTimelineProps = structuredClone(defaultTimelineProps);
|
||||
expectedTimelineProps.timeline.excludedRowRendererIds = [];
|
||||
|
||||
expect(updateTimelineIsLoading).not.toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps);
|
||||
|
@ -574,7 +541,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMock,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -582,7 +548,6 @@ describe('alert actions', () => {
|
|||
const expectedTimelineProps = structuredClone(defaultTimelineProps);
|
||||
expectedTimelineProps.timeline.excludedRowRendererIds = [];
|
||||
|
||||
expect(updateTimelineIsLoading).not.toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps);
|
||||
|
@ -608,12 +573,10 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMock,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
||||
expect(updateTimelineIsLoading).not.toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith({
|
||||
|
@ -655,12 +618,10 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMock,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
||||
expect(updateTimelineIsLoading).not.toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).not.toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps);
|
||||
|
@ -732,7 +693,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMockWithNoTemplateTimeline,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -740,7 +700,6 @@ describe('alert actions', () => {
|
|||
const expectedFrom = '2021-01-10T21:11:45.839Z';
|
||||
const expectedTo = '2021-01-10T21:12:45.839Z';
|
||||
|
||||
expect(updateTimelineIsLoading).not.toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith({
|
||||
|
@ -861,7 +820,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMockWithNoTemplateTimelineAndNoFilters,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -886,7 +844,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMockWithTemplateTimeline,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -894,7 +851,6 @@ describe('alert actions', () => {
|
|||
const expectedFrom = '2021-01-10T21:11:45.839Z';
|
||||
const expectedTo = '2021-01-10T21:12:45.839Z';
|
||||
|
||||
expect(updateTimelineIsLoading).toHaveBeenCalled();
|
||||
expect(mockGetExceptionFilter).toHaveBeenCalled();
|
||||
expect(createTimeline).toHaveBeenCalledTimes(1);
|
||||
expect(createTimeline).toHaveBeenCalledWith({
|
||||
|
@ -1046,7 +1002,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMockWithNoTemplateTimeline,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
@ -1141,7 +1096,6 @@ describe('alert actions', () => {
|
|||
await sendAlertToTimelineAction({
|
||||
createTimeline,
|
||||
ecsData: ecsDataMockWithNoTemplateTimeline,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter: mockGetExceptionFilter,
|
||||
});
|
||||
|
|
|
@ -936,7 +936,6 @@ export const sendBulkEventsToTimelineAction = async (
|
|||
export const sendAlertToTimelineAction = async ({
|
||||
createTimeline,
|
||||
ecsData: ecs,
|
||||
updateTimelineIsLoading,
|
||||
searchStrategyClient,
|
||||
getExceptionFilter,
|
||||
}: SendAlertToTimelineActionProps) => {
|
||||
|
@ -962,7 +961,6 @@ export const sendAlertToTimelineAction = async ({
|
|||
// For now we do not want to populate the template timeline if we have alertIds
|
||||
if (!isEmpty(timelineId)) {
|
||||
try {
|
||||
updateTimelineIsLoading({ id: TimelineId.active, isLoading: true });
|
||||
const [responseTimeline, eventDataResp] = await Promise.all([
|
||||
getTimelineTemplate(timelineId),
|
||||
lastValueFrom(
|
||||
|
@ -1092,7 +1090,6 @@ export const sendAlertToTimelineAction = async ({
|
|||
} catch (error) {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.error(error);
|
||||
updateTimelineIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
return createTimeline({
|
||||
from,
|
||||
notes: null,
|
||||
|
|
|
@ -23,7 +23,6 @@ import { useTimelineEventsHandler } from '../../../../timelines/containers';
|
|||
import { eventsViewerSelector } from '../../../../common/components/events_viewer/selectors';
|
||||
import type { State } from '../../../../common/store/types';
|
||||
import { useUpdateTimeline } from '../../../../timelines/components/open_timeline/use_update_timeline';
|
||||
import { timelineActions } from '../../../../timelines/store';
|
||||
import { useCreateTimeline } from '../../../../timelines/hooks/use_create_timeline';
|
||||
import { INVESTIGATE_BULK_IN_TIMELINE } from '../translations';
|
||||
import { TimelineId } from '../../../../../common/types/timeline';
|
||||
|
@ -141,18 +140,11 @@ export const useAddBulkToTimelineAction = ({
|
|||
timelineType: TimelineTypeEnum.default,
|
||||
});
|
||||
|
||||
const updateTimelineIsLoading = useCallback(
|
||||
(payload: Parameters<typeof timelineActions.updateIsLoading>[0]) =>
|
||||
dispatch(timelineActions.updateIsLoading(payload)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const updateTimeline = useUpdateTimeline();
|
||||
|
||||
const createTimeline = useCallback(
|
||||
async ({ timeline, ruleNote, timeline: { filters: eventIdFilters } }: CreateTimelineProps) => {
|
||||
await clearActiveTimeline();
|
||||
updateTimelineIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
updateTimeline({
|
||||
duplicate: true,
|
||||
from,
|
||||
|
@ -168,7 +160,7 @@ export const useAddBulkToTimelineAction = ({
|
|||
ruleNote,
|
||||
});
|
||||
},
|
||||
[updateTimeline, updateTimelineIsLoading, clearActiveTimeline, from, to]
|
||||
[updateTimeline, clearActiveTimeline, from, to]
|
||||
);
|
||||
|
||||
const sendBulkEventsToTimelineHandler = useCallback(
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ALERT_RULE_EXCEPTIONS_LIST, ALERT_RULE_PARAMETERS } from '@kbn/rule-data-utils';
|
||||
|
@ -23,7 +22,6 @@ import { createHistoryEntry } from '../../../../common/utils/global_query_string
|
|||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { TimelineId } from '../../../../../common/types/timeline';
|
||||
import { TimelineTypeEnum } from '../../../../../common/api/timeline';
|
||||
import { timelineActions } from '../../../../timelines/store';
|
||||
import { sendAlertToTimelineAction } from '../actions';
|
||||
import { useUpdateTimeline } from '../../../../timelines/components/open_timeline/use_update_timeline';
|
||||
import { useCreateTimeline } from '../../../../timelines/hooks/use_create_timeline';
|
||||
|
@ -98,7 +96,6 @@ export const useInvestigateInTimeline = ({
|
|||
const {
|
||||
data: { search: searchStrategyClient },
|
||||
} = useKibana().services;
|
||||
const dispatch = useDispatch();
|
||||
const { startTransaction } = useStartTransaction();
|
||||
|
||||
const { services } = useKibana();
|
||||
|
@ -133,12 +130,6 @@ export const useInvestigateInTimeline = ({
|
|||
[addError, getExceptionFilterFromIds]
|
||||
);
|
||||
|
||||
const updateTimelineIsLoading = useCallback(
|
||||
(payload: Parameters<typeof timelineActions.updateIsLoading>[0]) =>
|
||||
dispatch(timelineActions.updateIsLoading(payload)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const clearActiveTimeline = useCreateTimeline({
|
||||
timelineId: TimelineId.active,
|
||||
timelineType: TimelineTypeEnum.default,
|
||||
|
@ -153,7 +144,6 @@ export const useInvestigateInTimeline = ({
|
|||
!newColumns || isEmpty(newColumns) ? defaultUdtHeaders : newColumns;
|
||||
|
||||
await clearActiveTimeline();
|
||||
updateTimelineIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
updateTimeline({
|
||||
duplicate: true,
|
||||
from: fromTimeline,
|
||||
|
@ -173,12 +163,11 @@ export const useInvestigateInTimeline = ({
|
|||
ruleNote,
|
||||
});
|
||||
},
|
||||
[updateTimeline, updateTimelineIsLoading, clearActiveTimeline]
|
||||
[updateTimeline, clearActiveTimeline]
|
||||
);
|
||||
|
||||
const investigateInTimelineAlertClick = useCallback(async () => {
|
||||
createHistoryEntry();
|
||||
|
||||
startTransaction({ name: ALERTS_ACTIONS.INVESTIGATE_IN_TIMELINE });
|
||||
if (onInvestigateInTimelineAlertClick) {
|
||||
onInvestigateInTimelineAlertClick();
|
||||
|
@ -188,7 +177,6 @@ export const useInvestigateInTimeline = ({
|
|||
createTimeline,
|
||||
ecsData: ecsRowData,
|
||||
searchStrategyClient,
|
||||
updateTimelineIsLoading,
|
||||
getExceptionFilter,
|
||||
});
|
||||
}
|
||||
|
@ -198,7 +186,6 @@ export const useInvestigateInTimeline = ({
|
|||
ecsRowData,
|
||||
onInvestigateInTimelineAlertClick,
|
||||
searchStrategyClient,
|
||||
updateTimelineIsLoading,
|
||||
getExceptionFilter,
|
||||
]);
|
||||
|
||||
|
|
|
@ -55,13 +55,10 @@ export interface UpdateAlertStatusActionProps {
|
|||
export interface SendAlertToTimelineActionProps {
|
||||
createTimeline: CreateTimeline;
|
||||
ecsData: Ecs | Ecs[];
|
||||
updateTimelineIsLoading: UpdateTimelineLoading;
|
||||
searchStrategyClient: ISearchStart;
|
||||
getExceptionFilter: GetExceptionFilter;
|
||||
}
|
||||
|
||||
export type UpdateTimelineLoading = ({ id, isLoading }: { id: string; isLoading: boolean }) => void;
|
||||
|
||||
export interface CreateTimelineProps {
|
||||
from: string;
|
||||
timeline: TimelineModel;
|
||||
|
|
|
@ -121,7 +121,6 @@ describe('useRuleFromTimeline', () => {
|
|||
expect(result.current.loading).toEqual(true);
|
||||
await waitForNextUpdate();
|
||||
expect(setRuleQuery).toHaveBeenCalled();
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -153,16 +152,8 @@ describe('useRuleFromTimeline', () => {
|
|||
await waitForNextUpdate();
|
||||
expect(setRuleQuery).toHaveBeenCalled();
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(4);
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(2);
|
||||
expect(mockDispatch).toHaveBeenNthCalledWith(1, {
|
||||
type: 'x-pack/security_solution/local/timeline/UPDATE_LOADING',
|
||||
payload: {
|
||||
id: 'timeline-1',
|
||||
isLoading: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockDispatch).toHaveBeenNthCalledWith(2, {
|
||||
type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW',
|
||||
payload: {
|
||||
id: 'timeline',
|
||||
|
@ -170,13 +161,6 @@ describe('useRuleFromTimeline', () => {
|
|||
selectedPatterns: selectedTimeline.data.timeline.indexNames,
|
||||
},
|
||||
});
|
||||
expect(mockDispatch).toHaveBeenNthCalledWith(3, {
|
||||
type: 'x-pack/security_solution/local/timeline/UPDATE_LOADING',
|
||||
payload: {
|
||||
id: 'timeline-1',
|
||||
isLoading: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('when from timeline data view id === selected data view id and browser fields is not empty, set rule data to match from timeline query', async () => {
|
||||
|
@ -347,7 +331,7 @@ describe('useRuleFromTimeline', () => {
|
|||
const { waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery));
|
||||
await waitForNextUpdate();
|
||||
expect(setRuleQuery).toHaveBeenCalled();
|
||||
expect(mockDispatch).toHaveBeenNthCalledWith(4, {
|
||||
expect(mockDispatch).toHaveBeenNthCalledWith(2, {
|
||||
type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW',
|
||||
payload: {
|
||||
id: 'timeline',
|
||||
|
|
|
@ -6,14 +6,12 @@
|
|||
*/
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { timelineDefaults } from '../timelines/store/defaults';
|
||||
import { APP_UI_ID } from '../../common/constants';
|
||||
import type { DataProvider } from '../../common/types';
|
||||
import { TimelineId } from '../../common/types/timeline';
|
||||
import { TimelineTypeEnum } from '../../common/api/timeline';
|
||||
import { useStartTransaction } from '../common/lib/apm/use_start_transaction';
|
||||
import { timelineActions } from '../timelines/store';
|
||||
import { useCreateTimeline } from '../timelines/hooks/use_create_timeline';
|
||||
import type { CreateTimelineProps } from '../detections/components/alerts_table/types';
|
||||
import { useUpdateTimeline } from '../timelines/components/open_timeline/use_update_timeline';
|
||||
|
@ -46,15 +44,8 @@ export const useInvestigateInTimeline = ({
|
|||
from,
|
||||
to,
|
||||
}: UseInvestigateInTimelineActionProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const { startTransaction } = useStartTransaction();
|
||||
|
||||
const updateTimelineIsLoading = useCallback(
|
||||
(payload: Parameters<typeof timelineActions.updateIsLoading>[0]) =>
|
||||
dispatch(timelineActions.updateIsLoading(payload)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const clearActiveTimeline = useCreateTimeline({
|
||||
timelineId: TimelineId.active,
|
||||
timelineType: TimelineTypeEnum.default,
|
||||
|
@ -65,7 +56,6 @@ export const useInvestigateInTimeline = ({
|
|||
const createTimeline = useCallback(
|
||||
async ({ from: fromTimeline, timeline, to: toTimeline, ruleNote }: CreateTimelineProps) => {
|
||||
await clearActiveTimeline();
|
||||
updateTimelineIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
updateTimeline({
|
||||
duplicate: true,
|
||||
from: fromTimeline,
|
||||
|
@ -80,7 +70,7 @@ export const useInvestigateInTimeline = ({
|
|||
ruleNote,
|
||||
});
|
||||
},
|
||||
[updateTimeline, updateTimelineIsLoading, clearActiveTimeline]
|
||||
[updateTimeline, clearActiveTimeline]
|
||||
);
|
||||
|
||||
const investigateInTimelineClick = useCallback(async () => {
|
||||
|
|
|
@ -11,7 +11,6 @@ import { waitFor } from '@testing-library/react';
|
|||
|
||||
import { mockTimelineResults, mockGetOneTimelineResult } from '../../../common/mock';
|
||||
import { timelineDefaults } from '../../store/defaults';
|
||||
import { updateIsLoading as dispatchUpdateIsLoading } from '../../store/actions';
|
||||
import type { QueryTimelineById } from './helpers';
|
||||
import {
|
||||
defaultTimelineToTimelineModel,
|
||||
|
@ -646,13 +645,6 @@ describe('helpers', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('dispatch updateIsLoading to true', () => {
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('get timeline by Id', () => {
|
||||
expect(resolveTimeline).toHaveBeenCalled();
|
||||
});
|
||||
|
@ -671,13 +663,6 @@ describe('helpers', () => {
|
|||
...timeline,
|
||||
});
|
||||
});
|
||||
|
||||
test('dispatch updateIsLoading to false', () => {
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('update a timeline', () => {
|
||||
|
@ -706,11 +691,6 @@ describe('helpers', () => {
|
|||
await queryTimelineById(args);
|
||||
});
|
||||
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
// expect(resolveTimeline).toHaveBeenCalled();
|
||||
const { timeline } = formatTimelineResponseToModel(
|
||||
omitTypenameInTimeline(getOr({}, 'data.timeline', selectedTimeline)),
|
||||
|
@ -741,11 +721,6 @@ describe('helpers', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('should update timeline correctly when timeline is untitled', async () => {
|
||||
|
@ -764,11 +739,6 @@ describe('helpers', () => {
|
|||
queryTimelineById(newArgs);
|
||||
});
|
||||
|
||||
expect(dispatchUpdateIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
expect(mockUpdateTimeline).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
|
@ -778,10 +748,6 @@ describe('helpers', () => {
|
|||
}),
|
||||
})
|
||||
);
|
||||
expect(dispatchUpdateIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('should update timeline correctly when timeline is already saved and onOpenTimeline is not provided', async () => {
|
||||
|
@ -791,11 +757,6 @@ describe('helpers', () => {
|
|||
queryTimelineById(args);
|
||||
});
|
||||
|
||||
expect(dispatchUpdateIsLoading).toHaveBeenCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpdateTimeline).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
|
@ -860,13 +821,6 @@ describe('helpers', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('dispatch updateIsLoading to true', () => {
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('get timeline by Id', () => {
|
||||
expect(resolveTimeline).toHaveBeenCalled();
|
||||
});
|
||||
|
@ -885,13 +839,6 @@ describe('helpers', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('dispatch updateIsLoading to false', () => {
|
||||
expect(dispatchUpdateIsLoading).toBeCalledWith({
|
||||
id: TimelineId.active,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@ import { set } from '@kbn/safer-lodash-set/fp';
|
|||
import { getOr } from 'lodash/fp';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import deepMerge from 'deepmerge';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useCallback } from 'react';
|
||||
import { useDiscoverInTimelineContext } from '../../../common/components/discover_in_timeline/use_discover_in_timeline_context';
|
||||
import type { ColumnHeaderOptions } from '../../../../common/types/timeline';
|
||||
import type {
|
||||
|
@ -49,7 +47,6 @@ import {
|
|||
DEFAULT_TO_MOMENT,
|
||||
} from '../../../common/utils/default_date_settings';
|
||||
import { resolveTimeline } from '../../containers/api';
|
||||
import { timelineActions } from '../../store';
|
||||
|
||||
export const OPEN_TIMELINE_CLASS_NAME = 'open-timeline';
|
||||
|
||||
|
@ -314,13 +311,6 @@ export interface QueryTimelineById {
|
|||
export const useQueryTimelineById = () => {
|
||||
const { resetDiscoverAppState } = useDiscoverInTimelineContext();
|
||||
const updateTimeline = useUpdateTimeline();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const updateIsLoading = useCallback(
|
||||
(status: { id: string; isLoading: boolean }) =>
|
||||
dispatch(timelineActions.updateIsLoading(status)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return ({
|
||||
activeTimelineTab = TimelineTabs.query,
|
||||
|
@ -333,7 +323,6 @@ export const useQueryTimelineById = () => {
|
|||
openTimeline = true,
|
||||
savedSearchId,
|
||||
}: QueryTimelineById) => {
|
||||
updateIsLoading({ id: TimelineId.active, isLoading: true });
|
||||
if (timelineId == null) {
|
||||
updateTimeline({
|
||||
id: TimelineId.active,
|
||||
|
@ -356,7 +345,6 @@ export const useQueryTimelineById = () => {
|
|||
},
|
||||
});
|
||||
resetDiscoverAppState();
|
||||
updateIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
} else {
|
||||
return Promise.resolve(resolveTimeline(timelineId))
|
||||
.then((result) => {
|
||||
|
@ -409,9 +397,6 @@ export const useQueryTimelineById = () => {
|
|||
if (onError != null) {
|
||||
onError(error, timelineId);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
updateIsLoading({ id: TimelineId.active, isLoading: false });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -109,9 +109,6 @@ export const DataProviders = React.memo<Props>(({ timelineId }) => {
|
|||
const { browserFields } = useSourcererDataView(SourcererScopeName.timeline);
|
||||
const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []);
|
||||
|
||||
const isLoading = useDeepEqualSelector(
|
||||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).isLoading
|
||||
);
|
||||
const dataProviders = useDeepEqualSelector(
|
||||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).dataProviders
|
||||
);
|
||||
|
@ -167,7 +164,7 @@ export const DataProviders = React.memo<Props>(({ timelineId }) => {
|
|||
dataProviders={dataProviders}
|
||||
/>
|
||||
) : (
|
||||
<DroppableWrapper isDropDisabled={isLoading} droppableId={droppableId}>
|
||||
<DroppableWrapper droppableId={droppableId}>
|
||||
<Empty browserFields={browserFields} timelineId={timelineId} />
|
||||
</DroppableWrapper>
|
||||
)}
|
||||
|
|
|
@ -44,7 +44,6 @@ interface OwnProps {
|
|||
kqlQuery: string; // eslint-disable-line react/no-unused-prop-types
|
||||
isEnabled: boolean;
|
||||
isExcluded: boolean;
|
||||
isLoading: boolean;
|
||||
isOpen: boolean;
|
||||
onDataProviderEdited?: OnDataProviderEdited;
|
||||
operator: QueryOperator;
|
||||
|
@ -77,7 +76,6 @@ interface GetProviderActionsProps {
|
|||
field: string;
|
||||
isEnabled: boolean;
|
||||
isExcluded: boolean;
|
||||
isLoading: boolean;
|
||||
onDataProviderEdited?: OnDataProviderEdited;
|
||||
onFilterForFieldPresent: () => void;
|
||||
operator: QueryOperator;
|
||||
|
@ -98,7 +96,6 @@ export const getProviderActions = ({
|
|||
field,
|
||||
isEnabled,
|
||||
isExcluded,
|
||||
isLoading,
|
||||
operator,
|
||||
onDataProviderEdited,
|
||||
onFilterForFieldPresent,
|
||||
|
@ -116,28 +113,24 @@ export const getProviderActions = ({
|
|||
items: [
|
||||
{
|
||||
className: EDIT_CLASS_NAME,
|
||||
disabled: isLoading,
|
||||
icon: 'pencil',
|
||||
name: i18n.EDIT_MENU_ITEM,
|
||||
panel: 1,
|
||||
},
|
||||
{
|
||||
className: EXCLUDE_CLASS_NAME,
|
||||
disabled: isLoading,
|
||||
icon: `${isExcluded ? 'plusInCircle' : 'minusInCircle'}`,
|
||||
name: isExcluded ? i18n.INCLUDE_DATA_PROVIDER : i18n.EXCLUDE_DATA_PROVIDER,
|
||||
onClick: toggleExcluded,
|
||||
},
|
||||
{
|
||||
className: ENABLE_CLASS_NAME,
|
||||
disabled: isLoading,
|
||||
icon: `${isEnabled ? 'eyeClosed' : 'eye'}`,
|
||||
name: isEnabled ? i18n.TEMPORARILY_DISABLE_DATA_PROVIDER : i18n.RE_ENABLE_DATA_PROVIDER,
|
||||
onClick: toggleEnabled,
|
||||
},
|
||||
{
|
||||
className: FILTER_FOR_FIELD_PRESENT_CLASS_NAME,
|
||||
disabled: isLoading,
|
||||
icon: 'logstashFilter',
|
||||
name: i18n.FILTER_FOR_FIELD_PRESENT,
|
||||
onClick: onFilterForFieldPresent,
|
||||
|
@ -145,7 +138,7 @@ export const getProviderActions = ({
|
|||
timelineType === TimelineTypeEnum.template
|
||||
? {
|
||||
className: CONVERT_TO_FIELD_CLASS_NAME,
|
||||
disabled: isLoading || operator === IS_ONE_OF_OPERATOR,
|
||||
disabled: operator === IS_ONE_OF_OPERATOR,
|
||||
icon: 'visText',
|
||||
name:
|
||||
type === DataProviderTypeEnum.template
|
||||
|
@ -156,7 +149,6 @@ export const getProviderActions = ({
|
|||
: { name: null },
|
||||
{
|
||||
className: DELETE_CLASS_NAME,
|
||||
disabled: isLoading,
|
||||
icon: 'trash',
|
||||
name: i18n.DELETE_DATA_PROVIDER,
|
||||
onClick: deleteItem,
|
||||
|
@ -196,7 +188,6 @@ export class ProviderItemActions extends React.PureComponent<OwnProps> {
|
|||
field,
|
||||
isEnabled,
|
||||
isExcluded,
|
||||
isLoading,
|
||||
isOpen,
|
||||
operator,
|
||||
providerId,
|
||||
|
@ -216,7 +207,6 @@ export class ProviderItemActions extends React.PureComponent<OwnProps> {
|
|||
field,
|
||||
isEnabled,
|
||||
isExcluded,
|
||||
isLoading,
|
||||
onDataProviderEdited: this.onDataProviderEdited,
|
||||
onFilterForFieldPresent: this.onFilterForFieldPresent,
|
||||
operator,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { noop } from 'lodash/fp';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
|
@ -15,10 +14,7 @@ import {
|
|||
TimelineTypeEnum,
|
||||
} from '../../../../../common/api/timeline';
|
||||
import type { BrowserFields } from '../../../../common/containers/source';
|
||||
import {
|
||||
useDeepEqualSelector,
|
||||
useShallowEqualSelector,
|
||||
} from '../../../../common/hooks/use_selector';
|
||||
import { useShallowEqualSelector } from '../../../../common/hooks/use_selector';
|
||||
import { timelineSelectors } from '../../../store';
|
||||
import type { PrimitiveOrArrayOfPrimitives } from '../../../../common/lib/kuery';
|
||||
|
||||
|
@ -27,7 +23,6 @@ import { ProviderBadge } from './provider_badge';
|
|||
import { ProviderItemActions } from './provider_item_actions';
|
||||
import type { DataProvidersAnd, QueryOperator } from './data_provider';
|
||||
import { dragAndDropActions } from '../../../../common/store/drag_and_drop';
|
||||
import { timelineDefaults } from '../../../store/defaults';
|
||||
|
||||
interface ProviderItemBadgeProps {
|
||||
andProviderId?: string;
|
||||
|
@ -86,10 +81,6 @@ export const ProviderItemBadge = React.memo<ProviderItemBadgeProps>(
|
|||
return getTimeline(state, timelineId)?.timelineType ?? TimelineTypeEnum.default;
|
||||
});
|
||||
|
||||
const { isLoading } = useDeepEqualSelector(
|
||||
(state) => getTimeline(state, timelineId ?? '') ?? timelineDefaults
|
||||
);
|
||||
|
||||
const togglePopover = useCallback(() => {
|
||||
setIsPopoverOpen(!isPopoverOpen);
|
||||
}, [isPopoverOpen, setIsPopoverOpen]);
|
||||
|
@ -142,7 +133,7 @@ export const ProviderItemBadge = React.memo<ProviderItemBadgeProps>(
|
|||
const button = useMemo(
|
||||
() => (
|
||||
<ProviderBadge
|
||||
deleteProvider={!isLoading ? deleteProvider : noop}
|
||||
deleteProvider={deleteProvider}
|
||||
field={field}
|
||||
kqlQuery={kqlQuery}
|
||||
isEnabled={isEnabled}
|
||||
|
@ -163,7 +154,6 @@ export const ProviderItemBadge = React.memo<ProviderItemBadgeProps>(
|
|||
field,
|
||||
isEnabled,
|
||||
isExcluded,
|
||||
isLoading,
|
||||
kqlQuery,
|
||||
onToggleTypeProvider,
|
||||
operator,
|
||||
|
@ -186,7 +176,6 @@ export const ProviderItemBadge = React.memo<ProviderItemBadgeProps>(
|
|||
kqlQuery={kqlQuery}
|
||||
isEnabled={isEnabled}
|
||||
isExcluded={isExcluded}
|
||||
isLoading={isLoading}
|
||||
isOpen={isPopoverOpen}
|
||||
onDataProviderEdited={onDataProviderEdited}
|
||||
operator={operator}
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('Providers', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: false });
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({});
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
|
@ -88,28 +88,6 @@ describe('Providers', () => {
|
|||
expect(mockOnDataProviderRemoved.mock.calls[0][0].providerId).toEqual('id-Provider 1');
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onDataProviderRemoved callback when the close button is clicked', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={mockDataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="providerBadge"] [data-euiicon-type]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnDataProviderRemoved).not.toBeCalled();
|
||||
});
|
||||
|
||||
test('it invokes the onDataProviderRemoved callback when you click on the option "Delete" in the provider menu', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
|
@ -132,31 +110,6 @@ describe('Providers', () => {
|
|||
.simulate('click');
|
||||
expect(mockOnDataProviderRemoved.mock.calls[0][0].providerId).toEqual('id-Provider 1');
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onDataProviderRemoved callback when you click on the option "Delete" in the provider menu', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={mockDataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
wrapper.find('button[data-test-subj="providerBadge"]').first().simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find(`[data-test-subj="providerActions"] .${DELETE_CLASS_NAME}`)
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnDataProviderRemoved).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#onToggleDataProviderEnabled', () => {
|
||||
|
@ -191,35 +144,6 @@ describe('Providers', () => {
|
|||
providerId: 'id-Provider 1',
|
||||
});
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const mockOnToggleDataProviderEnabled = jest.spyOn(
|
||||
timelineActions,
|
||||
'updateDataProviderEnabled'
|
||||
);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={mockDataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper.find('button[data-test-subj="providerBadge"]').first().simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find(`[data-test-subj="providerActions"] .${ENABLE_CLASS_NAME}`)
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnToggleDataProviderEnabled).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#onToggleDataProviderExcluded', () => {
|
||||
|
@ -257,37 +181,6 @@ describe('Providers', () => {
|
|||
providerId: 'id-Provider 1',
|
||||
});
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const mockOnToggleDataProviderExcluded = jest.spyOn(
|
||||
timelineActions,
|
||||
'updateDataProviderExcluded'
|
||||
);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={mockDataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper.find('button[data-test-subj="providerBadge"]').first().simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find(`[data-test-subj="providerActions"] .${EXCLUDE_CLASS_NAME}`)
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnToggleDataProviderExcluded).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#ProviderWithAndProvider', () => {
|
||||
|
@ -349,35 +242,6 @@ describe('Providers', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onDataProviderRemoved callback when you click on the close button is clicked', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const dataProviders = mockDataProviders.slice(0, 1);
|
||||
dataProviders[0].and = mockDataProviders.slice(1, 3);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={mockDataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="providerBadge"]')
|
||||
.at(4)
|
||||
.find('[data-euiicon-type]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
expect(mockOnDataProviderRemoved).not.toBeCalled();
|
||||
});
|
||||
|
||||
test('it invokes the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => {
|
||||
const dataProviders = mockDataProviders.slice(0, 1);
|
||||
dataProviders[0].and = mockDataProviders.slice(1, 3);
|
||||
|
@ -420,44 +284,6 @@ describe('Providers', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onToggleDataProviderEnabled callback when you click on the option "Temporary disable" in the provider menu', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const dataProviders = mockDataProviders.slice(0, 1);
|
||||
dataProviders[0].and = mockDataProviders.slice(1, 3);
|
||||
const mockOnToggleDataProviderEnabled = jest.spyOn(
|
||||
timelineActions,
|
||||
'updateDataProviderEnabled'
|
||||
);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={dataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="providerBadge"]')
|
||||
.at(4)
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find(`[data-test-subj="providerActions"] .${ENABLE_CLASS_NAME}`)
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnToggleDataProviderEnabled).not.toBeCalled();
|
||||
});
|
||||
|
||||
test('it invokes the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => {
|
||||
const dataProviders = mockDataProviders.slice(0, 1);
|
||||
dataProviders[0].and = mockDataProviders.slice(1, 3);
|
||||
|
@ -499,43 +325,5 @@ describe('Providers', () => {
|
|||
providerId: 'id-Provider 1',
|
||||
});
|
||||
});
|
||||
|
||||
test('while loading data, it does NOT invoke the onToggleDataProviderExcluded callback when you click on the option "Exclude results" in the provider menu', () => {
|
||||
(useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: true });
|
||||
const dataProviders = mockDataProviders.slice(0, 1);
|
||||
dataProviders[0].and = mockDataProviders.slice(1, 3);
|
||||
const mockOnToggleDataProviderExcluded = jest.spyOn(
|
||||
timelineActions,
|
||||
'updateDataProviderExcluded'
|
||||
);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<DroppableWrapper droppableId="unitTest">
|
||||
<Providers
|
||||
browserFields={{}}
|
||||
dataProviders={dataProviders}
|
||||
timelineId={TimelineId.test}
|
||||
/>
|
||||
</DroppableWrapper>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="providerBadge"]')
|
||||
.at(4)
|
||||
.find('button')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find(`[data-test-subj="providerActions"] .${EXCLUDE_CLASS_NAME}`)
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnToggleDataProviderExcluded).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -100,7 +100,6 @@ const StatefulTimelineComponent: React.FC<Props> = ({
|
|||
'sessionViewConfig',
|
||||
'initialized',
|
||||
'show',
|
||||
'isLoading',
|
||||
'activeTab',
|
||||
],
|
||||
getTimeline(state, timelineId) ?? timelineDefaults
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { ConnectedProps } from 'react-redux';
|
||||
import { connect, useDispatch } from 'react-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import { InPortal } from 'react-reverse-portal';
|
||||
import type { EuiDataGridControlColumn } from '@elastic/eui';
|
||||
|
@ -25,7 +25,7 @@ import {
|
|||
} from '../../../../../flyout/document_details/shared/constants/panel_keys';
|
||||
import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features';
|
||||
import { timelineActions, timelineSelectors } from '../../../../store';
|
||||
import { timelineSelectors } from '../../../../store';
|
||||
import { useTimelineEvents } from '../../../../containers';
|
||||
import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline';
|
||||
import type { inputsModel, State } from '../../../../../common/store';
|
||||
|
@ -66,7 +66,6 @@ export const EqlTabContentComponent: React.FC<Props> = ({
|
|||
eventIdToNoteIds,
|
||||
}) => {
|
||||
const { telemetry } = useKibana().services;
|
||||
const dispatch = useDispatch();
|
||||
const { query: eqlQuery = '', ...restEqlOption } = eqlOptions;
|
||||
const { portalNode: eqlEventsCountPortalNode } = useEqlEventsCountPortal();
|
||||
const { setTimelineFullScreen, timelineFullScreen } = useTimelineFullScreen();
|
||||
|
@ -206,15 +205,6 @@ export const EqlTabContentComponent: React.FC<Props> = ({
|
|||
[dataLoadingState]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
timelineActions.updateIsLoading({
|
||||
id: timelineId,
|
||||
isLoading: isQueryLoading || loadingSourcerer,
|
||||
})
|
||||
);
|
||||
}, [loadingSourcerer, timelineId, isQueryLoading, dispatch]);
|
||||
|
||||
const unifiedHeader = useMemo(
|
||||
() => (
|
||||
<EuiFlexGroup gutterSize="s" direction="column">
|
||||
|
|
|
@ -280,15 +280,6 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
[dataLoadingState]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
timelineActions.updateIsLoading({
|
||||
id: timelineId,
|
||||
isLoading: isQueryLoading || loadingSourcerer,
|
||||
})
|
||||
);
|
||||
}, [loadingSourcerer, timelineId, isQueryLoading, dispatch]);
|
||||
|
||||
// NOTE: The timeline is blank after browser FORWARD navigation (after using back button to navigate to
|
||||
// the previous page from the timeline), yet we still see total count. This is because the timeline
|
||||
// is not getting refreshed when using browser navigation.
|
||||
|
|
|
@ -191,11 +191,6 @@ export const updateEqlOptions = actionCreator<{
|
|||
value: string | undefined;
|
||||
}>('UPDATE_EQL_OPTIONS_TIMELINE');
|
||||
|
||||
export const updateIsLoading = actionCreator<{
|
||||
id: string;
|
||||
isLoading: boolean;
|
||||
}>('UPDATE_LOADING');
|
||||
|
||||
export const setEventsLoading = actionCreator<{
|
||||
id: string;
|
||||
eventIds: string[];
|
||||
|
|
|
@ -64,7 +64,6 @@ export const timelineDefaults: SubsetTimelineModel &
|
|||
indexNames: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
itemsPerPage: 25,
|
||||
itemsPerPageOptions: [10, 25, 50, 100],
|
||||
|
|
|
@ -104,7 +104,6 @@ const basicTimeline: TimelineModel = {
|
|||
indexNames: [],
|
||||
isFavorite: false,
|
||||
isLive: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isSelectAllChecked: false,
|
||||
itemsPerPage: 25,
|
||||
|
|
|
@ -131,7 +131,6 @@ export const addTimelineToStore = ({
|
|||
...timelineById,
|
||||
[id]: {
|
||||
...timeline,
|
||||
isLoading: timelineById[id].isLoading,
|
||||
initialized: timeline.initialized ?? timelineById[id].initialized,
|
||||
resolveTimelineConfig,
|
||||
dateRange:
|
||||
|
@ -180,7 +179,6 @@ export const addNewTimeline = ({
|
|||
savedObjectId: null,
|
||||
version: null,
|
||||
isSaving: false,
|
||||
isLoading: false,
|
||||
timelineType,
|
||||
...templateTimelineInfo,
|
||||
},
|
||||
|
|
|
@ -295,7 +295,6 @@ describe('Timeline save middleware', () => {
|
|||
isFavorite: false,
|
||||
isLive: false,
|
||||
isSelectAllChecked: false,
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
itemsPerPage: 25,
|
||||
itemsPerPageOptions: [10, 25, 50, 100],
|
||||
|
|
|
@ -129,7 +129,6 @@ export interface TimelineModel {
|
|||
selectedEventIds: Record<string, TimelineNonEcsData[]>;
|
||||
/** If selectAll checkbox in header is checked **/
|
||||
isSelectAllChecked: boolean;
|
||||
isLoading: boolean;
|
||||
selectAll: boolean;
|
||||
/* discover saved search Id */
|
||||
savedSearchId: string | null;
|
||||
|
@ -190,7 +189,6 @@ export type SubsetTimelineModel = Readonly<
|
|||
| 'show'
|
||||
| 'sort'
|
||||
| 'isSaving'
|
||||
| 'isLoading'
|
||||
| 'savedObjectId'
|
||||
| 'version'
|
||||
| 'status'
|
||||
|
|
|
@ -45,7 +45,6 @@ import {
|
|||
removeColumn,
|
||||
upsertColumn,
|
||||
updateColumns,
|
||||
updateIsLoading,
|
||||
updateSort,
|
||||
clearSelected,
|
||||
setSelected,
|
||||
|
@ -409,16 +408,6 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState)
|
|||
timelineById: state.timelineById,
|
||||
}),
|
||||
}))
|
||||
.case(updateIsLoading, (state, { id, isLoading }) => ({
|
||||
...state,
|
||||
timelineById: {
|
||||
...state.timelineById,
|
||||
[id]: {
|
||||
...state.timelineById[id],
|
||||
isLoading,
|
||||
},
|
||||
},
|
||||
}))
|
||||
.case(updateSort, (state, { id, sort }) => ({
|
||||
...state,
|
||||
timelineById: updateTableSort({ id, sort, timelineById: state.timelineById }),
|
||||
|
|
|
@ -117,8 +117,6 @@ export const ALERTS_TABLE_COUNT = `[data-test-subj="toolbar-alerts-count"]`;
|
|||
|
||||
export const STAR_ICON = '[data-test-subj="timeline-favorite-empty-star"]';
|
||||
|
||||
export const TIMELINE_COLUMN_SPINNER = '[data-test-subj="timeline-loading-spinner"]';
|
||||
|
||||
export const TIMELINE_COLLAPSED_ITEMS_BTN = '[data-test-subj="euiCollapsedItemActionsButton"]';
|
||||
|
||||
export const TIMELINE_CREATE_TEMPLATE_FROM_TIMELINE_BTN =
|
||||
|
|
|
@ -57,7 +57,6 @@ import {
|
|||
TOOLTIP,
|
||||
} from '../screens/alerts';
|
||||
import { LOADING_INDICATOR, REFRESH_BUTTON } from '../screens/security_header';
|
||||
import { TIMELINE_COLUMN_SPINNER } from '../screens/timeline';
|
||||
import {
|
||||
UPDATE_ENRICHMENT_RANGE_BUTTON,
|
||||
ENRICHMENT_QUERY_END_INPUT,
|
||||
|
@ -216,7 +215,6 @@ export const goToClosedAlertsOnRuleDetailsPage = () => {
|
|||
cy.get(CLOSED_ALERTS_FILTER_BTN).click();
|
||||
cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating');
|
||||
cy.get(REFRESH_BUTTON).should('have.attr', 'aria-label', 'Refresh query');
|
||||
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
|
||||
};
|
||||
|
||||
export const goToClosedAlerts = () => {
|
||||
|
@ -233,7 +231,6 @@ export const goToClosedAlerts = () => {
|
|||
selectPageFilterValue(0, 'closed');
|
||||
cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating');
|
||||
cy.get(REFRESH_BUTTON).should('have.attr', 'aria-label', 'Refresh query');
|
||||
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
|
||||
};
|
||||
|
||||
export const goToOpenedAlertsOnRuleDetailsPage = () => {
|
||||
|
@ -297,7 +294,6 @@ export const goToAcknowledgedAlerts = () => {
|
|||
selectPageFilterValue(0, 'acknowledged');
|
||||
cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating');
|
||||
cy.get(REFRESH_BUTTON).should('have.attr', 'aria-label', 'Refresh query');
|
||||
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
|
||||
};
|
||||
|
||||
export const markAlertsAcknowledged = () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue