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;