-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Security Solution][Timeline] fix timeline favorite working for draft…
… timeline (#175161)
- Loading branch information
1 parent
99112c0
commit 0d06c17
Showing
11 changed files
with
170 additions
and
271 deletions.
There are no files selected for viewing
89 changes: 89 additions & 0 deletions
89
x-pack/plugins/security_solution/public/timelines/components/add_to_favorites/index.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import { mockTimelineModel, TestProviders } from '../../../common/mock'; | ||
import { AddToFavoritesButton } from '.'; | ||
import { TimelineStatus } from '../../../../common/api/timeline'; | ||
|
||
const mockGetState = jest.fn(); | ||
jest.mock('react-redux', () => { | ||
const original = jest.requireActual('react-redux'); | ||
return { | ||
...original, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
useSelector: (selector: any) => | ||
selector({ | ||
timeline: { | ||
timelineById: { | ||
'timeline-1': { | ||
...mockGetState(), | ||
}, | ||
}, | ||
}, | ||
}), | ||
}; | ||
}); | ||
|
||
const renderAddFavoritesButton = () => | ||
render( | ||
<TestProviders> | ||
<AddToFavoritesButton timelineId="timeline-1" /> | ||
</TestProviders> | ||
); | ||
|
||
describe('AddToFavoritesButton', () => { | ||
it('should render favorite button enabled and unchecked', () => { | ||
mockGetState.mockReturnValue({ | ||
...mockTimelineModel, | ||
status: TimelineStatus.active, | ||
}); | ||
|
||
const { getByTestId, queryByTestId } = renderAddFavoritesButton(); | ||
|
||
const button = getByTestId('timeline-favorite-empty-star'); | ||
|
||
expect(button).toBeInTheDocument(); | ||
expect(button.firstChild).toHaveAttribute('data-euiicon-type', 'starEmpty'); | ||
expect(queryByTestId('timeline-favorite-filled-star')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render favorite button disabled for a draft timeline', () => { | ||
mockGetState.mockReturnValue({ | ||
...mockTimelineModel, | ||
status: TimelineStatus.draft, | ||
}); | ||
|
||
const { getByTestId } = renderAddFavoritesButton(); | ||
|
||
expect(getByTestId('timeline-favorite-empty-star')).toHaveProperty('disabled'); | ||
}); | ||
|
||
it('should render favorite button disabled for an immutable timeline', () => { | ||
mockGetState.mockReturnValue({ | ||
...mockTimelineModel, | ||
status: TimelineStatus.immutable, | ||
}); | ||
|
||
const { getByTestId } = renderAddFavoritesButton(); | ||
|
||
expect(getByTestId('timeline-favorite-empty-star')).toHaveProperty('disabled'); | ||
}); | ||
|
||
it('should render favorite button filled for a favorite timeline', () => { | ||
mockGetState.mockReturnValue({ | ||
...mockTimelineModel, | ||
isFavorite: true, | ||
}); | ||
|
||
const { getByTestId, queryByTestId } = renderAddFavoritesButton(); | ||
|
||
expect(getByTestId('timeline-favorite-filled-star')).toBeInTheDocument(); | ||
expect(queryByTestId('timeline-favorite-empty-star')).not.toBeInTheDocument(); | ||
}); | ||
}); |
73 changes: 73 additions & 0 deletions
73
x-pack/plugins/security_solution/public/timelines/components/add_to_favorites/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React, { useCallback } from 'react'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import { EuiButtonIcon } from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
import type { State } from '../../../common/store'; | ||
import { selectTimelineById } from '../../store/selectors'; | ||
import { timelineActions } from '../../store'; | ||
import { TimelineStatus } from '../../../../common/api/timeline'; | ||
import { TIMELINE_TOUR_CONFIG_ANCHORS } from '../timeline/tour/step_config'; | ||
|
||
const ADD_TO_FAVORITES = i18n.translate( | ||
'xpack.securitySolution.timeline.addToFavoriteButtonLabel', | ||
{ | ||
defaultMessage: 'Add to favorites', | ||
} | ||
); | ||
|
||
const REMOVE_FROM_FAVORITES = i18n.translate( | ||
'xpack.securitySolution.timeline.removeFromFavoritesButtonLabel', | ||
{ | ||
defaultMessage: 'Remove from favorites', | ||
} | ||
); | ||
|
||
interface AddToFavoritesButtonProps { | ||
/** | ||
* Id of the timeline to be displayed in the bottom bar and within the modal | ||
*/ | ||
timelineId: string; | ||
} | ||
|
||
/** | ||
* This component renders the add to favorites button for timeline. | ||
* It is used in the bottom bar as well as in the timeline modal's header. | ||
*/ | ||
export const AddToFavoritesButton = React.memo<AddToFavoritesButtonProps>(({ timelineId }) => { | ||
const dispatch = useDispatch(); | ||
const { isFavorite, status } = useSelector((state: State) => | ||
selectTimelineById(state, timelineId) | ||
); | ||
|
||
const isTimelineDraftOrImmutable = status !== TimelineStatus.active; | ||
const label = isFavorite ? REMOVE_FROM_FAVORITES : ADD_TO_FAVORITES; | ||
|
||
const handleClick = useCallback( | ||
() => dispatch(timelineActions.updateIsFavorite({ id: timelineId, isFavorite: !isFavorite })), | ||
[dispatch, timelineId, isFavorite] | ||
); | ||
|
||
return ( | ||
<EuiButtonIcon | ||
id={TIMELINE_TOUR_CONFIG_ANCHORS.ADD_TO_FAVORITES} | ||
iconType={isFavorite ? 'starFilled' : 'starEmpty'} | ||
isSelected={isFavorite} | ||
disabled={isTimelineDraftOrImmutable} | ||
aria-label={label} | ||
title={label} | ||
data-test-subj={`timeline-favorite-${isFavorite ? 'filled' : 'empty'}-star`} | ||
onClick={handleClick} | ||
> | ||
{label} | ||
</EuiButtonIcon> | ||
); | ||
}); | ||
|
||
AddToFavoritesButton.displayName = 'AddToFavoritesButton'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.