diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx index 023b0202ecb63..7ccc3477a9d5d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx @@ -14,6 +14,7 @@ import { NOTES_COUNT_TEST_ID, NOTES_LOADING_TEST_ID, NOTES_TITLE_TEST_ID, + NOTES_VIEW_NOTES_BUTTON_TEST_ID, } from './test_ids'; import { FETCH_NOTES_ERROR, Notes } from './notes'; import { mockContextValue } from '../../shared/mocks/mock_context'; @@ -24,8 +25,10 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelNotesTab } from '../../left'; import { getEmptyValue } from '../../../../common/components/empty_value'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; jest.mock('@kbn/expandable-flyout'); +jest.mock('../../../../common/components/user_privileges'); const mockAddError = jest.fn(); jest.mock('../../../../common/hooks/use_app_toasts', () => ({ @@ -45,6 +48,9 @@ jest.mock('react-redux', () => { describe('', () => { beforeEach(() => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: true }, + }); jest.clearAllMocks(); }); @@ -297,4 +303,69 @@ describe('', () => { title: FETCH_NOTES_ERROR, }); }); + + it('should show View note button if user does not have the correct privileges but notes have already been created', () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false }, + }); + + const mockOpenLeftPanel = jest.fn(); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + + const contextValue = { + ...mockContextValue, + eventId: '1', + }; + + const { getByTestId, queryByTestId } = render( + + + + + + ); + + expect(mockDispatch).toHaveBeenCalled(); + + expect(getByTestId(NOTES_COUNT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1'); + + expect(queryByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + const button = getByTestId(NOTES_VIEW_NOTES_BUTTON_TEST_ID); + expect(button).toBeInTheDocument(); + + button.click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { tab: LeftPanelNotesTab }, + params: { + id: contextValue.eventId, + indexName: mockContextValue.indexName, + scopeId: mockContextValue.scopeId, + }, + }); + }); + + it('should show a - if user does not have the correct privileges and no notes have been created', () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false }, + }); + + const { getByText, queryByTestId } = render( + + + + + + ); + + expect(mockDispatch).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(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx index b0e2008c04103..e10a1ff23919f 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useCallback, useEffect } from 'react'; +import React, { memo, useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { FormattedCount } from '../../../../common/components/formatted_number'; @@ -29,6 +30,7 @@ import { NOTES_COUNT_TEST_ID, NOTES_LOADING_TEST_ID, NOTES_TITLE_TEST_ID, + NOTES_VIEW_NOTES_BUTTON_TEST_ID, } from './test_ids'; import type { State } from '../../../../common/store'; import type { Note } from '../../../../../common/api/timeline'; @@ -55,6 +57,12 @@ export const ADD_NOTE_BUTTON = i18n.translate( defaultMessage: 'Add note', } ); +export const VIEW_NOTES_BUTTON_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.flyout.right.notes.viewNoteButtonAriaLabel', + { + defaultMessage: 'View notes', + } +); /** * Renders a block with the number of notes for the event @@ -64,6 +72,7 @@ export const Notes = memo(() => { const dispatch = useDispatch(); const { eventId, indexName, scopeId, isPreview, isPreviewMode } = useDocumentDetailsContext(); const { addError: addErrorToast } = useAppToasts(); + const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); const { openLeftPanel } = useExpandableFlyoutApi(); const openExpandedFlyoutNotesTab = useCallback( @@ -101,6 +110,61 @@ export const Notes = memo(() => { } }, [addErrorToast, fetchError, fetchStatus]); + const viewNotesButton = useMemo( + () => ( + + + + ), + [isPreview, isPreviewMode, notes.length, openExpandedFlyoutNotesTab] + ); + const addNoteButton = useMemo( + () => ( + + {ADD_NOTE_BUTTON} + + ), + [isPreview, isPreviewMode, openExpandedFlyoutNotesTab] + ); + const addNoteButtonIcon = useMemo( + () => ( + + ), + [ + euiTheme.size.xs, + isPreview, + isPreviewMode, + kibanaSecuritySolutionsPrivileges.crud, + openExpandedFlyoutNotesTab, + ] + ); + return ( { ) : ( <> {notes.length === 0 ? ( - - {ADD_NOTE_BUTTON} - + <>{kibanaSecuritySolutionsPrivileges.crud ? addNoteButton : getEmptyTagValue()} ) : ( - + {kibanaSecuritySolutionsPrivileges.crud ? addNoteButtonIcon : viewNotesButton} )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index 959f8f106bb08..78afeb19e0b80 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -35,6 +35,8 @@ export const CHAT_BUTTON_TEST_ID = 'newChatByTitle' as const; export const NOTES_TITLE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesTitle` as const; export const NOTES_ADD_NOTE_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesAddNoteButton` as const; +export const NOTES_VIEW_NOTES_BUTTON_TEST_ID = + `${FLYOUT_HEADER_TEST_ID}NotesViewNotesButton` as const; export const NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesAddNoteIconButton` as const; export const NOTES_COUNT_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesCount` as const;