Skip to content

Commit

Permalink
[Security Solution][Notes] - disable note buttons in the right panel …
Browse files Browse the repository at this point in the history
…header when in preview mode (#199189)

## Summary

This PR fixes a issue where the `Add note` button and the `+` icon
button are clickable when an alert is viewed in preview mode. Users
should not be able to perform actions here, as the action expands the
flyouts and opens the left panel Notes tab, but the issue is the left
panel now shows a different alert from the right panel. If the user
closes the preview panel, they now see a different alerts on the left
and right panels but they have no way to know this.

#### Add note button disabled

https://github.com/user-attachments/assets/20554b60-39a1-4c6d-b215-e502b5b24dbd

#### + button disabled

https://github.com/user-attachments/assets/df540aed-b583-457d-a9f4-0093a171ddaa

Also adding notes should be disabled when in the rule creation page, as
we do not want to generate notes for alerts that actually do not exist
yet. To be consistent with the other blocks in the flyout header, we
show a `-`.

https://github.com/user-attachments/assets/b62ecf85-ee0f-4bee-853c-ff1034b5bf25
(cherry picked from commit 53acbab)
  • Loading branch information
PhilippeOberti committed Nov 6, 2024
1 parent 5464069 commit 79fab7f
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { Note } from '../../../../../common/api/timeline';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys';
import { LeftPanelNotesTab } from '../../left';
import { getEmptyValue } from '../../../../common/components/empty_value';

jest.mock('@kbn/expandable-flyout');

Expand All @@ -43,6 +44,10 @@ jest.mock('react-redux', () => {
});

describe('<Notes />', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should render loading spinner', () => {
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: jest.fn() });

Expand Down Expand Up @@ -99,6 +104,34 @@ describe('<Notes />', () => {
});
});

it('should disabled the Add note button if in preview mode', () => {
const contextValue = {
...mockContextValue,
isPreviewMode: true,
};

const mockOpenLeftPanel = jest.fn();
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });

const { getByTestId } = render(
<TestProviders>
<DocumentDetailsContext.Provider value={contextValue}>
<Notes />
</DocumentDetailsContext.Provider>
</TestProviders>
);

expect(mockDispatch).not.toHaveBeenCalled();

const button = getByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID);
expect(button).toBeInTheDocument();
expect(button).toBeDisabled();

button.click();

expect(mockOpenLeftPanel).not.toHaveBeenCalled();
});

it('should render number of notes and plus button', () => {
const mockOpenLeftPanel = jest.fn();
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });
Expand Down Expand Up @@ -135,6 +168,38 @@ describe('<Notes />', () => {
});
});

it('should disable the plus button if in preview mode', () => {
const mockOpenLeftPanel = jest.fn();
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });

const contextValue = {
...mockContextValue,
eventId: '1',
isPreviewMode: true,
};

const { getByTestId } = render(
<TestProviders>
<DocumentDetailsContext.Provider value={contextValue}>
<Notes />
</DocumentDetailsContext.Provider>
</TestProviders>
);

expect(getByTestId(NOTES_COUNT_TEST_ID)).toBeInTheDocument();
expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1');

expect(mockDispatch).not.toHaveBeenCalled();

const button = getByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID);

expect(button).toBeInTheDocument();
button.click();
expect(button).toBeDisabled();

expect(mockOpenLeftPanel).not.toHaveBeenCalled();
});

it('should render number of notes in scientific notation for big numbers', () => {
const createMockNote = (noteId: string): Note => ({
eventId: '1', // should be a valid id based on mockTimelineData
Expand Down Expand Up @@ -180,6 +245,30 @@ describe('<Notes />', () => {
expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1k');
});

it('should show a - when in rule creation workflow', () => {
const contextValue = {
...mockContextValue,
isPreview: true,
};

(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: jest.fn() });

const { getByText, queryByTestId } = render(
<TestProviders>
<DocumentDetailsContext.Provider value={contextValue}>
<Notes />
</DocumentDetailsContext.Provider>
</TestProviders>
);

expect(mockDispatch).not.toHaveBeenCalled();

expect(queryByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID)).not.toBeInTheDocument();
expect(queryByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID)).not.toBeInTheDocument();
expect(queryByTestId(NOTES_COUNT_TEST_ID)).not.toBeInTheDocument();
expect(getByText(getEmptyValue())).toBeInTheDocument();
});

it('should render toast error', () => {
const store = createMockStore({
...mockGlobalState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '@elastic/eui';
import { css } from '@emotion/react';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { getEmptyTagValue } from '../../../../common/components/empty_value';
import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys';
import { FormattedCount } from '../../../../common/components/formatted_number';
import { useDocumentDetailsContext } from '../../shared/context';
Expand Down Expand Up @@ -61,7 +62,7 @@ export const ADD_NOTE_BUTTON = i18n.translate(
export const Notes = memo(() => {
const { euiTheme } = useEuiTheme();
const dispatch = useDispatch();
const { eventId, indexName, scopeId } = useDocumentDetailsContext();
const { eventId, indexName, scopeId, isPreview, isPreviewMode } = useDocumentDetailsContext();
const { addError: addErrorToast } = useAppToasts();

const { openLeftPanel } = useExpandableFlyoutApi();
Expand All @@ -80,8 +81,11 @@ export const Notes = memo(() => {
);

useEffect(() => {
dispatch(fetchNotesByDocumentIds({ documentIds: [eventId] }));
}, [dispatch, eventId]);
// only fetch notes if we are not in a preview panel, or not in a rule preview workflow
if (!isPreviewMode && !isPreview) {
dispatch(fetchNotesByDocumentIds({ documentIds: [eventId] }));
}
}, [dispatch, eventId, isPreview, isPreviewMode]);

const fetchStatus = useSelector((state: State) => selectFetchNotesByDocumentIdsStatus(state));
const fetchError = useSelector((state: State) => selectFetchNotesByDocumentIdsError(state));
Expand All @@ -107,37 +111,45 @@ export const Notes = memo(() => {
}
data-test-subj={NOTES_TITLE_TEST_ID}
>
{fetchStatus === ReqStatus.Loading ? (
<EuiLoadingSpinner data-test-subj={NOTES_LOADING_TEST_ID} size="m" />
{isPreview ? (
getEmptyTagValue()
) : (
<>
{notes.length === 0 ? (
<EuiButtonEmpty
iconType="plusInCircle"
onClick={openExpandedFlyoutNotesTab}
size="s"
aria-label={ADD_NOTE_BUTTON}
data-test-subj={NOTES_ADD_NOTE_BUTTON_TEST_ID}
>
{ADD_NOTE_BUTTON}
</EuiButtonEmpty>
{fetchStatus === ReqStatus.Loading ? (
<EuiLoadingSpinner data-test-subj={NOTES_LOADING_TEST_ID} size="m" />
) : (
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="none">
<EuiFlexItem data-test-subj={NOTES_COUNT_TEST_ID}>
<FormattedCount count={notes.length} />
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
onClick={openExpandedFlyoutNotesTab}
<>
{notes.length === 0 ? (
<EuiButtonEmpty
iconType="plusInCircle"
css={css`
margin-left: ${euiTheme.size.xs};
`}
onClick={openExpandedFlyoutNotesTab}
size="s"
disabled={isPreviewMode || isPreview}
aria-label={ADD_NOTE_BUTTON}
data-test-subj={NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID}
/>
</EuiFlexItem>
</EuiFlexGroup>
data-test-subj={NOTES_ADD_NOTE_BUTTON_TEST_ID}
>
{ADD_NOTE_BUTTON}
</EuiButtonEmpty>
) : (
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="none">
<EuiFlexItem data-test-subj={NOTES_COUNT_TEST_ID}>
<FormattedCount count={notes.length} />
</EuiFlexItem>
<EuiFlexItem>
<EuiButtonIcon
onClick={openExpandedFlyoutNotesTab}
iconType="plusInCircle"
disabled={isPreviewMode || isPreview}
css={css`
margin-left: ${euiTheme.size.xs};
`}
aria-label={ADD_NOTE_BUTTON}
data-test-subj={NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID}
/>
</EuiFlexItem>
</EuiFlexGroup>
)}
</>
)}
</>
)}
Expand Down

0 comments on commit 79fab7f

Please sign in to comment.