[Security Solution][Notes] - add feature flag, new expandable flyout tab and manage entry (#186299)

This commit is contained in:
Philippe Oberti 2024-06-18 17:39:06 -05:00 committed by GitHub
parent 0dd4f9b8c7
commit 072cad1ab8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 153 additions and 48 deletions

View file

@ -86,4 +86,5 @@ export enum SecurityPageName {
entityAnalyticsManagement = 'entity_analytics-management',
entityAnalyticsAssetClassification = 'entity_analytics-asset-classification',
coverageOverview = 'coverage-overview',
notesManagement = 'notes-management',
}

View file

@ -121,20 +121,7 @@ export const ENTITY_ANALYTICS_PATH = '/entity_analytics' as const;
export const ENTITY_ANALYTICS_MANAGEMENT_PATH = `/entity_analytics_management` as const;
export const ENTITY_ANALYTICS_ASSET_CRITICALITY_PATH =
`/entity_analytics_asset_criticality` as const;
export const APP_OVERVIEW_PATH = `${APP_PATH}${OVERVIEW_PATH}` as const;
export const APP_LANDING_PATH = `${APP_PATH}${LANDING_PATH}` as const;
export const APP_DETECTION_RESPONSE_PATH = `${APP_PATH}${DETECTION_RESPONSE_PATH}` as const;
export const APP_MANAGEMENT_PATH = `${APP_PATH}${MANAGEMENT_PATH}` as const;
export const APP_ALERTS_PATH = `${APP_PATH}${ALERTS_PATH}` as const;
export const APP_RULES_PATH = `${APP_PATH}${RULES_PATH}` as const;
export const APP_EXCEPTIONS_PATH = `${APP_PATH}${EXCEPTIONS_PATH}` as const;
export const APP_HOSTS_PATH = `${APP_PATH}${HOSTS_PATH}` as const;
export const APP_USERS_PATH = `${APP_PATH}${USERS_PATH}` as const;
export const APP_NETWORK_PATH = `${APP_PATH}${NETWORK_PATH}` as const;
export const APP_KUBERNETES_PATH = `${APP_PATH}${KUBERNETES_PATH}` as const;
export const APP_TIMELINES_PATH = `${APP_PATH}${TIMELINES_PATH}` as const;
export const APP_CASES_PATH = `${APP_PATH}${CASES_PATH}` as const;
export const APP_ENDPOINTS_PATH = `${APP_PATH}${ENDPOINTS_PATH}` as const;
export const APP_POLICIES_PATH = `${APP_PATH}${POLICIES_PATH}` as const;
@ -145,8 +132,7 @@ export const APP_HOST_ISOLATION_EXCEPTIONS_PATH =
export const APP_BLOCKLIST_PATH = `${APP_PATH}${BLOCKLIST_PATH}` as const;
export const APP_RESPONSE_ACTIONS_HISTORY_PATH =
`${APP_PATH}${RESPONSE_ACTIONS_HISTORY_PATH}` as const;
export const APP_ENTITY_ANALYTICS_PATH = `${APP_PATH}${ENTITY_ANALYTICS_PATH}` as const;
export const APP_DATA_QUALITY_PATH = `${APP_PATH}${DATA_QUALITY_PATH}` as const;
export const NOTES_MANAGEMENT_PATH = `/notes_management` as const;
// cloud logs to exclude from default index pattern
export const EXCLUDE_ELASTIC_CLOUD_INDICES = ['-*elastic-cloud-logs-*'];

View file

@ -114,6 +114,11 @@ export const allowedExperimentalValues = Object.freeze({
*/
expandableFlyoutDisabled: false,
/**
* Enables new notes
*/
notesEnabled: false,
/**
* Enables the Assistant Model Evaluation advanced setting and API endpoint, introduced in `8.11.0`.
*/

View file

@ -25,6 +25,10 @@ export const ENTITY_ANALYTICS_RISK_SCORE = i18n.translate(
}
);
export const NOTES = i18n.translate('xpack.securitySolution.navigation.notesManagement', {
defaultMessage: 'Notes',
});
export const ASSET_CRITICALITY = i18n.translate(
'xpack.securitySolution.navigation.assetCriticality',
{
@ -143,12 +147,6 @@ export const HOST_ISOLATION_EXCEPTIONS = i18n.translate(
defaultMessage: 'Host isolation exceptions',
}
);
export const DETECT = i18n.translate('xpack.securitySolution.navigation.detect', {
defaultMessage: 'Detect',
});
export const FINDINGS = i18n.translate('xpack.securitySolution.navigation.findings', {
defaultMessage: 'Findings',
});
export const EXPLORE = i18n.translate('xpack.securitySolution.navigation.explore', {
defaultMessage: 'Explore',
});
@ -177,10 +175,3 @@ export const PROTECTION_UPDATES = i18n.translate(
export const CREATE_NEW_RULE = i18n.translate('xpack.securitySolution.navigation.newRuleTitle', {
defaultMessage: 'Create new rule',
});
export const THREAT_INTELLIGENCE = i18n.translate(
'xpack.securitySolution.navigation.threatIntelligence',
{
defaultMessage: 'Intelligence',
}
);

View file

@ -0,0 +1,18 @@
/*
* 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, { memo } from 'react';
/**
* List all the notes for a document id and allows to create new notes associated with that document.
* Displayed in the document details expandable flyout left section.
*/
export const NotesDetails = memo(() => {
return <></>;
});
NotesDetails.displayName = 'NotesDetails';

View file

@ -9,6 +9,7 @@ import type { FC } from 'react';
import React, { memo, useMemo } from 'react';
import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
import { DocumentDetailsLeftPanelKey } from '../shared/constants/panel_keys';
import { useKibana } from '../../../common/lib/kibana';
import { PanelHeader } from './header';
@ -20,11 +21,12 @@ import { EventKind } from '../shared/constants/event_kinds';
import { useLeftPanelContext } from './context';
import { LeftPanelTour } from './components/tour';
export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response';
export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response' | 'notes';
export const LeftPanelVisualizeTab: LeftPanelPaths = 'visualize';
export const LeftPanelInsightsTab: LeftPanelPaths = 'insights';
export const LeftPanelInvestigationTab: LeftPanelPaths = 'investigation';
export const LeftPanelResponseTab: LeftPanelPaths = 'response';
export const LeftPanelNotesTab: LeftPanelPaths = 'notes';
export interface LeftPanelProps extends FlyoutPanelProps {
key: typeof DocumentDetailsLeftPanelKey;
@ -41,14 +43,18 @@ export const LeftPanel: FC<Partial<LeftPanelProps>> = memo(({ path }) => {
const { openLeftPanel } = useExpandableFlyoutApi();
const { eventId, indexName, scopeId, getFieldsData } = useLeftPanelContext();
const eventKind = getField(getFieldsData('event.kind'));
const notesEnabled = useIsExperimentalFeatureEnabled('notesEnabled');
const tabsDisplayed = useMemo(
() =>
const tabsDisplayed = useMemo(() => {
const tabList =
eventKind === EventKind.signal
? [tabs.insightsTab, tabs.investigationTab, tabs.responseTab]
: [tabs.insightsTab],
[eventKind]
);
: [tabs.insightsTab];
if (notesEnabled) {
tabList.push(tabs.notesTab);
}
return tabList;
}, [eventKind, notesEnabled]);
const selectedTabId = useMemo(() => {
const defaultTab = tabsDisplayed[0].id;

View file

@ -8,6 +8,7 @@
import type { ReactElement } from 'react';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { NotesTab } from './tabs/notes_tab';
import { VisualizeTab } from './tabs/visualize_tab';
import { InvestigationTab } from './tabs/investigation_tab';
import { InsightsTab } from './tabs/insights_tab';
@ -15,6 +16,7 @@ import type { LeftPanelPaths } from '.';
import {
INSIGHTS_TAB_TEST_ID,
INVESTIGATION_TAB_TEST_ID,
NOTES_TAB_TEST_ID,
RESPONSE_TAB_TEST_ID,
VISUALIZE_TAB_TEST_ID,
} from './test_ids';
@ -74,3 +76,15 @@ export const responseTab: LeftPanelTabType = {
),
content: <ResponseTab />,
};
export const notesTab: LeftPanelTabType = {
id: 'notes',
'data-test-subj': NOTES_TAB_TEST_ID,
name: (
<FormattedMessage
id="xpack.securitySolution.flyout.left.notes.tabLabel"
defaultMessage="Notes"
/>
),
content: <NotesTab />,
};

View file

@ -0,0 +1,25 @@
/*
* 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, { memo } from 'react';
import { EuiPanel } from '@elastic/eui';
import { NotesDetails } from '../components/notes_details';
import { NOTES_TAB_CONTENT_TEST_ID } from './test_ids';
/**
* Notes view displayed in the document details expandable flyout left section
* // TODO to be implemented
*/
export const NotesTab = memo(() => {
return (
<EuiPanel data-test-subj={NOTES_TAB_CONTENT_TEST_ID} hasShadow={false}>
<NotesDetails />
</EuiPanel>
);
});
NotesTab.displayName = 'NotesTab';

View file

@ -29,3 +29,4 @@ export const INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID =
`${INSIGHTS_TAB_TEST_ID}CorrelationsButton` as const;
export const INVESTIGATION_TAB_CONTENT_TEST_ID = `${PREFIX}InvestigationsTabContent` as const;
export const RESPONSE_TAB_CONTENT_TEST_ID = `${PREFIX}ResponseTabContent` as const;
export const NOTES_TAB_CONTENT_TEST_ID = `${PREFIX}NotesTabContent` as const;

View file

@ -11,3 +11,4 @@ export const VISUALIZE_TAB_TEST_ID = `${PREFIX}VisualizeTab` as const;
export const INSIGHTS_TAB_TEST_ID = `${PREFIX}InsightsTab` as const;
export const INVESTIGATION_TAB_TEST_ID = `${PREFIX}InvestigationTab` as const;
export const RESPONSE_TAB_TEST_ID = `${PREFIX}ResponseTab` as const;
export const NOTES_TAB_TEST_ID = `${PREFIX}NotesTab` as const;

View file

@ -22,6 +22,7 @@ import {
EVENT_FILTERS_PATH,
HOST_ISOLATION_EXCEPTIONS_PATH,
MANAGE_PATH,
NOTES_MANAGEMENT_PATH,
POLICIES_PATH,
RESPONSE_ACTIONS_HISTORY_PATH,
SecurityPageName,
@ -39,6 +40,7 @@ import {
TRUSTED_APPLICATIONS,
ENTITY_ANALYTICS_RISK_SCORE,
ASSET_CRITICALITY,
NOTES,
} from '../app/translations';
import { licenseService } from '../common/hooks/use_license';
import type { LinkItem } from '../common/links/types';
@ -85,6 +87,12 @@ const categories = [
}),
linkIds: [SecurityPageName.cloudDefendPolicies],
},
{
label: i18n.translate('xpack.securitySolution.appLinks.category.investigations', {
defaultMessage: 'Investigations',
}),
linkIds: [SecurityPageName.notesManagement],
},
];
export const links: LinkItem = {
@ -215,6 +223,18 @@ export const links: LinkItem = {
hideTimeline: true,
},
cloudDefendLink,
{
id: SecurityPageName.notesManagement,
title: NOTES,
description: i18n.translate('xpack.securitySolution.appLinks.notesManagementDescription', {
defaultMessage: 'Visualize and delete notes.',
}),
landingIcon: IconTool, // TODO get new icon
path: NOTES_MANAGEMENT_PATH,
skipUrlState: true,
hideTimeline: true,
experimentalKey: 'notesEnabled',
},
],
};

View file

@ -0,0 +1,18 @@
/*
* 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';
/**
* Page to allow users to manage notes. The page is accessible via the Investigations section within the Manage page.
* // TODO to be implemented
*/
export const NoteManagementPage = () => {
return <></>;
};
NoteManagementPage.displayName = 'NoteManagementPage';

View file

@ -5,14 +5,38 @@
* 2.0.
*/
import React from 'react';
import React, { memo } from 'react';
import { TrackApplicationView } from '@kbn/usage-collection-plugin/public';
import { Timelines } from './pages';
import { TIMELINES_PATH } from '../../common/constants';
import type { SecuritySubPluginRoutes } from '../app/types';
import { SecurityPageName } from '../app/types';
import { Switch } from 'react-router-dom';
import { Route } from '@kbn/shared-ux-router';
import { SpyRoute } from '../common/utils/route/spy_routes';
import { NotFoundPage } from '../app/404';
import { NoteManagementPage } from '../notes/pages/note_management_page';
import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper';
import { SecurityPageName } from '../app/types';
import type { SecuritySubPluginRoutes } from '../app/types';
import { NOTES_MANAGEMENT_PATH, TIMELINES_PATH } from '../../common/constants';
import { Timelines } from './pages';
const NoteManagementTelemetry = () => (
<PluginTemplateWrapper>
<TrackApplicationView viewId={SecurityPageName.notesManagement}>
<NoteManagementPage />
<SpyRoute pageName={SecurityPageName.notesManagement} />
</TrackApplicationView>
</PluginTemplateWrapper>
);
const NoteManagementContainer = memo(() => {
return (
<Switch>
<Route path={NOTES_MANAGEMENT_PATH} exact component={NoteManagementTelemetry} />
<Route component={NotFoundPage} />
</Switch>
);
});
NoteManagementContainer.displayName = 'NoteManagementContainer';
const TimelinesRoutes = () => (
<PluginTemplateWrapper>
@ -27,4 +51,8 @@ export const routes: SecuritySubPluginRoutes = [
path: TIMELINES_PATH,
component: TimelinesRoutes,
},
{
path: NOTES_MANAGEMENT_PATH,
component: NoteManagementContainer,
},
];

View file

@ -36624,7 +36624,6 @@
"xpack.securitySolution.navigation.case": "Cas",
"xpack.securitySolution.navigation.coverageOverviewDashboard": "Couverture MITRE ATT&CK®",
"xpack.securitySolution.navigation.dashboards": "Tableaux de bord",
"xpack.securitySolution.navigation.detect": "Détecter",
"xpack.securitySolution.navigation.detectionResponse": "Détection et réponse",
"xpack.securitySolution.navigation.detectionRules": "Règles de détection (SIEM)",
"xpack.securitySolution.navigation.ecsDataQualityDashboard": "Qualité des données",
@ -36632,7 +36631,6 @@
"xpack.securitySolution.navigation.entityRiskScore": "Score de risque des entités",
"xpack.securitySolution.navigation.exceptions": "Listes d'exceptions partagées",
"xpack.securitySolution.navigation.explore": "Explorer",
"xpack.securitySolution.navigation.findings": "Résultats",
"xpack.securitySolution.navigation.gettingStarted": "Démarrer",
"xpack.securitySolution.navigation.hosts": "Hôtes",
"xpack.securitySolution.navigation.kubernetes": "Kubernetes",
@ -36644,7 +36642,6 @@
"xpack.securitySolution.navigation.protectionUpdates": "Mises à jour de la protection",
"xpack.securitySolution.navigation.responseActionsHistory": "Historique des actions de réponse",
"xpack.securitySolution.navigation.rules": "Règles",
"xpack.securitySolution.navigation.threatIntelligence": "Intelligence",
"xpack.securitySolution.navigation.timelines": "Chronologies",
"xpack.securitySolution.navigation.users": "Utilisateurs",
"xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "Comme destination",

View file

@ -36599,7 +36599,6 @@
"xpack.securitySolution.navigation.case": "ケース",
"xpack.securitySolution.navigation.coverageOverviewDashboard": "MITRE ATT&CK®の範囲",
"xpack.securitySolution.navigation.dashboards": "ダッシュボード",
"xpack.securitySolution.navigation.detect": "検知",
"xpack.securitySolution.navigation.detectionResponse": "検出と対応",
"xpack.securitySolution.navigation.detectionRules": "検出ルールSIEM",
"xpack.securitySolution.navigation.ecsDataQualityDashboard": "データ品質",
@ -36607,7 +36606,6 @@
"xpack.securitySolution.navigation.entityRiskScore": "エンティティリスクスコア",
"xpack.securitySolution.navigation.exceptions": "共有例外リスト",
"xpack.securitySolution.navigation.explore": "探索",
"xpack.securitySolution.navigation.findings": "調査結果",
"xpack.securitySolution.navigation.gettingStarted": "使ってみる",
"xpack.securitySolution.navigation.hosts": "ホスト",
"xpack.securitySolution.navigation.kubernetes": "Kubernetes",
@ -36619,7 +36617,6 @@
"xpack.securitySolution.navigation.protectionUpdates": "保護更新",
"xpack.securitySolution.navigation.responseActionsHistory": "対応アクション履歴",
"xpack.securitySolution.navigation.rules": "ルール",
"xpack.securitySolution.navigation.threatIntelligence": "インテリジェンス",
"xpack.securitySolution.navigation.timelines": "タイムライン",
"xpack.securitySolution.navigation.users": "ユーザー",
"xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "送信先として",

View file

@ -36642,7 +36642,6 @@
"xpack.securitySolution.navigation.case": "案例",
"xpack.securitySolution.navigation.coverageOverviewDashboard": "MITRE ATT&CK® 支持",
"xpack.securitySolution.navigation.dashboards": "仪表板",
"xpack.securitySolution.navigation.detect": "检测",
"xpack.securitySolution.navigation.detectionResponse": "检测和响应",
"xpack.securitySolution.navigation.detectionRules": "检测规则 (SIEM)",
"xpack.securitySolution.navigation.ecsDataQualityDashboard": "数据质量",
@ -36650,7 +36649,6 @@
"xpack.securitySolution.navigation.entityRiskScore": "实体风险分数",
"xpack.securitySolution.navigation.exceptions": "共享例外列表",
"xpack.securitySolution.navigation.explore": "浏览",
"xpack.securitySolution.navigation.findings": "结果",
"xpack.securitySolution.navigation.gettingStarted": "开始使用",
"xpack.securitySolution.navigation.hosts": "主机",
"xpack.securitySolution.navigation.kubernetes": "Kubernetes",
@ -36662,7 +36660,6 @@
"xpack.securitySolution.navigation.protectionUpdates": "防护更新",
"xpack.securitySolution.navigation.responseActionsHistory": "响应操作历史记录",
"xpack.securitySolution.navigation.rules": "规则",
"xpack.securitySolution.navigation.threatIntelligence": "情报",
"xpack.securitySolution.navigation.timelines": "时间线",
"xpack.securitySolution.navigation.users": "用户",
"xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "作为目标",