mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Security Solution][Alert details] remove enableVisualizationsInFlyout advanced setting (#220590)
## Summary This PR removes the `securitySolution:enableVisualizationsInFlyout` advanced settings that allowed users to switch between Analyzer and Session View components displayed in an overlay on top of tables, or within the flyout expanded panel. The setting was already defaulted to true, so this PR just removes the ability to go back to the analyzer and session view components displayed as table overlay. This PR is the first of 4 that perform the clean up: - this first PR that removes the advanced setting - a follow up PR that will remove the code related to rendering session view as overlay - a follow up PR that will remove the code related to rendering analyzer as overlay - a final clean up that removes a lot of dead code related to timeline full screen and such The work is divided in multiple PRs because when I got everything working locally it ended up touching nearly 120 files, making the review difficult... --------------------------- No more advanced settings  The alerts table goes to the flyout https://github.com/user-attachments/assets/b8b934ba-ea9f-4bb2-aaf4-0f73f359eb3a The table still works from the Cases page https://github.com/user-attachments/assets/65ffe289-3a3c-4766-aa52-4f68a2f2dd87 And from timeline (the tabs are not showing up either) https://github.com/user-attachments/assets/0bb17b2f-b6b7-4417-9212-2302b778cc23 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
5bc61bff26
commit
91106944ed
28 changed files with 266 additions and 1020 deletions
|
@ -1580,7 +1580,7 @@
|
|||
"\"securitySolution:enableVisualizationsInFlyout\""
|
||||
],
|
||||
"path": "src/platform/packages/shared/kbn-management/settings/setting_ids/index.ts",
|
||||
"deprecated": false,
|
||||
"deprecated": true,
|
||||
"trackAdoption": false,
|
||||
"initialIsOpen": false
|
||||
},
|
||||
|
|
|
@ -23,7 +23,6 @@ export const SECURITY_PROJECT_SETTINGS = [
|
|||
settings.SECURITY_SOLUTION_NEWS_FEED_URL_ID,
|
||||
settings.SECURITY_SOLUTION_ENABLE_NEWS_FEED_ID,
|
||||
settings.SECURITY_SOLUTION_DEFAULT_ALERT_TAGS_KEY,
|
||||
settings.SECURITY_SOLUTION_ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
|
||||
settings.SECURITY_SOLUTION_ENABLE_GRAPH_VISUALIZATION_SETTING,
|
||||
settings.SECURITY_SOLUTION_ENABLE_ASSET_INVENTORY_SETTING,
|
||||
];
|
||||
|
|
|
@ -39396,7 +39396,6 @@
|
|||
"xpack.securitySolution.flyout.right.response.sectionTitle": "Réponse",
|
||||
"xpack.securitySolution.flyout.right.rule.rulePreviewTitle": "Afficher les détails de la règle",
|
||||
"xpack.securitySolution.flyout.right.user.userPreviewTitle": "Aperçu des détails de l'utilisateur",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewInvestigateTooltip": "Investiguer dans la chronologie",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewOpenAnalyzerTooltip": "Ouvrir l'analyseur de graphe",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewTitle": "Aperçu de l'analyseur",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.errorDescription": "Une erreur empêche l'analyse de cette alerte.",
|
||||
|
@ -41229,14 +41228,11 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "Les événements des fournisseurs de données ci-dessus sont combinés avec les résultats de ce KQL",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "Score maximal d'anomalie par tâche",
|
||||
"xpack.securitySolution.timeline.source": "Source",
|
||||
"xpack.securitySolution.timeline.tabs.analyserTabTimelineTitle": "Analyseur",
|
||||
"xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline": "ES|QL",
|
||||
"xpack.securitySolution.timeline.tabs.eqlTabTimelineTitle": "Corrélation",
|
||||
"xpack.securitySolution.timeline.tabs.notesTabTimelineTitle": "Notes",
|
||||
"xpack.securitySolution.timeline.tabs.pinnedTabTimelineTitle": "Épinglé",
|
||||
"xpack.securitySolution.timeline.tabs.queyTabTimelineTitle": "Recherche",
|
||||
"xpack.securitySolution.timeline.tabs.securityAssistantTimelineTitle": "Assistant d’intelligence artificielle d’Elastic",
|
||||
"xpack.securitySolution.timeline.tabs.sessionTabTimelineTitle": "Vue de session",
|
||||
"xpack.securitySolution.timeline.tcp": "TCP",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.text": "Vous essayez d'ouvrir une chronologie, mais vous ne disposez pas de privilèges suffisants. Veuillez contacter votre administrateur afin d'obtenir les bons privilèges pour la chronologie.",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.title": "Privilèges insuffisants (choronologie)",
|
||||
|
@ -41360,12 +41356,9 @@
|
|||
"xpack.securitySolution.uiSettings.defaultTimeRangeLabel": "Période du filtre de temps",
|
||||
"xpack.securitySolution.uiSettings.enableCcsReadWarningLabel": "Avertissement lié aux privilèges de la règle CCS",
|
||||
"xpack.securitySolution.uiSettings.enableCcsWarningDescription": "<p>Active les avertissements de vérification des privilèges dans les règles relatives aux index CCS</p>",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationDescription": "<em>[version d'évaluation technique]</em> Activez la fonctionnalité de visualisation de graphe dans la solution de sécurité. <br/>Remarque : Cette fonctionnalité nécessite que le paramètre {visualizationFlyoutFeatureFlag} soit activé. <br/>Veuillez vous assurer que les deux paramètres sont activés afin d'utiliser les visualisations de graphe dans le menu volant.",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationLabel": "Activer la visualisation de graphique",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedDescription": "<p>Active le fil d'actualités</p>",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedLabel": "Fil d'actualités",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutDescription": "Activez les visualisations (analyseur et visualiseur de session) dans le menu volant des détails du document.",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutLabel": "Activer les visualisations dans le menu volant",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzer": "Exclure les niveaux froids de l'analyseur",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzerDescription": "<p>Lorsque cette option est activée, les niveaux \"cold\" et \"frozen\" sont ignorés dans les requêtes de l'analyseur</p>",
|
||||
"xpack.securitySolution.uiSettings.excludedDataTiersForRuleExecutionDescription": "Une fois configurés, les événements des niveaux de données spécifiés ne sont pas recherchés lors des exécutions de règles. <br/>Cela peut contribuer à l'amélioration des performances des règles ou à la réduction du temps d'exécution. <br/>Si vous spécifiez plusieurs niveaux de données, séparez les valeurs par des virgules. Par exemple : data_frozen,data_cold",
|
||||
|
|
|
@ -39358,7 +39358,6 @@
|
|||
"xpack.securitySolution.flyout.right.response.sectionTitle": "応答",
|
||||
"xpack.securitySolution.flyout.right.rule.rulePreviewTitle": "ルール詳細をプレビュー",
|
||||
"xpack.securitySolution.flyout.right.user.userPreviewTitle": "ユーザー詳細をプレビュー",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewInvestigateTooltip": "タイムラインで調査",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewOpenAnalyzerTooltip": "アナライザーグラフを開く",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewTitle": "アナライザープレビュー",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.errorDescription": "エラーが発生したため、このアラートを分析できません。",
|
||||
|
@ -41192,14 +41191,11 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "上のデータプロバイダーからのイベントは、この KQL からの結果と組み合わされます。",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "ジョブ別の最高異常スコア",
|
||||
"xpack.securitySolution.timeline.source": "送信元",
|
||||
"xpack.securitySolution.timeline.tabs.analyserTabTimelineTitle": "アナライザー",
|
||||
"xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline": "ES|QL",
|
||||
"xpack.securitySolution.timeline.tabs.eqlTabTimelineTitle": "相関関係",
|
||||
"xpack.securitySolution.timeline.tabs.notesTabTimelineTitle": "メモ",
|
||||
"xpack.securitySolution.timeline.tabs.pinnedTabTimelineTitle": "ピン付け済み",
|
||||
"xpack.securitySolution.timeline.tabs.queyTabTimelineTitle": "クエリー",
|
||||
"xpack.securitySolution.timeline.tabs.securityAssistantTimelineTitle": "Elastic AI Assistant",
|
||||
"xpack.securitySolution.timeline.tabs.sessionTabTimelineTitle": "セッションビュー",
|
||||
"xpack.securitySolution.timeline.tcp": "TCP",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.text": "タイムラインを開こうとしていますが、権限が不十分です。タイムラインに適切な権限を設定するには、管理者に依頼してください。",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.title": "権限が不十分です(タイムライン)",
|
||||
|
@ -41323,12 +41319,9 @@
|
|||
"xpack.securitySolution.uiSettings.defaultTimeRangeLabel": "時間フィルターの期間",
|
||||
"xpack.securitySolution.uiSettings.enableCcsReadWarningLabel": "CCSルール権限警告",
|
||||
"xpack.securitySolution.uiSettings.enableCcsWarningDescription": "<p>CCSインデックスのルールで権限チェック警告を有効にします</p>",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationDescription": "<em>[テクニカルプレビュー]</em> Securityソリューション内でグラフ視覚化機能を有効にします。<br/>注:この機能を使用するには、{visualizationFlyoutFeatureFlag}設定を有効にする必要があります。<br/>フライアウトでグラフ視覚化を実行するには、両方の設定が有効になっていることを確認してください。",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationLabel": "グラフビジュアライゼーションを有効化",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedDescription": "<p>ニュースフィードを有効にします</p>",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedLabel": "ニュースフィード",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutDescription": "ドキュメント詳細フライアウトで視覚化(アナライザーとセッションビューアー)を有効にします。",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutLabel": "フライアウトでビジュアライゼーションを有効化",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzer": "アナライザーでコールドティアとフローズンティアを除外",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzerDescription": "<p>有効にすると、アナライザークエリーでコールドティアとフローズンティアがスキップされます</p>",
|
||||
"xpack.securitySolution.uiSettings.excludedDataTiersForRuleExecutionDescription": "構成されていると、指定したデータティアのイベントがルール実行中に検索されません。<br/>このため、ルールパフォーマンスが改善されたり、実行時間が短縮されたりする場合があります。<br/>複数のデータティアを指定する場合は、値をカンマで区切ってください。例:data_frozen,data_cold",
|
||||
|
|
|
@ -39442,7 +39442,6 @@
|
|||
"xpack.securitySolution.flyout.right.response.sectionTitle": "响应",
|
||||
"xpack.securitySolution.flyout.right.rule.rulePreviewTitle": "预览规则详情",
|
||||
"xpack.securitySolution.flyout.right.user.userPreviewTitle": "预览用户详情",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewInvestigateTooltip": "在时间线中调查",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewOpenAnalyzerTooltip": "打开分析器图表",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewTitle": "分析器预览",
|
||||
"xpack.securitySolution.flyout.right.visualizations.analyzerPreview.errorDescription": "出现错误,无法分析此告警。",
|
||||
|
@ -41276,14 +41275,11 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "来自上述数据提供程序的事件与此 KQL 的结果进行组合",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "最大异常分数(按作业)",
|
||||
"xpack.securitySolution.timeline.source": "源",
|
||||
"xpack.securitySolution.timeline.tabs.analyserTabTimelineTitle": "分析器",
|
||||
"xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline": "ES|QL",
|
||||
"xpack.securitySolution.timeline.tabs.eqlTabTimelineTitle": "相关性",
|
||||
"xpack.securitySolution.timeline.tabs.notesTabTimelineTitle": "备注",
|
||||
"xpack.securitySolution.timeline.tabs.pinnedTabTimelineTitle": "已固定",
|
||||
"xpack.securitySolution.timeline.tabs.queyTabTimelineTitle": "查询",
|
||||
"xpack.securitySolution.timeline.tabs.securityAssistantTimelineTitle": "Elastic AI 助手",
|
||||
"xpack.securitySolution.timeline.tabs.sessionTabTimelineTitle": "会话视图",
|
||||
"xpack.securitySolution.timeline.tcp": "TCP",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.text": "您正尝试打开时间线,但您的权限不足。请联系管理员以便为时间线设置正确的权限。",
|
||||
"xpack.securitySolution.timeline.toast.insufficientPrivileges.title": "权限不足(时间线)",
|
||||
|
@ -41407,12 +41403,9 @@
|
|||
"xpack.securitySolution.uiSettings.defaultTimeRangeLabel": "时间筛选时段",
|
||||
"xpack.securitySolution.uiSettings.enableCcsReadWarningLabel": "CCS 规则权限警告",
|
||||
"xpack.securitySolution.uiSettings.enableCcsWarningDescription": "<p>在规则中为 CCS 索引启用权限检查警告</p>",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationDescription": "<em>[技术预览]</em> 在安全解决方案中启用 Graph 可视化功能。<br/>注意:此功能需要启用 {visualizationFlyoutFeatureFlag} 设置。<br/>请确保启用这两项设置以在浮出控件中使用 Graph 可视化。",
|
||||
"xpack.securitySolution.uiSettings.enableGraphVisualizationLabel": "启用 Graph 可视化",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedDescription": "<p>启用新闻源</p>",
|
||||
"xpack.securitySolution.uiSettings.enableNewsFeedLabel": "新闻源",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutDescription": "在文档详情浮出控件中启用可视化(分析器和会话查看器)。",
|
||||
"xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutLabel": "在浮出控件中启用可视化",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzer": "在分析器中排除冷层和冻结层",
|
||||
"xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzerDescription": "<p>启用后,将在分析器查询中跳过冷层和冻结层</p>",
|
||||
"xpack.securitySolution.uiSettings.excludedDataTiersForRuleExecutionDescription": "配置之后,将不会在执行规则期间搜索指定数据层中的事件。<br/>这可能有助于提高规则性能或缩短执行时间。<br/>如果指定了多个数据层,请用逗号分隔值。例如:data_frozen,data_cold",
|
||||
|
|
|
@ -19,7 +19,6 @@ export { SecurityPageName } from '@kbn/security-solution-navigation';
|
|||
*/
|
||||
export const APP_ID = 'securitySolution' as const;
|
||||
export const APP_UI_ID = 'securitySolutionUI' as const;
|
||||
export const ASSET_INVENTORY_FEATURE_ID = 'securitySolutionAssetInventory' as const;
|
||||
export const ASSISTANT_FEATURE_ID = 'securitySolutionAssistant' as const;
|
||||
export const ATTACK_DISCOVERY_FEATURE_ID = 'securitySolutionAttackDiscovery' as const;
|
||||
export const CASES_FEATURE_ID = 'securitySolutionCasesV3' as const;
|
||||
|
@ -28,7 +27,6 @@ export const NOTES_FEATURE_ID = 'securitySolutionNotes' as const;
|
|||
export const SERVER_APP_ID = 'siem' as const;
|
||||
export const SECURITY_FEATURE_ID = 'siemV2' as const;
|
||||
export const APP_NAME = 'Security' as const;
|
||||
export const APP_ICON = 'securityAnalyticsApp' as const;
|
||||
export const APP_ICON_SOLUTION = 'logoSecurity' as const;
|
||||
export const APP_PATH = `/app/security` as const;
|
||||
export const APP_INTEGRATIONS_PATH = `/app/integrations` as const;
|
||||
|
@ -112,9 +110,6 @@ export const NETWORK_PATH = '/network' as const;
|
|||
export const MANAGEMENT_PATH = '/administration' as const;
|
||||
export const COVERAGE_OVERVIEW_PATH = '/rules_coverage_overview' as const;
|
||||
export const THREAT_INTELLIGENCE_PATH = '/threat_intelligence' as const;
|
||||
export const INVESTIGATIONS_PATH = '/investigations' as const;
|
||||
export const MACHINE_LEARNING_PATH = '/ml' as const;
|
||||
export const ASSETS_PATH = '/assets' as const;
|
||||
export const ENDPOINTS_PATH = `${MANAGEMENT_PATH}/endpoints` as const;
|
||||
export const POLICIES_PATH = `${MANAGEMENT_PATH}/policy` as const;
|
||||
export const TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/trusted_apps` as const;
|
||||
|
@ -216,10 +211,6 @@ export const EXTENDED_RULE_EXECUTION_LOGGING_MIN_LEVEL_SETTING =
|
|||
export const EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION =
|
||||
'securitySolution:excludedDataTiersForRuleExecution' as const;
|
||||
|
||||
/** This Kibana Advanced Setting allows users to enable/disable the Visualizations in Flyout feature */
|
||||
export const ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING =
|
||||
'securitySolution:enableVisualizationsInFlyout' as const;
|
||||
|
||||
/** This Kibana Advanced Setting allows users to enable/disable the Graph Visualizations for alerts and events */
|
||||
export const ENABLE_GRAPH_VISUALIZATION_SETTING =
|
||||
'securitySolution:enableGraphVisualization' as const;
|
||||
|
@ -292,7 +283,6 @@ export const TIMELINE_COPY_URL = `${TIMELINE_URL}/_copy` as const;
|
|||
|
||||
export const NOTE_URL = '/api/note' as const;
|
||||
export const PINNED_EVENT_URL = '/api/pinned_event' as const;
|
||||
export const SOURCERER_API_URL = '/internal/security_solution/sourcerer' as const;
|
||||
|
||||
/**
|
||||
* This limit exists to maintain some kind of a safety net for how many events we are fetching in total,
|
||||
|
@ -360,18 +350,6 @@ export const NOTIFICATION_DEFAULT_FREQUENCY = {
|
|||
summary: true,
|
||||
};
|
||||
|
||||
export const showAllOthersBucket: string[] = [
|
||||
'destination.ip',
|
||||
'event.action',
|
||||
'event.category',
|
||||
'event.dataset',
|
||||
'event.module',
|
||||
'signal.rule.threat.tactic.name',
|
||||
'source.ip',
|
||||
'destination.ip',
|
||||
'user.name',
|
||||
];
|
||||
|
||||
export const TRANSFORM_STATES = {
|
||||
ABORTING: 'aborting',
|
||||
FAILED: 'failed',
|
||||
|
|
|
@ -46,15 +46,6 @@ jest.mock(
|
|||
})
|
||||
);
|
||||
|
||||
const mockUseUiSetting = jest.fn().mockReturnValue([true]);
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
useUiSetting$: () => mockUseUiSetting(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('./add_note_icon_item', () => {
|
||||
return {
|
||||
AddEventNoteAction: jest.fn(() => <div data-test-subj="add-note-mock-action" />),
|
||||
|
@ -76,9 +67,6 @@ jest.mock('../../lib/kibana', () => {
|
|||
},
|
||||
},
|
||||
cases: mockCasesContract(),
|
||||
uiSettings: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
savedObjects: {
|
||||
client: {},
|
||||
},
|
||||
|
@ -390,24 +378,6 @@ describe('Actions', () => {
|
|||
expect(wrapper.find('[data-test-subj="view-in-analyzer"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it does not render the analyze event button on the cases alerts table with advanced settings disabled', () => {
|
||||
const ecsData = {
|
||||
...mockTimelineData[0].ecs,
|
||||
event: { kind: ['alert'] },
|
||||
agent: { type: ['endpoint'] },
|
||||
process: { entity_id: ['1'] },
|
||||
};
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Actions {...defaultProps} ecsData={ecsData} timelineId={TableId.alertsOnCasePage} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="view-in-analyzer"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it does render the analyze event button on the cases alerts table with advanced settings enabled', () => {
|
||||
const ecsData = {
|
||||
...mockTimelineData[0].ecs,
|
||||
|
@ -415,7 +385,6 @@ describe('Actions', () => {
|
|||
agent: { type: ['endpoint'] },
|
||||
process: { entity_id: ['1'] },
|
||||
};
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
|
@ -433,7 +402,6 @@ describe('Actions', () => {
|
|||
agent: { type: ['endpoint'] },
|
||||
process: { entity_id: ['1'] },
|
||||
};
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
|
@ -462,28 +430,6 @@ describe('Actions', () => {
|
|||
expect(wrapper.find('[data-test-subj="session-view-button"]').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
test('it should show session view button on action tabs when user access the session viewer via K8S dashboard', () => {
|
||||
const ecsData = {
|
||||
...mockTimelineData[0].ecs,
|
||||
event: { kind: ['alert'] },
|
||||
agent: { type: ['endpoint'] },
|
||||
process: { entry_leader: { entity_id: ['test_id'], start: ['2022-05-08T13:44:00.13Z'] } },
|
||||
_index: '.ds-logs-endpoint.events.process-default',
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Actions
|
||||
{...defaultProps}
|
||||
ecsData={ecsData}
|
||||
timelineId={TableId.kubernetesPageSessions}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="session-view-button"]').exists()).toEqual(true);
|
||||
});
|
||||
|
||||
test('it should show session view button on action tabs for enterprise users', () => {
|
||||
const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
|
||||
|
||||
|
@ -506,25 +452,6 @@ describe('Actions', () => {
|
|||
expect(wrapper.find('[data-test-subj="session-view-button"]').exists()).toEqual(true);
|
||||
});
|
||||
|
||||
test('it does not render the session view button on the cases alerts table with advanced settings disabled', () => {
|
||||
const ecsData = {
|
||||
...mockTimelineData[0].ecs,
|
||||
event: { kind: ['alert'] },
|
||||
agent: { type: ['endpoint'] },
|
||||
process: { entry_leader: { entity_id: ['test_id'], start: ['2022-05-08T13:44:00.13Z'] } },
|
||||
_index: '.ds-logs-endpoint.events.process-default',
|
||||
};
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Actions {...defaultProps} ecsData={ecsData} timelineId={TableId.alertsOnCasePage} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="session-view-button"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it does render the session view button on the cases alerts table with advanced settings enabled', () => {
|
||||
const ecsData = {
|
||||
...mockTimelineData[0].ecs,
|
||||
|
@ -533,7 +460,6 @@ describe('Actions', () => {
|
|||
process: { entry_leader: { entity_id: ['test_id'], start: ['2022-05-08T13:44:00.13Z'] } },
|
||||
_index: '.ds-logs-endpoint.events.process-default',
|
||||
};
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
|
|
|
@ -9,12 +9,9 @@ import React, { useCallback, useMemo } from 'react';
|
|||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
import { TimelineTabs, TableId } from '@kbn/securitysolution-data-table';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../common/constants';
|
||||
import {
|
||||
makeSelectNotesByDocumentId,
|
||||
makeSelectDocumentNotesBySavedObjectId,
|
||||
makeSelectNotesByDocumentId,
|
||||
} from '../../../notes/store/notes.slice';
|
||||
import type { State } from '../../store';
|
||||
import { selectTimelineById } from '../../../timelines/store/selectors';
|
||||
|
@ -23,7 +20,7 @@ import {
|
|||
getEventType,
|
||||
getPinOnClick,
|
||||
} from '../../../timelines/components/timeline/body/helpers';
|
||||
import { getScopedActions, isTimelineScope } from '../../../helpers';
|
||||
import { isTimelineScope } from '../../../helpers';
|
||||
import { useIsInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver';
|
||||
import { timelineActions } from '../../../timelines/store';
|
||||
import type { ActionProps, OnPinEvent } from '../../../../common/types';
|
||||
|
@ -34,9 +31,7 @@ import { useShallowEqualSelector } from '../../hooks/use_selector';
|
|||
import { timelineDefaults } from '../../../timelines/store/defaults';
|
||||
import { useStartTransaction } from '../../lib/apm/use_start_transaction';
|
||||
import { useLicense } from '../../hooks/use_license';
|
||||
import { useGlobalFullScreen, useTimelineFullScreen } from '../../containers/use_full_screen';
|
||||
import { ALERTS_ACTIONS } from '../../lib/apm/user_actions';
|
||||
import { setActiveTabTimeline } from '../../../timelines/store/actions';
|
||||
import { EventsTdContent } from '../../../timelines/components/timeline/styles';
|
||||
import { AlertContextMenu } from '../../../detections/components/alerts_table/timeline_actions/alert_context_menu';
|
||||
import { InvestigateInTimelineAction } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_timeline_action';
|
||||
|
@ -113,10 +108,6 @@ const ActionsComponent: React.FC<ActionProps> = ({
|
|||
);
|
||||
}, [ecsData, eventType]);
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
|
||||
const { navigateToAnalyzer } = useNavigateToAnalyzer({
|
||||
isFlyoutOpen: false,
|
||||
eventId,
|
||||
|
@ -131,41 +122,10 @@ const ActionsComponent: React.FC<ActionProps> = ({
|
|||
scopeId: timelineId,
|
||||
});
|
||||
|
||||
const { setGlobalFullScreen } = useGlobalFullScreen();
|
||||
const { setTimelineFullScreen } = useTimelineFullScreen();
|
||||
const handleClick = useCallback(() => {
|
||||
startTransaction({ name: ALERTS_ACTIONS.OPEN_ANALYZER });
|
||||
|
||||
if (visualizationInFlyoutEnabled) {
|
||||
navigateToAnalyzer();
|
||||
} else {
|
||||
const scopedActions = getScopedActions(timelineId);
|
||||
|
||||
const dataGridIsFullScreen = document.querySelector('.euiDataGrid--fullScreen');
|
||||
if (scopedActions) {
|
||||
dispatch(scopedActions.updateGraphEventId({ id: timelineId, graphEventId: ecsData._id }));
|
||||
}
|
||||
if (timelineId === TimelineId.active) {
|
||||
if (dataGridIsFullScreen) {
|
||||
setTimelineFullScreen(true);
|
||||
}
|
||||
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph }));
|
||||
} else {
|
||||
if (dataGridIsFullScreen) {
|
||||
setGlobalFullScreen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
startTransaction,
|
||||
timelineId,
|
||||
dispatch,
|
||||
ecsData._id,
|
||||
setTimelineFullScreen,
|
||||
setGlobalFullScreen,
|
||||
visualizationInFlyoutEnabled,
|
||||
navigateToAnalyzer,
|
||||
]);
|
||||
navigateToAnalyzer();
|
||||
}, [startTransaction, navigateToAnalyzer]);
|
||||
|
||||
const sessionViewConfig = useMemo(() => {
|
||||
const { process, _id, _index, timestamp, kibana } = ecsData;
|
||||
|
@ -193,46 +153,9 @@ const ActionsComponent: React.FC<ActionProps> = ({
|
|||
}, [ecsData, eventType]);
|
||||
|
||||
const openSessionView = useCallback(() => {
|
||||
const dataGridIsFullScreen = document.querySelector('.euiDataGrid--fullScreen');
|
||||
startTransaction({ name: ALERTS_ACTIONS.OPEN_SESSION_VIEW });
|
||||
|
||||
if (
|
||||
visualizationInFlyoutEnabled &&
|
||||
sessionViewConfig !== null &&
|
||||
timelineId !== TableId.kubernetesPageSessions
|
||||
) {
|
||||
navigateToSessionView();
|
||||
} else {
|
||||
const scopedActions = getScopedActions(timelineId);
|
||||
|
||||
if (timelineId === TimelineId.active) {
|
||||
if (dataGridIsFullScreen) {
|
||||
setTimelineFullScreen(true);
|
||||
}
|
||||
if (sessionViewConfig !== null) {
|
||||
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.session }));
|
||||
}
|
||||
} else {
|
||||
if (dataGridIsFullScreen) {
|
||||
setGlobalFullScreen(true);
|
||||
}
|
||||
}
|
||||
if (sessionViewConfig !== null) {
|
||||
if (scopedActions) {
|
||||
dispatch(scopedActions.updateSessionViewConfig({ id: timelineId, sessionViewConfig }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
startTransaction,
|
||||
timelineId,
|
||||
sessionViewConfig,
|
||||
setTimelineFullScreen,
|
||||
dispatch,
|
||||
setGlobalFullScreen,
|
||||
visualizationInFlyoutEnabled,
|
||||
navigateToSessionView,
|
||||
]);
|
||||
navigateToSessionView();
|
||||
}, [navigateToSessionView, startTransaction]);
|
||||
|
||||
const { activeStep, isTourShown, incrementStep } = useTourContext();
|
||||
|
||||
|
@ -293,27 +216,17 @@ const ActionsComponent: React.FC<ActionProps> = ({
|
|||
|
||||
// we hide the analyzer icon if the data is not available for the resolver
|
||||
// or if we are on the cases alerts table and the the visualization in flyout advanced setting is disabled
|
||||
const ecsHasDataForAnalyzer = useIsInvestigateInResolverActionEnabled(ecsData);
|
||||
const showAnalyzerIcon = useMemo(() => {
|
||||
return (
|
||||
ecsHasDataForAnalyzer &&
|
||||
(timelineId !== TableId.alertsOnCasePage ||
|
||||
(timelineId === TableId.alertsOnCasePage && visualizationInFlyoutEnabled))
|
||||
);
|
||||
}, [ecsHasDataForAnalyzer, timelineId, visualizationInFlyoutEnabled]);
|
||||
const showAnalyzerIcon = useIsInvestigateInResolverActionEnabled(ecsData);
|
||||
|
||||
// we hide the session view icon if the session view is not available
|
||||
// or if we are on the cases alerts table and the the visualization in flyout advanced setting is disabled
|
||||
// or if the user is not on an enterprise license or on the kubernetes page
|
||||
const isEnterprisePlus = useLicense().isEnterprise();
|
||||
const showSessionViewIcon = useMemo(() => {
|
||||
return (
|
||||
sessionViewConfig !== null &&
|
||||
(isEnterprisePlus || timelineId === TableId.kubernetesPageSessions) &&
|
||||
(timelineId !== TableId.alertsOnCasePage ||
|
||||
(timelineId === TableId.alertsOnCasePage && visualizationInFlyoutEnabled))
|
||||
);
|
||||
}, [sessionViewConfig, isEnterprisePlus, timelineId, visualizationInFlyoutEnabled]);
|
||||
const showSessionViewIcon = useMemo(
|
||||
() => sessionViewConfig !== null && isEnterprisePlus,
|
||||
|
||||
[isEnterprisePlus, sessionViewConfig]
|
||||
);
|
||||
|
||||
return (
|
||||
<ActionsContainer data-test-subj="actions-container">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState, useCallback, useMemo, memo, type FC } from 'react';
|
||||
import React, { type FC, memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type { EuiDataGridRowHeightsOptions, EuiDataGridStyle } from '@elastic/eui';
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
|
@ -25,19 +25,14 @@ import { useAlertsContext } from './alerts_context';
|
|||
import { useBulkActionsByTableType } from '../../hooks/trigger_actions_alert_table/use_bulk_actions';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
import type {
|
||||
SecurityAlertsTableContext,
|
||||
GetSecurityAlertsTableProp,
|
||||
SecurityAlertsTableContext,
|
||||
SecurityAlertsTableProps,
|
||||
} from './types';
|
||||
import { ActionsCell } from './actions_cell';
|
||||
import { useGlobalTime } from '../../../common/containers/use_global_time';
|
||||
import { useLicense } from '../../../common/hooks/use_license';
|
||||
import {
|
||||
APP_ID,
|
||||
CASES_FEATURE_ID,
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
|
||||
VIEW_SELECTION,
|
||||
} from '../../../../common/constants';
|
||||
import { APP_ID, CASES_FEATURE_ID, VIEW_SELECTION } from '../../../../common/constants';
|
||||
import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants';
|
||||
import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers';
|
||||
import { eventsDefaultModel } from '../../../common/components/events_viewer/default_model';
|
||||
|
@ -54,9 +49,9 @@ import { StatefulEventContext } from '../../../common/components/events_viewer/s
|
|||
import { useSourcererDataView } from '../../../sourcerer/containers';
|
||||
import type { RunTimeMappings } from '../../../sourcerer/store/model';
|
||||
import { SourcererScopeName } from '../../../sourcerer/store/model';
|
||||
import { useKibana, useUiSetting$ } from '../../../common/lib/kibana';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { getColumns, CellValue } from '../../configurations/security_solution_detections';
|
||||
import { CellValue, getColumns } from '../../configurations/security_solution_detections';
|
||||
import { buildTimeRangeFilter } from './helpers';
|
||||
import { useUserPrivileges } from '../../../common/components/user_privileges';
|
||||
import * as i18n from './translations';
|
||||
|
@ -169,9 +164,6 @@ const DetectionEngineAlertsTableComponent: FC<Omit<DetectionEngineAlertTableProp
|
|||
settings,
|
||||
cases,
|
||||
} = useKibana().services;
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
const { alertsTableRef } = useAlertsContext();
|
||||
|
||||
const { from, to, setQuery } = useGlobalTime();
|
||||
|
@ -350,15 +342,6 @@ const DetectionEngineAlertsTableComponent: FC<Omit<DetectionEngineAlertTableProp
|
|||
if (!canReadNotes || securitySolutionNotesDisabled) {
|
||||
ACTION_BUTTON_COUNT--;
|
||||
}
|
||||
// we do not show the analyzer graph and session view icons on the cases alerts tab alerts table
|
||||
// if the visualization in flyout advanced settings is disabled because these aren't supported inside the table
|
||||
if (tableType === TableId.alertsOnCasePage) {
|
||||
if (!isEnterprisePlus && !visualizationInFlyoutEnabled) {
|
||||
ACTION_BUTTON_COUNT -= 1;
|
||||
} else if (isEnterprisePlus && !visualizationInFlyoutEnabled) {
|
||||
ACTION_BUTTON_COUNT -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
const leadingControlColumn = useMemo(
|
||||
() => getDefaultControlColumn(ACTION_BUTTON_COUNT)[0],
|
||||
|
|
|
@ -9,10 +9,8 @@ import type { FC } from 'react';
|
|||
import React, { memo, useMemo } from 'react';
|
||||
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
import { useUserPrivileges } from '../../../common/components/user_privileges';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../common/constants';
|
||||
import { DocumentDetailsLeftPanelKey } from '../shared/constants/panel_keys';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { PanelHeader } from './header';
|
||||
|
@ -44,10 +42,6 @@ export const LeftPanel: FC<Partial<DocumentDetailsProps>> = memo(({ path }) => {
|
|||
notesPrivileges: { read: canSeeNotes },
|
||||
} = useUserPrivileges();
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
|
||||
const tabsDisplayed = useMemo(() => {
|
||||
const tabList =
|
||||
eventKind === EventKind.signal
|
||||
|
@ -56,17 +50,11 @@ export const LeftPanel: FC<Partial<DocumentDetailsProps>> = memo(({ path }) => {
|
|||
if (canSeeNotes && !securitySolutionNotesDisabled && !isPreview) {
|
||||
tabList.push(tabs.notesTab);
|
||||
}
|
||||
if (visualizationInFlyoutEnabled && !isPreview) {
|
||||
if (!isPreview) {
|
||||
return [tabs.visualizeTab, ...tabList];
|
||||
}
|
||||
return tabList;
|
||||
}, [
|
||||
eventKind,
|
||||
isPreview,
|
||||
canSeeNotes,
|
||||
securitySolutionNotesDisabled,
|
||||
visualizationInFlyoutEnabled,
|
||||
]);
|
||||
}, [eventKind, isPreview, canSeeNotes, securitySolutionNotesDisabled]);
|
||||
|
||||
const selectedTabId = useMemo(() => {
|
||||
const defaultTab = tabsDisplayed[0].id;
|
||||
|
|
|
@ -39,14 +39,6 @@ jest.mock('../../shared/hooks/use_navigate_to_analyzer', () => {
|
|||
return { useNavigateToAnalyzer: () => ({ navigateToAnalyzer: mockNavigateToAnalyzer }) };
|
||||
});
|
||||
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
useUiSetting$: () => mockUseUiSetting(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => {
|
||||
const actual = jest.requireActual('react-router-dom');
|
||||
return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) };
|
||||
|
@ -60,15 +52,6 @@ jest.mock('react-redux', () => {
|
|||
};
|
||||
});
|
||||
|
||||
const mockUseUiSetting = jest.fn().mockReturnValue([false]);
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
useUiSetting$: () => mockUseUiSetting(),
|
||||
};
|
||||
});
|
||||
|
||||
const NO_ANALYZER_MESSAGE =
|
||||
'You can only visualize events triggered by hosts configured with the Elastic Defend integration or any sysmon data from winlogbeat. Refer to Visual event analyzer(external, opens in a new tab or window) for more information.';
|
||||
|
||||
|
@ -138,132 +121,61 @@ describe('AnalyzerPreviewContainer', () => {
|
|||
).toHaveTextContent(NO_ANALYZER_MESSAGE);
|
||||
});
|
||||
|
||||
describe('when visualizationInFlyoutEnabled is disabled', () => {
|
||||
it('should navigate to analyzer in timeline when clicking on title', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(investigateInTimelineAlertClick).toHaveBeenCalled();
|
||||
it('should open left flyout visualization tab when clicking on title', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
it('should not navigate to analyzer when in preview and clicking on title', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
expect(investigateInTimelineAlertClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not navigate to analyzer when in preview mode', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
const { queryByTestId } = renderAnalyzerPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
expect(investigateInTimelineAlertClick).not.toHaveBeenCalled();
|
||||
});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when visualizationInFlyoutEnabled is enabled', () => {
|
||||
it('should open left flyout visualization tab when clicking on title', () => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
it('should disable link when in rule preview', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
it('should disable link when in rule preview', () => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
it('should disable link when in preview mode', () => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
it('should disable link when in preview mode', () => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
|
||||
const { queryByTestId } = renderAnalyzerPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
const { queryByTestId } = renderAnalyzerPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -271,82 +183,37 @@ describe('AnalyzerPreviewContainer', () => {
|
|||
beforeEach(() => {
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
|
||||
});
|
||||
describe('when visualizationInFlyoutEnabled is enabled', () => {
|
||||
beforeEach(() => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
beforeEach(() => {
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
it('should open left flyout visualization tab when clicking on title', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disable link when in rule preview', () => {
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render link when in preview mode', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreviewMode: true });
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
});
|
||||
it('should open left flyout visualization tab when clicking on title', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
|
||||
describe('when visualizationInFlyoutEnabled is disabled', () => {
|
||||
beforeEach(() => {
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
error: false,
|
||||
alertIds: ['alertid'],
|
||||
statsNodes: mock.mockStatsNodes,
|
||||
});
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
});
|
||||
it('should navigate to analyzer in timeline when clicking on title', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(investigateInTimelineAlertClick).toHaveBeenCalled();
|
||||
});
|
||||
it('should disable link when in rule preview', () => {
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not navigate to analyzer when in preview and clicking on title', () => {
|
||||
const { queryByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreview: true });
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
expect(investigateInTimelineAlertClick).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should render link when in preview mode', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview({ ...mockContextValue, isPreviewMode: true });
|
||||
|
||||
it('should open analyzer in timelinewhen in preview mode', () => {
|
||||
const { getByTestId } = renderAnalyzerPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(investigateInTimelineAlertClick).toHaveBeenCalled();
|
||||
});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToAnalyzer).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,18 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { TimelineTabs } from '@kbn/securitysolution-data-table';
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiLink, EuiMark } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants';
|
||||
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
|
||||
import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline';
|
||||
import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions';
|
||||
import { getScopedActions } from '../../../../helpers';
|
||||
import { setActiveTabTimeline } from '../../../../timelines/store/actions';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver';
|
||||
import { AnalyzerPreview } from './analyzer_preview';
|
||||
|
@ -25,8 +16,6 @@ import { useNavigateToAnalyzer } from '../../shared/hooks/use_navigate_to_analyz
|
|||
import { ExpandablePanel } from '../../../shared/components/expandable_panel';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
|
||||
|
||||
const timelineId = 'timeline-1';
|
||||
|
||||
/**
|
||||
* Analyzer preview under Overview, Visualizations. It shows a tree representation of analyzer.
|
||||
*/
|
||||
|
@ -34,37 +23,12 @@ export const AnalyzerPreviewContainer: React.FC = () => {
|
|||
const { dataAsNestedObject, isPreview, eventId, indexName, scopeId, isPreviewMode } =
|
||||
useDocumentDetailsContext();
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
const isNewNavigationEnabled = !useIsExperimentalFeatureEnabled(
|
||||
'newExpandableFlyoutNavigationDisabled'
|
||||
);
|
||||
// decide whether to show the analyzer preview or not
|
||||
const isEnabled = useIsInvestigateInResolverActionEnabled(dataAsNestedObject);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { startTransaction } = useStartTransaction();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({
|
||||
ecsRowData: dataAsNestedObject,
|
||||
});
|
||||
|
||||
// open timeline to the analyzer tab because the expandable flyout left panel Visualize => Analyzer tab is not ready
|
||||
const goToAnalyzerTab = useCallback(async () => {
|
||||
// open timeline
|
||||
await investigateInTimelineAlertClick();
|
||||
|
||||
// open analyzer tab
|
||||
startTransaction({ name: ALERTS_ACTIONS.OPEN_ANALYZER });
|
||||
const scopedActions = getScopedActions(timelineId);
|
||||
if (scopedActions && dataAsNestedObject) {
|
||||
dispatch(
|
||||
scopedActions.updateGraphEventId({ id: timelineId, graphEventId: dataAsNestedObject._id })
|
||||
);
|
||||
}
|
||||
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph }));
|
||||
}, [dataAsNestedObject, dispatch, investigateInTimelineAlertClick, startTransaction]);
|
||||
|
||||
const { navigateToAnalyzer } = useNavigateToAnalyzer({
|
||||
eventId,
|
||||
indexName,
|
||||
|
@ -73,10 +37,7 @@ export const AnalyzerPreviewContainer: React.FC = () => {
|
|||
isPreviewMode,
|
||||
});
|
||||
|
||||
const iconType = useMemo(() => {
|
||||
const icon = visualizationInFlyoutEnabled ? 'arrowStart' : 'timeline';
|
||||
return !isPreviewMode ? icon : undefined;
|
||||
}, [visualizationInFlyoutEnabled, isPreviewMode]);
|
||||
const iconType = useMemo(() => (!isPreviewMode ? 'arrowStart' : undefined), [isPreviewMode]);
|
||||
|
||||
const isNavigationEnabled = useMemo(() => {
|
||||
// if the analyzer is not enabled or in rule preview mode, the navigation is not enabled
|
||||
|
@ -103,17 +64,12 @@ export const AnalyzerPreviewContainer: React.FC = () => {
|
|||
iconType,
|
||||
...(isNavigationEnabled && {
|
||||
link: {
|
||||
callback: visualizationInFlyoutEnabled ? navigateToAnalyzer : goToAnalyzerTab,
|
||||
tooltip: visualizationInFlyoutEnabled ? (
|
||||
callback: navigateToAnalyzer,
|
||||
tooltip: (
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewOpenAnalyzerTooltip"
|
||||
defaultMessage="Open analyzer graph"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewInvestigateTooltip"
|
||||
defaultMessage="Investigate in timeline"
|
||||
/>
|
||||
),
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -9,8 +9,8 @@ import React from 'react';
|
|||
import { render } from '@testing-library/react';
|
||||
import { useFetchGraphData } from '@kbn/cloud-security-posture-graph/src/hooks';
|
||||
import {
|
||||
uiMetricService,
|
||||
GRAPH_PREVIEW,
|
||||
uiMetricService,
|
||||
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
|
@ -36,15 +36,6 @@ jest.mock('@kbn/cloud-security-posture-common/utils/ui_metrics', () => ({
|
|||
|
||||
const uiMetricServiceMock = uiMetricService as jest.Mocked<typeof uiMetricService>;
|
||||
|
||||
const mockUseUiSetting = jest.fn().mockReturnValue([true]);
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
useUiSetting$: () => mockUseUiSetting(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../../common/hooks/use_experimental_features', () => ({
|
||||
useIsExperimentalFeatureEnabled: jest.fn(),
|
||||
}));
|
||||
|
@ -355,58 +346,6 @@ describe('<GraphPreviewContainer />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should render component and without link in header when expanding flyout feature is disabled', async () => {
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
mockUseFetchGraphData.mockReturnValue({
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
data: { nodes: DEFAULT_NODES, edges: [] },
|
||||
});
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
(useGraphPreview as jest.Mock).mockReturnValue({
|
||||
timestamp,
|
||||
eventIds: [],
|
||||
hasGraphRepresentation: true,
|
||||
isAlert: true,
|
||||
});
|
||||
|
||||
const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview();
|
||||
|
||||
// Using findByTestId to wait for the component to be rendered because it is a lazy loaded component
|
||||
expect(await findByTestId(GRAPH_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(mockUseFetchGraphData).toHaveBeenCalled();
|
||||
expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({
|
||||
req: {
|
||||
query: {
|
||||
originEventIds: [],
|
||||
start: `${timestamp}||-30m`,
|
||||
end: `${timestamp}||+30m`,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
enabled: true,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render when graph data is not available', async () => {
|
||||
mockUseFetchGraphData.mockReturnValue({
|
||||
isLoading: false,
|
||||
|
@ -429,9 +368,6 @@ describe('<GraphPreviewContainer />', () => {
|
|||
expect(
|
||||
await findByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
|
@ -441,9 +377,6 @@ describe('<GraphPreviewContainer />', () => {
|
|||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(GRAPH_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(mockUseFetchGraphData).toHaveBeenCalled();
|
||||
expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({
|
||||
req: {
|
||||
|
|
|
@ -5,18 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
import { EuiBetaBadge, useGeneratedHtmlId } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useFetchGraphData } from '@kbn/cloud-security-posture-graph/src/hooks';
|
||||
import {
|
||||
uiMetricService,
|
||||
GRAPH_PREVIEW,
|
||||
uiMetricService,
|
||||
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { GRAPH_PREVIEW_TEST_ID } from './test_ids';
|
||||
import { GraphPreview } from './graph_preview';
|
||||
|
@ -40,10 +38,10 @@ export const GraphPreviewContainer: React.FC = () => {
|
|||
dataFormattedForFieldBrowser,
|
||||
} = useDocumentDetailsContext();
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
const allowFlyoutExpansion = useMemo(
|
||||
() => !isPreviewMode && !isPreview,
|
||||
[isPreview, isPreviewMode]
|
||||
);
|
||||
const allowFlyoutExpansion = visualizationInFlyoutEnabled && !isPreviewMode && !isPreview;
|
||||
|
||||
const { navigateToGraphVisualization } = useNavigateToGraphVisualization({
|
||||
eventId,
|
||||
|
|
|
@ -36,15 +36,6 @@ jest.mock('../../shared/hooks/use_navigate_to_session_view', () => {
|
|||
return { useNavigateToSessionView: () => ({ navigateToSessionView: mockNavigateToSessionView }) };
|
||||
});
|
||||
|
||||
const mockUseUiSetting = jest.fn().mockReturnValue([false]);
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
...original,
|
||||
useUiSetting$: () => mockUseUiSetting(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-redux', () => {
|
||||
const original = jest.requireActual('react-redux');
|
||||
|
||||
|
@ -75,140 +66,81 @@ const renderSessionPreview = (context = mockContextValue) =>
|
|||
);
|
||||
|
||||
describe('SessionPreviewContainer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should render component and link in header', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(NO_DATA_MESSAGE);
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(UPSELL_TEXT);
|
||||
});
|
||||
|
||||
it('should render error message and text in header if no sessionConfig', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(null);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toHaveTextContent(NO_DATA_MESSAGE);
|
||||
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(UPSELL_TEXT);
|
||||
expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render upsell message in header if no correct license', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => false });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview();
|
||||
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toHaveTextContent(UPSELL_TEXT);
|
||||
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(NO_DATA_MESSAGE);
|
||||
expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in preview', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
describe('when newExpandableFlyoutNavigationDisabled is true', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true);
|
||||
(useInvestigateInTimeline as jest.Mock).mockReturnValue({
|
||||
investigateInTimelineAlertClick: jest.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in preview mode', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('when visualization in flyout flag is enabled', () => {
|
||||
it('should open left panel vizualization tab when visualization in flyout flag is on', () => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
it('should render component and link in header', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(NO_DATA_MESSAGE);
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(UPSELL_TEXT);
|
||||
});
|
||||
|
||||
it('should render error message and text in header if no sessionConfig', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(null);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toHaveTextContent(NO_DATA_MESSAGE);
|
||||
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(UPSELL_TEXT);
|
||||
expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render upsell message in header if no correct license', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => false });
|
||||
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview();
|
||||
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toHaveTextContent(UPSELL_TEXT);
|
||||
|
||||
expect(
|
||||
screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toHaveTextContent(NO_DATA_MESSAGE);
|
||||
expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in rule preview', () => {
|
||||
|
@ -221,6 +153,15 @@ describe('SessionPreviewContainer', () => {
|
|||
});
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
|
@ -246,104 +187,68 @@ describe('SessionPreviewContainer', () => {
|
|||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should open left panel visualization tab when visualization in flyout flag is on', () => {
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when newExpandableFlyoutNavigationDisabled is false', () => {
|
||||
describe('when visualization in flyout flag is enabled', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
|
||||
});
|
||||
|
||||
it('should open left panel vizualization tab when visualization in flyout flag is on', () => {
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in rule preview', () => {
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render link to session viewer if flyout is open in preview mode', () => {
|
||||
const { getByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
|
||||
});
|
||||
|
||||
describe('when visualization in flyout flag is not enabled', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseUiSetting.mockReturnValue([false]);
|
||||
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
|
||||
it('should open left panel visualization tab when visualization in flyout flag is on', () => {
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in rule preview', () => {
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
|
||||
it('should open session viewer in timeline', () => {
|
||||
const { getByTestId } = renderSessionPreview();
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(investigateInTimelineAlertClick).toHaveBeenCalled();
|
||||
it('should render link to session viewer if flyout is open in preview mode', () => {
|
||||
const { getByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
|
||||
it('should not render link to session viewer if flyout is open in rule preview', () => {
|
||||
const { getByTestId, queryByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument();
|
||||
expect(
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID))
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render link to open session viewer in timeline if flyout is open in preview mode', () => {
|
||||
const { getByTestId } = renderSessionPreview({
|
||||
...mockContextValue,
|
||||
isPreviewMode: true,
|
||||
});
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
expect(investigateInTimelineAlertClick).toHaveBeenCalled();
|
||||
});
|
||||
getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)).click();
|
||||
expect(mockNavigateToSessionView).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,29 +5,18 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { type FC, useCallback, useMemo } from 'react';
|
||||
import { TimelineTabs } from '@kbn/securitysolution-data-table';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import React, { type FC, useMemo } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants';
|
||||
import { useLicense } from '../../../../common/hooks/use_license';
|
||||
import { SessionPreview } from './session_preview';
|
||||
import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config';
|
||||
import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions';
|
||||
import { ExpandablePanel } from '../../../shared/components/expandable_panel';
|
||||
import { SESSION_PREVIEW_TEST_ID } from './test_ids';
|
||||
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
|
||||
import { setActiveTabTimeline } from '../../../../timelines/store/actions';
|
||||
import { getScopedActions } from '../../../../helpers';
|
||||
import { useNavigateToSessionView } from '../../shared/hooks/use_navigate_to_session_view';
|
||||
import { SessionViewNoDataMessage } from '../../shared/components/session_view_no_data_message';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
|
||||
|
||||
const timelineId = 'timeline-1';
|
||||
|
||||
/**
|
||||
* Checks if the SessionView component is available, if so render it or else render an error message
|
||||
*/
|
||||
|
@ -36,17 +25,12 @@ export const SessionPreviewContainer: FC = () => {
|
|||
eventId,
|
||||
indexName,
|
||||
scopeId,
|
||||
dataAsNestedObject,
|
||||
getFieldsData,
|
||||
isPreview,
|
||||
isPreviewMode,
|
||||
dataFormattedForFieldBrowser,
|
||||
} = useDocumentDetailsContext();
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
|
||||
// decide whether to show the session view or not
|
||||
const sessionViewConfig = useSessionViewConfig({ getFieldsData, dataFormattedForFieldBrowser });
|
||||
const isEnterprisePlus = useLicense().isEnterprise();
|
||||
|
@ -56,33 +40,6 @@ export const SessionPreviewContainer: FC = () => {
|
|||
'newExpandableFlyoutNavigationDisabled'
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { startTransaction } = useStartTransaction();
|
||||
const scopedActions = getScopedActions(timelineId);
|
||||
const { investigateInTimelineAlertClick } = useInvestigateInTimeline({
|
||||
ecsRowData: dataAsNestedObject,
|
||||
});
|
||||
|
||||
const goToSessionViewTab = useCallback(async () => {
|
||||
// open timeline
|
||||
await investigateInTimelineAlertClick();
|
||||
|
||||
// open session view tab
|
||||
startTransaction({ name: ALERTS_ACTIONS.OPEN_SESSION_VIEW });
|
||||
if (sessionViewConfig !== null) {
|
||||
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.session }));
|
||||
if (scopedActions) {
|
||||
dispatch(scopedActions.updateSessionViewConfig({ id: timelineId, sessionViewConfig }));
|
||||
}
|
||||
}
|
||||
}, [
|
||||
dispatch,
|
||||
investigateInTimelineAlertClick,
|
||||
scopedActions,
|
||||
sessionViewConfig,
|
||||
startTransaction,
|
||||
]);
|
||||
|
||||
const { navigateToSessionView } = useNavigateToSessionView({
|
||||
eventId,
|
||||
indexName,
|
||||
|
@ -91,10 +48,7 @@ export const SessionPreviewContainer: FC = () => {
|
|||
isPreviewMode,
|
||||
});
|
||||
|
||||
const iconType = useMemo(() => {
|
||||
const icon = visualizationInFlyoutEnabled ? 'arrowStart' : 'timeline';
|
||||
return !isPreviewMode ? icon : undefined;
|
||||
}, [visualizationInFlyoutEnabled, isPreviewMode]);
|
||||
const iconType = useMemo(() => (!isPreviewMode ? 'arrowStart' : undefined), [isPreviewMode]);
|
||||
|
||||
const isNavigationEnabled = useMemo(() => {
|
||||
// if the session view is not enabled or in rule preview mode, the navigation is not enabled
|
||||
|
@ -121,7 +75,7 @@ export const SessionPreviewContainer: FC = () => {
|
|||
iconType,
|
||||
...(isNavigationEnabled && {
|
||||
link: {
|
||||
callback: visualizationInFlyoutEnabled ? navigateToSessionView : goToSessionViewTab,
|
||||
callback: navigateToSessionView,
|
||||
tooltip: (
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.sessionPreviewTooltip"
|
||||
|
|
|
@ -10,14 +10,14 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
|||
import { render } from '@testing-library/react';
|
||||
import { useFetchGraphData } from '@kbn/cloud-security-posture-graph/src/hooks';
|
||||
import {
|
||||
uiMetricService,
|
||||
GRAPH_PREVIEW,
|
||||
uiMetricService,
|
||||
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import {
|
||||
ANALYZER_PREVIEW_TEST_ID,
|
||||
SESSION_PREVIEW_TEST_ID,
|
||||
GRAPH_PREVIEW_TEST_ID,
|
||||
SESSION_PREVIEW_TEST_ID,
|
||||
VISUALIZATIONS_SECTION_CONTENT_TEST_ID,
|
||||
VISUALIZATIONS_SECTION_HEADER_TEST_ID,
|
||||
} from './test_ids';
|
||||
|
@ -34,10 +34,7 @@ import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/
|
|||
import { useGraphPreview } from '../../shared/hooks/use_graph_preview';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
|
||||
import { createUseUiSetting$Mock } from '../../../../common/lib/kibana/kibana_react.mock';
|
||||
import {
|
||||
ENABLE_GRAPH_VISUALIZATION_SETTING,
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
|
||||
} from '../../../../../common/constants';
|
||||
import { ENABLE_GRAPH_VISUALIZATION_SETTING } from '../../../../../common/constants';
|
||||
|
||||
jest.mock('../hooks/use_expand_section');
|
||||
jest.mock('../../shared/hooks/use_alert_prevalence_from_process_tree', () => ({
|
||||
|
@ -70,8 +67,8 @@ jest.mock('../../../../common/hooks/use_experimental_features', () => ({
|
|||
|
||||
const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock;
|
||||
useIsExperimentalFeatureEnabledMock.mockReturnValue(true);
|
||||
const mockUseUiSetting = jest.fn().mockImplementation((key) => [false]);
|
||||
|
||||
const mockUseUiSetting = jest.fn().mockImplementation((key) => [false]);
|
||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||
return {
|
||||
|
@ -163,8 +160,6 @@ describe('<VisualizationsSection />', () => {
|
|||
|
||||
if (key === ENABLE_GRAPH_VISUALIZATION_SETTING) {
|
||||
return [false, jest.fn()];
|
||||
} else if (key === ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING) {
|
||||
return [false, jest.fn()];
|
||||
}
|
||||
|
||||
return useUiSetting$Mock(key, defaultValue);
|
||||
|
@ -185,8 +180,6 @@ describe('<VisualizationsSection />', () => {
|
|||
|
||||
if (key === ENABLE_GRAPH_VISUALIZATION_SETTING) {
|
||||
return [true, jest.fn()];
|
||||
} else if (key === ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING) {
|
||||
return [true, jest.fn()];
|
||||
}
|
||||
|
||||
return useUiSetting$Mock(key, defaultValue);
|
||||
|
@ -208,27 +201,6 @@ describe('<VisualizationsSection />', () => {
|
|||
|
||||
if (key === ENABLE_GRAPH_VISUALIZATION_SETTING) {
|
||||
return [false, jest.fn()];
|
||||
} else if (key === ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING) {
|
||||
return [true, jest.fn()];
|
||||
}
|
||||
|
||||
return useUiSetting$Mock(key, defaultValue);
|
||||
});
|
||||
|
||||
const { queryByTestId } = renderVisualizationsSection();
|
||||
|
||||
expect(queryByTestId(`${GRAPH_PREVIEW_TEST_ID}LeftSection`)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render the graph preview component if the flyout feature is disabled', () => {
|
||||
(useExpandSection as jest.Mock).mockReturnValue(true);
|
||||
mockUseUiSetting.mockImplementation((key, defaultValue) => {
|
||||
const useUiSetting$Mock = createUseUiSetting$Mock();
|
||||
|
||||
if (key === ENABLE_GRAPH_VISUALIZATION_SETTING) {
|
||||
return [true, jest.fn()];
|
||||
} else if (key === ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING) {
|
||||
return [false, jest.fn()];
|
||||
}
|
||||
|
||||
return useUiSetting$Mock(key, defaultValue);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
|
@ -17,10 +17,7 @@ import { VISUALIZATIONS_TEST_ID } from './test_ids';
|
|||
import { GraphPreviewContainer } from './graph_preview_container';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { useGraphPreview } from '../../shared/hooks/use_graph_preview';
|
||||
import {
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
|
||||
ENABLE_GRAPH_VISUALIZATION_SETTING,
|
||||
} from '../../../../../common/constants';
|
||||
import { ENABLE_GRAPH_VISUALIZATION_SETTING } from '../../../../../common/constants';
|
||||
|
||||
const KEY = 'visualizations';
|
||||
|
||||
|
@ -32,10 +29,6 @@ export const VisualizationsSection = memo(() => {
|
|||
const { dataAsNestedObject, getFieldsData, dataFormattedForFieldBrowser } =
|
||||
useDocumentDetailsContext();
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
|
||||
const [graphVisualizationEnabled] = useUiSetting$<boolean>(ENABLE_GRAPH_VISUALIZATION_SETTING);
|
||||
|
||||
// Decide whether to show the graph preview or not
|
||||
|
@ -45,8 +38,10 @@ export const VisualizationsSection = memo(() => {
|
|||
dataFormattedForFieldBrowser,
|
||||
});
|
||||
|
||||
const shouldShowGraphPreview =
|
||||
visualizationInFlyoutEnabled && graphVisualizationEnabled && hasGraphRepresentation;
|
||||
const shouldShowGraphPreview = useMemo(
|
||||
() => graphVisualizationEnabled && hasGraphRepresentation,
|
||||
[graphVisualizationEnabled, hasGraphRepresentation]
|
||||
);
|
||||
|
||||
return (
|
||||
<ExpandableSection
|
||||
|
|
|
@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { DetailPanelAlertTab, useFetchSessionViewAlerts } from '@kbn/session-view-plugin/public';
|
||||
import type { ProcessEvent } from '@kbn/session-view-plugin/common';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { LeftPanelVisualizeTab } from '../../left';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
|
||||
import { SESSION_VIEW_ID } from '../../left/components/session_view';
|
||||
import {
|
||||
|
@ -22,6 +23,7 @@ import { useSessionViewPanelContext } from '../context';
|
|||
import { SourcererScopeName } from '../../../../sourcerer/store/model';
|
||||
import { useSourcererDataView } from '../../../../sourcerer/containers';
|
||||
import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns';
|
||||
|
||||
/**
|
||||
* Tab displayed in the SessionView preview panel, shows alerts related to the session.
|
||||
*/
|
||||
|
@ -106,7 +108,7 @@ export const AlertsTab = memo(() => {
|
|||
jumpToCursor,
|
||||
},
|
||||
path: {
|
||||
tab: 'visualize',
|
||||
tab: LeftPanelVisualizeTab,
|
||||
subTab: SESSION_VIEW_ID,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useCallback, useMemo } from 'react';
|
|||
import type { FlyoutPanelProps } from '@kbn/expandable-flyout';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import type { Maybe } from '@kbn/timelines-plugin/common/search_strategy/common';
|
||||
import { LeftPanelVisualizeTab } from '../../left';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { ANALYZE_GRAPH_ID } from '../../left/components/analyze_graph';
|
||||
import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey } from '../constants/panel_keys';
|
||||
|
@ -84,7 +85,7 @@ export const useNavigateToAnalyzer = ({
|
|||
scopeId,
|
||||
},
|
||||
path: {
|
||||
tab: 'visualize',
|
||||
tab: LeftPanelVisualizeTab,
|
||||
subTab: ANALYZE_GRAPH_ID,
|
||||
},
|
||||
}),
|
||||
|
@ -98,7 +99,7 @@ export const useNavigateToAnalyzer = ({
|
|||
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, {
|
||||
location: scopeId,
|
||||
panel: 'left',
|
||||
tabId: 'visualize',
|
||||
tabId: LeftPanelVisualizeTab,
|
||||
});
|
||||
}
|
||||
// if flyout is not currently open, open flyout with right, left and preview panel
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useCallback, useMemo } from 'react';
|
|||
import type { FlyoutPanelProps } from '@kbn/expandable-flyout';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import type { Maybe } from '@kbn/timelines-plugin/common/search_strategy/common';
|
||||
import { LeftPanelVisualizeTab } from '../../left';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey } from '../constants/panel_keys';
|
||||
import { DocumentEventTypes } from '../../../../common/lib/telemetry';
|
||||
|
@ -74,7 +75,7 @@ export const useNavigateToGraphVisualization = ({
|
|||
scopeId,
|
||||
},
|
||||
path: {
|
||||
tab: 'visualize',
|
||||
tab: LeftPanelVisualizeTab,
|
||||
subTab: GRAPH_ID,
|
||||
},
|
||||
}),
|
||||
|
@ -87,7 +88,7 @@ export const useNavigateToGraphVisualization = ({
|
|||
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, {
|
||||
location: scopeId,
|
||||
panel: 'left',
|
||||
tabId: 'visualize',
|
||||
tabId: LeftPanelVisualizeTab,
|
||||
});
|
||||
} else {
|
||||
openFlyout({
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useCallback, useMemo } from 'react';
|
|||
import type { FlyoutPanelProps } from '@kbn/expandable-flyout';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import type { Maybe } from '@kbn/timelines-plugin/common/search_strategy/common';
|
||||
import { LeftPanelVisualizeTab } from '../../left';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { SESSION_VIEW_ID } from '../../left/components/session_view';
|
||||
import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey } from '../constants/panel_keys';
|
||||
|
@ -84,7 +85,7 @@ export const useNavigateToSessionView = ({
|
|||
scopeId,
|
||||
},
|
||||
path: {
|
||||
tab: 'visualize',
|
||||
tab: LeftPanelVisualizeTab,
|
||||
subTab: SESSION_VIEW_ID,
|
||||
},
|
||||
}),
|
||||
|
@ -98,7 +99,7 @@ export const useNavigateToSessionView = ({
|
|||
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, {
|
||||
location: scopeId,
|
||||
panel: 'left',
|
||||
tabId: 'visualize',
|
||||
tabId: LeftPanelVisualizeTab,
|
||||
});
|
||||
}
|
||||
// if flyout is not currently open, open flyout with right and left panels
|
||||
|
|
|
@ -18,10 +18,11 @@ import { timelineDefaults } from '../../store/defaults';
|
|||
import type { CellValueElementProps } from './cell_rendering';
|
||||
import { SourcererScopeName } from '../../../sourcerer/store/model';
|
||||
import { TimelineModalHeader } from '../modal/header';
|
||||
import type { TimelineId, RowRenderer } from '../../../../common/types/timeline';
|
||||
import type { RowRenderer, TimelineId } from '../../../../common/types/timeline';
|
||||
import { TimelineTypeEnum } from '../../../../common/api/timeline';
|
||||
import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import type { State } from '../../../common/store';
|
||||
import { sourcererSelectors } from '../../../common/store';
|
||||
import { EVENTS_COUNT_BUTTON_CLASS_NAME, onTimelineTabKeyPressed } from './helpers';
|
||||
import * as i18n from './translations';
|
||||
import { TabsContent } from './tabs';
|
||||
|
@ -29,7 +30,6 @@ import { HideShowContainer, TimelineContainer } from './styles';
|
|||
import { useTimelineFullScreen } from '../../../common/containers/use_full_screen';
|
||||
import { EXIT_FULL_SCREEN_CLASS_NAME } from '../../../common/components/exit_full_screen';
|
||||
import { useResolveConflict } from '../../../common/hooks/use_resolve_conflict';
|
||||
import { sourcererSelectors } from '../../../common/store';
|
||||
import { defaultUdtHeaders } from './body/column_headers/default_headers';
|
||||
import { useSelectedPatterns } from '../../../data_view_manager/hooks/use_selected_patterns';
|
||||
import { useDataViewSpec } from '../../../data_view_manager/hooks/use_data_view_spec';
|
||||
|
@ -82,7 +82,6 @@ const StatefulTimelineComponent: React.FC<Props> = ({
|
|||
savedObjectId,
|
||||
timelineType,
|
||||
description,
|
||||
sessionViewConfig,
|
||||
initialized,
|
||||
} = useDeepEqualSelector((state) =>
|
||||
pick(
|
||||
|
@ -93,7 +92,6 @@ const StatefulTimelineComponent: React.FC<Props> = ({
|
|||
'savedObjectId',
|
||||
'timelineType',
|
||||
'description',
|
||||
'sessionViewConfig',
|
||||
'initialized',
|
||||
'show',
|
||||
'activeTab',
|
||||
|
@ -230,7 +228,6 @@ const StatefulTimelineComponent: React.FC<Props> = ({
|
|||
|
||||
<TabsContent
|
||||
graphEventId={graphEventId}
|
||||
sessionViewConfig={sessionViewConfig}
|
||||
renderCellValue={renderCellValue}
|
||||
rowRenderers={rowRenderers}
|
||||
timelineId={timelineId}
|
||||
|
|
|
@ -115,16 +115,6 @@ describe('Timeline', () => {
|
|||
describe('analyzer tab and session view tab', () => {
|
||||
const analyzerTabSubj = `timelineTabs-${TimelineTabs.graph}`;
|
||||
const sessionViewTabSubj = `timelineTabs-${TimelineTabs.session}`;
|
||||
it('should show the analyzer tab when the advanced setting is disabled', () => {
|
||||
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
|
||||
render(
|
||||
<TestProviders>
|
||||
<TabsContent {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(screen.getByTestId(analyzerTabSubj)).toBeInTheDocument();
|
||||
expect(screen.getByTestId(sessionViewTabSubj)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show the analyzer tab when the advanced setting is enabled', async () => {
|
||||
mockUseUiSetting.mockReturnValue([true]);
|
||||
|
|
|
@ -5,24 +5,22 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiBadge, EuiSkeletonText, EuiTabs, EuiTab } from '@elastic/eui';
|
||||
import { EuiBadge, EuiSkeletonText, EuiTab, EuiTabs } from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
import type { Ref, ReactElement, ComponentType } from 'react';
|
||||
import type { ComponentType, ReactElement, Ref } from 'react';
|
||||
import React, { lazy, memo, Suspense, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
|
||||
import type { State } from '../../../../common/store';
|
||||
import { useEsqlAvailability } from '../../../../common/hooks/esql/use_esql_availability';
|
||||
import type { SessionViewConfig } from '../../../../../common/types';
|
||||
import type { RowRenderer, TimelineId } from '../../../../../common/types/timeline';
|
||||
import { TimelineTabs } from '../../../../../common/types/timeline';
|
||||
import { type TimelineType, TimelineTypeEnum } from '../../../../../common/api/timeline';
|
||||
import {
|
||||
useShallowEqualSelector,
|
||||
useDeepEqualSelector,
|
||||
useShallowEqualSelector,
|
||||
} from '../../../../common/hooks/use_selector';
|
||||
import {
|
||||
EqlEventsCountBadge,
|
||||
|
@ -32,18 +30,16 @@ import { timelineActions } from '../../../store';
|
|||
import type { CellValueElementProps } from '../cell_rendering';
|
||||
import {
|
||||
getActiveTabSelector,
|
||||
getEventIdToNoteIdsSelector,
|
||||
getNoteIdsSelector,
|
||||
getNotesSelector,
|
||||
getPinnedEventSelector,
|
||||
getShowTimelineSelector,
|
||||
getEventIdToNoteIdsSelector,
|
||||
} from './selectors';
|
||||
import * as i18n from './translations';
|
||||
import { useLicense } from '../../../../common/hooks/use_license';
|
||||
import { initializeTimelineSettings } from '../../../store/actions';
|
||||
import { selectTimelineById, selectTimelineESQLSavedSearchId } from '../../../store/selectors';
|
||||
import { fetchNotesBySavedObjectIds, makeSelectNotesBySavedObjectId } from '../../../../notes';
|
||||
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants';
|
||||
import { useUserPrivileges } from '../../../../common/components/user_privileges';
|
||||
import { LazyTimelineTabRenderer, TimelineTabFallback } from './lazy_timeline_tab_renderer';
|
||||
|
||||
|
@ -102,7 +98,6 @@ interface BasicTimelineTab {
|
|||
timelineId: TimelineId;
|
||||
timelineType: TimelineType;
|
||||
graphEventId?: string;
|
||||
sessionViewConfig?: SessionViewConfig | null;
|
||||
timelineDescription: string;
|
||||
}
|
||||
|
||||
|
@ -243,7 +238,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
timelineFullScreen,
|
||||
timelineType,
|
||||
graphEventId,
|
||||
sessionViewConfig,
|
||||
timelineDescription,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -263,10 +257,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
'securitySolutionNotesDisabled'
|
||||
);
|
||||
|
||||
const [visualizationInFlyoutEnabled] = useUiSetting$<boolean>(
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING
|
||||
);
|
||||
|
||||
const activeTab = useShallowEqualSelector((state) => getActiveTab(state, timelineId));
|
||||
const showTimeline = useShallowEqualSelector((state) => getShowTimeline(state, timelineId));
|
||||
const shouldShowESQLTab = useMemo(
|
||||
|
@ -285,8 +275,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
);
|
||||
const appNotes = useDeepEqualSelector((state) => getAppNotes(state));
|
||||
|
||||
const isEnterprisePlus = useLicense().isEnterprise();
|
||||
|
||||
// old notes system (through timeline)
|
||||
const allTimelineNoteIds = useMemo(() => {
|
||||
const eventNoteIds = Object.values(eventIdToNoteIds).reduce<string[]>(
|
||||
|
@ -356,10 +344,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
setActiveTab(TimelineTabs.eql);
|
||||
}, [setActiveTab]);
|
||||
|
||||
const setGraphAsActiveTab = useCallback(() => {
|
||||
setActiveTab(TimelineTabs.graph);
|
||||
}, [setActiveTab]);
|
||||
|
||||
const setNotesAsActiveTab = useCallback(() => {
|
||||
setActiveTab(TimelineTabs.notes);
|
||||
}, [setActiveTab]);
|
||||
|
@ -368,10 +352,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
setActiveTab(TimelineTabs.pinned);
|
||||
}, [setActiveTab]);
|
||||
|
||||
const setSessionAsActiveTab = useCallback(() => {
|
||||
setActiveTab(TimelineTabs.session);
|
||||
}, [setActiveTab]);
|
||||
|
||||
const setEsqlAsActiveTab = useCallback(() => {
|
||||
dispatch(
|
||||
initializeTimelineSettings({
|
||||
|
@ -424,28 +404,6 @@ const TabsContentComponent: React.FC<BasicTimelineTab> = ({
|
|||
{showTimeline && <EqlEventsCountBadge />}
|
||||
</StyledEuiTab>
|
||||
)}
|
||||
{!visualizationInFlyoutEnabled && (
|
||||
<EuiTab
|
||||
data-test-subj={`timelineTabs-${TimelineTabs.graph}`}
|
||||
onClick={setGraphAsActiveTab}
|
||||
isSelected={activeTab === TimelineTabs.graph}
|
||||
disabled={!graphEventId}
|
||||
key={TimelineTabs.graph}
|
||||
>
|
||||
{i18n.ANALYZER_TAB}
|
||||
</EuiTab>
|
||||
)}
|
||||
{isEnterprisePlus && !visualizationInFlyoutEnabled && (
|
||||
<EuiTab
|
||||
data-test-subj={`timelineTabs-${TimelineTabs.session}`}
|
||||
onClick={setSessionAsActiveTab}
|
||||
isSelected={activeTab === TimelineTabs.session}
|
||||
disabled={sessionViewConfig === null}
|
||||
key={TimelineTabs.session}
|
||||
>
|
||||
{i18n.SESSION_TAB}
|
||||
</EuiTab>
|
||||
)}
|
||||
<StyledEuiTab
|
||||
data-test-subj={`timelineTabs-${TimelineTabs.notes}`}
|
||||
onClick={setNotesAsActiveTab}
|
||||
|
|
|
@ -18,13 +18,6 @@ export const EQL_TAB = i18n.translate('xpack.securitySolution.timeline.tabs.eqlT
|
|||
defaultMessage: 'Correlation',
|
||||
});
|
||||
|
||||
export const ANALYZER_TAB = i18n.translate(
|
||||
'xpack.securitySolution.timeline.tabs.analyserTabTimelineTitle',
|
||||
{
|
||||
defaultMessage: 'Analyzer',
|
||||
}
|
||||
);
|
||||
|
||||
export const NOTES_TAB = i18n.translate(
|
||||
'xpack.securitySolution.timeline.tabs.notesTabTimelineTitle',
|
||||
{
|
||||
|
@ -39,23 +32,9 @@ export const PINNED_TAB = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const SECURITY_ASSISTANT = i18n.translate(
|
||||
'xpack.securitySolution.timeline.tabs.securityAssistantTimelineTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic AI Assistant',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISCOVER_ESQL_IN_TIMELINE_TAB = i18n.translate(
|
||||
'xpack.securitySolution.timeline.tabs.discoverEsqlInTimeline',
|
||||
{
|
||||
defaultMessage: 'ES|QL',
|
||||
}
|
||||
);
|
||||
|
||||
export const SESSION_TAB = i18n.translate(
|
||||
'xpack.securitySolution.timeline.tabs.sessionTabTimelineTitle',
|
||||
{
|
||||
defaultMessage: 'Session View',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -12,6 +12,9 @@ import type { CoreSetup, UiSettingsParams } from '@kbn/core/server';
|
|||
import type { Connector } from '@kbn/actions-plugin/server/application/connector/types';
|
||||
import {
|
||||
APP_ID,
|
||||
DEFAULT_AI_CONNECTOR,
|
||||
DEFAULT_ALERT_TAGS_KEY,
|
||||
DEFAULT_ALERT_TAGS_VALUE,
|
||||
DEFAULT_ANOMALY_SCORE,
|
||||
DEFAULT_APP_REFRESH_INTERVAL,
|
||||
DEFAULT_APP_TIME_RANGE,
|
||||
|
@ -26,23 +29,19 @@ import {
|
|||
DEFAULT_THREAT_INDEX_KEY,
|
||||
DEFAULT_THREAT_INDEX_VALUE,
|
||||
DEFAULT_TO,
|
||||
ENABLE_ASSET_INVENTORY_SETTING,
|
||||
ENABLE_CCS_READ_WARNING_SETTING,
|
||||
ENABLE_GRAPH_VISUALIZATION_SETTING,
|
||||
ENABLE_NEWS_FEED_SETTING,
|
||||
EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER,
|
||||
EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION,
|
||||
EXTENDED_RULE_EXECUTION_LOGGING_ENABLED_SETTING,
|
||||
EXTENDED_RULE_EXECUTION_LOGGING_MIN_LEVEL_SETTING,
|
||||
IP_REPUTATION_LINKS_SETTING,
|
||||
IP_REPUTATION_LINKS_SETTING_DEFAULT,
|
||||
NEWS_FEED_URL_SETTING,
|
||||
NEWS_FEED_URL_SETTING_DEFAULT,
|
||||
ENABLE_CCS_READ_WARNING_SETTING,
|
||||
SHOW_RELATED_INTEGRATIONS_SETTING,
|
||||
EXTENDED_RULE_EXECUTION_LOGGING_ENABLED_SETTING,
|
||||
EXTENDED_RULE_EXECUTION_LOGGING_MIN_LEVEL_SETTING,
|
||||
DEFAULT_ALERT_TAGS_KEY,
|
||||
DEFAULT_ALERT_TAGS_VALUE,
|
||||
EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER,
|
||||
EXCLUDED_DATA_TIERS_FOR_RULE_EXECUTION,
|
||||
ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING,
|
||||
ENABLE_GRAPH_VISUALIZATION_SETTING,
|
||||
ENABLE_ASSET_INVENTORY_SETTING,
|
||||
DEFAULT_AI_CONNECTOR,
|
||||
} from '../common/constants';
|
||||
import type { ExperimentalFeatures } from '../common/experimental_features';
|
||||
import { LogLevelSetting } from '../common/api/detection_engine/rule_monitoring';
|
||||
|
@ -66,12 +65,6 @@ export const initUiSettings = (
|
|||
experimentalFeatures: ExperimentalFeatures,
|
||||
validationsEnabled: boolean
|
||||
) => {
|
||||
const enableVisualizationsInFlyoutLabel = i18n.translate(
|
||||
'xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutLabel',
|
||||
{
|
||||
defaultMessage: 'Enable visualizations in flyout',
|
||||
}
|
||||
);
|
||||
const securityUiSettings: Record<string, UiSettingsParams<unknown>> = {
|
||||
[DEFAULT_APP_REFRESH_INTERVAL]: {
|
||||
type: 'json',
|
||||
|
@ -215,22 +208,6 @@ export const initUiSettings = (
|
|||
schema: schema.boolean(),
|
||||
solution: 'security',
|
||||
},
|
||||
[ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING]: {
|
||||
name: enableVisualizationsInFlyoutLabel,
|
||||
value: true,
|
||||
description: i18n.translate(
|
||||
'xpack.securitySolution.uiSettings.enableVisualizationsInFlyoutDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Enable visualizations (analyzer and session viewer) in document details flyout.',
|
||||
}
|
||||
),
|
||||
type: 'boolean',
|
||||
category: [APP_ID],
|
||||
requiresPageReload: true,
|
||||
schema: schema.boolean(),
|
||||
solution: 'security',
|
||||
},
|
||||
[ENABLE_GRAPH_VISUALIZATION_SETTING]: {
|
||||
name: i18n.translate('xpack.securitySolution.uiSettings.enableGraphVisualizationLabel', {
|
||||
defaultMessage: 'Enable graph visualization',
|
||||
|
@ -238,13 +215,8 @@ export const initUiSettings = (
|
|||
description: i18n.translate(
|
||||
'xpack.securitySolution.uiSettings.enableGraphVisualizationDescription',
|
||||
{
|
||||
defaultMessage: `<em>[technical preview]</em> Enable the Graph Visualization feature within the Security Solution.
|
||||
<br/>Note: This feature requires the {visualizationFlyoutFeatureFlag} setting to be enabled.
|
||||
<br/>Please ensure both settings are enabled to use graph visualizations in flyout.`,
|
||||
values: {
|
||||
em: (chunks) => `<em>${chunks}</em>`,
|
||||
visualizationFlyoutFeatureFlag: `<code>${enableVisualizationsInFlyoutLabel}</code>`,
|
||||
},
|
||||
defaultMessage: `<em>[technical preview]</em> Enable the Graph Visualization feature within the Security Solution.`,
|
||||
values: { em: (chunks) => `<em>${chunks}</em>` },
|
||||
}
|
||||
),
|
||||
type: 'boolean',
|
||||
|
|
|
@ -60,7 +60,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
* 1. release a new package to EPR
|
||||
* 2. merge the updated version number change to kibana
|
||||
*/
|
||||
`--uiSettings.overrides.securitySolution:enableVisualizationsInFlyout=true`,
|
||||
`--uiSettings.overrides.securitySolution:enableGraphVisualization=true`,
|
||||
`--xpack.fleet.packages.0.name=cloud_security_posture`,
|
||||
`--xpack.fleet.packages.0.version=${CLOUD_SECURITY_PLUGIN_VERSION}`,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue