From 0cc887be92df434671ad37fe89cb4ebcc0d5af3d Mon Sep 17 00:00:00 2001 From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:56:12 +0100 Subject: [PATCH] [ML][UX]: Consistent Layout and UI Enhancements for ML Pages (#203813) ## Summary * Updated alignment for `Add to` action buttons across various ML pages - see: #184109 * Fixed the overflowing date picker on `Anomaly Detection` pages - see: [#204394](https://github.com/elastic/kibana/issues/204394) * Standardized gaps around items on pages to maintain consistent values of `8px` (`gutterSize = 's'`) * Fixed the header on the Data Visualizer page - see: [#204393](https://github.com/elastic/kibana/issues/204393) * Adjusted the layout for Change Point Detection * Updated toast messages & toast action button - see: #184109 * Added icons for attachments actions Exploration around new `Add to` actions buttons - the right column is the most recent one, see: #184109 : | Before | After (add_to button) | After (icon button) - current | | ------------- | ------------- | ------------- | | ![Screenshot 2024-12-12 at 11 45 14](https://github.com/user-attachments/assets/08dc0be5-0b98-481d-9906-d3434f03f634) | ![Screenshot 2024-12-12 at 11 37 38](https://github.com/user-attachments/assets/0b2cbdcd-cad0-49aa-842f-123eebec1716) | ![Screenshot 2024-12-12 at 12 42 58](https://github.com/user-attachments/assets/c0a0c732-bbc0-4007-998e-df413fae612b) | | ![Screenshot 2024-12-12 at 11 45 49](https://github.com/user-attachments/assets/9ff45cf8-1c24-4ef4-ab59-2b54f1569c6e) | ![Screenshot 2024-12-12 at 11 39 34](https://github.com/user-attachments/assets/293255eb-eba5-4d90-a10b-0f41de0cc195) | ![Screenshot 2024-12-12 at 12 44 58](https://github.com/user-attachments/assets/740da2fb-ceed-4e6a-add6-9a8d695776a6) | | ![Screenshot 2024-12-12 at 11 46 30](https://github.com/user-attachments/assets/71cea9f4-7658-4776-865d-0f7c5682e67a) | ![Screenshot 2024-12-12 at 11 40 18](https://github.com/user-attachments/assets/b03e8a75-68d3-4c26-942c-1d41072a62ee) | ![image](https://github.com/user-attachments/assets/6a259924-7081-426c-8bd2-346e4f0ae152) | | ![Screenshot 2024-12-12 at 11 48 07](https://github.com/user-attachments/assets/2b340d38-26a5-45bc-851e-8b1956503500) | ![Screenshot 2024-12-12 at 11 42 03](https://github.com/user-attachments/assets/ecef0b37-a43c-42a3-911f-31d4acf9ac7b) | ![Screenshot 2024-12-12 at 12 46 14](https://github.com/user-attachments/assets/f9dddfe0-7296-4394-bb2f-94d702361f49) | | ![Screenshot 2024-12-12 at 11 49 05](https://github.com/user-attachments/assets/d670ad40-58d4-40fb-a88d-7ac5e6c1fbbd) | ![Screenshot 2024-12-12 at 11 43 40](https://github.com/user-attachments/assets/856f9476-c6ff-4405-8865-fb8784f3d818) | ![image](https://github.com/user-attachments/assets/b18f624b-e648-403f-9595-442b2723bdde) | Toasts: | Before | After | | ------ | ------ | | image | ![image](https://github.com/user-attachments/assets/36955456-026a-4abe-b872-c72c115a2dbe) | Other changes: | Before | After | | ------ | ------ | | ![Screenshot 2024-12-13 at 17 57 36](https://github.com/user-attachments/assets/263940ea-9396-4f82-b14e-c9086c6d36e8) | ![Screenshot 2024-12-13 at 18 00 26](https://github.com/user-attachments/assets/49430be4-356b-4902-b855-7fc1b252fbdb) | | ![Screenshot 2024-12-13 at 18 06 59](https://github.com/user-attachments/assets/67ad0faf-42f7-44e1-9290-857e28a9d5e4) | ![Screenshot 2024-12-13 at 18 02 04](https://github.com/user-attachments/assets/357d7296-7b5f-4df5-b664-8bd99c93205b) | | ![Screenshot 2024-12-13 at 18 08 20](https://github.com/user-attachments/assets/819a7c33-9c7a-4423-be1b-cbec30dd8a97) | ![Screenshot 2024-12-13 at 18 09 30](https://github.com/user-attachments/assets/c4b3cb40-f572-4828-888b-4cfff6b565b9) | | ![Screenshot 2024-12-13 at 18 11 52](https://github.com/user-attachments/assets/c63ccdf3-aeaa-4047-a3b5-f67c11690020) | ![Screenshot 2024-12-13 at 18 10 34](https://github.com/user-attachments/assets/6a6343d5-a7f7-45da-bf40-46b14b257e41) | | ![Screenshot 2024-12-13 at 18 30 32](https://github.com/user-attachments/assets/7aa13ad8-ba6f-4801-b0fe-ff90dd9038c1) | ![Screenshot 2024-12-13 at 18 32 59](https://github.com/user-attachments/assets/17774c78-003d-46fd-b7bb-d21cdee7df47) | | ![Screenshot 2024-12-13 at 18 35 56](https://github.com/user-attachments/assets/b7b003c6-11a6-4a1d-97c2-c1b920c0fd1a) | ![Screenshot 2024-12-13 at 18 34 25](https://github.com/user-attachments/assets/5af49323-cb9c-433d-aa6f-91af21dfa5bf) | | image | image | - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/components/date_picker_wrapper.tsx | 7 +- .../components/full_time_range_selector.tsx | 2 +- .../data_drift/data_drift_page.tsx | 1 - .../index_data_visualizer_view.tsx | 79 ++++---- .../shared/aiops/public/cases/constants.ts | 32 ++++ .../change_point_detection/fields_config.tsx | 81 ++++---- .../log_categorization/attachments_menu.tsx | 13 +- .../log_categorization_page.tsx | 88 +++++---- .../sampling_menu/sampling_menu.tsx | 10 +- .../log_rate_analysis_attachments_menu.tsx | 13 +- .../components/page_header/page_header.tsx | 1 - .../aiops/public/hooks/use_cases_modal.ts | 22 ++- .../contexts/kibana/use_cases_modal.ts | 23 ++- .../explorer/anomaly_context_menu.tsx | 9 +- .../application/explorer/anomaly_timeline.tsx | 10 +- .../forecasting_modal/forecast_button.tsx | 2 + .../series_controls/series_controls.tsx | 4 +- .../timeseriesexplorer_controls.tsx | 179 ++++++++++++------ .../timeseriesexplorer/timeseriesexplorer.js | 60 +++--- .../shared/ml/public/cases/constants.ts | 27 +++ .../cases/public/common/translations.ts | 2 +- .../public/common/use_cases_toast.test.tsx | 2 +- .../cases/public/common/use_cases_toast.tsx | 28 ++- .../apps/cases/group2/attachment_framework.ts | 8 +- .../cases/attachment_framework.ts | 4 +- 25 files changed, 447 insertions(+), 260 deletions(-) create mode 100644 x-pack/platform/plugins/shared/aiops/public/cases/constants.ts create mode 100644 x-pack/platform/plugins/shared/ml/public/cases/constants.ts diff --git a/x-pack/platform/packages/private/ml/date_picker/src/components/date_picker_wrapper.tsx b/x-pack/platform/packages/private/ml/date_picker/src/components/date_picker_wrapper.tsx index 3925b51b6c38e..060b0ee997d00 100644 --- a/x-pack/platform/packages/private/ml/date_picker/src/components/date_picker_wrapper.tsx +++ b/x-pack/platform/packages/private/ml/date_picker/src/components/date_picker_wrapper.tsx @@ -87,10 +87,6 @@ interface DatePickerWrapperProps { * Width setting to be passed on to `EuiSuperDatePicker` */ width?: EuiSuperDatePickerProps['width']; - /** - * Boolean flag to set use of flex group wrapper - */ - flexGroup?: boolean; /** * Boolean flag to disable the date picker */ @@ -123,7 +119,6 @@ export const DatePickerWrapper: FC = (props) => { isLoading = false, showRefresh, width, - flexGroup = true, isDisabled = false, needsUpdate, onRefresh, @@ -363,6 +358,8 @@ export const DatePickerWrapper: FC = (props) => { ); + const flexGroup = !isTimeRangeSelectorEnabled || isAutoRefreshOnly === true; + const wrapped = flexGroup ? ( {flexItems} diff --git a/x-pack/platform/packages/private/ml/date_picker/src/components/full_time_range_selector.tsx b/x-pack/platform/packages/private/ml/date_picker/src/components/full_time_range_selector.tsx index da0740f884ea9..f6e0aa1850cb9 100644 --- a/x-pack/platform/packages/private/ml/date_picker/src/components/full_time_range_selector.tsx +++ b/x-pack/platform/packages/private/ml/date_picker/src/components/full_time_range_selector.tsx @@ -220,7 +220,7 @@ export const FullTimeRangeSelector: FC = (props) => }, [frozenDataPreference, showFrozenDataTierChoice]); return ( - + = ({ onRefresh, needsUpdate }) => { isAutoRefreshOnly={!hasValidTimeField} showRefresh={!hasValidTimeField} width="full" - flexGroup={!hasValidTimeField} onRefresh={onRefresh} needsUpdate={needsUpdate} />, diff --git a/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx b/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx index 5f1f78af90073..b6ab99583cf49 100644 --- a/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx +++ b/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx @@ -12,7 +12,6 @@ import type { Required } from 'utility-types'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { - useEuiTheme, useEuiBreakpoint, useIsWithinMaxBreakpoint, EuiFlexGroup, @@ -21,7 +20,6 @@ import { EuiPanel, EuiProgress, EuiSpacer, - EuiTitle, } from '@elastic/eui'; import { type Filter, FilterStateStore, type Query, buildEsQuery } from '@kbn/es-query'; @@ -108,8 +106,6 @@ export interface IndexDataVisualizerViewProps { } export const IndexDataVisualizerView: FC = (dataVisualizerProps) => { - const { euiTheme } = useEuiTheme(); - const [savedRandomSamplerPreference, saveRandomSamplerPreference] = useStorage< DVKey, DVStorageMapped @@ -515,49 +511,40 @@ export const IndexDataVisualizerView: FC = (dataVi paddingSize="none" > - - - -

{currentDataView.getName()}

-
- -
- - {isWithinLargeBreakpoint ? : null} - - {hasValidTimeField ? ( - - - - ) : null} - - + {currentDataView.getName()} + {/* TODO: This management section shouldn't live inside the header */} + + + } + rightSideGroupProps={{ + gutterSize: 's', + 'data-test-subj': 'dataVisualizerTimeRangeSelectorSection', + }} + rightSideItems={[ + , + hasValidTimeField && ( + - - -
+ ), + ]} + /> diff --git a/x-pack/platform/plugins/shared/aiops/public/cases/constants.ts b/x-pack/platform/plugins/shared/aiops/public/cases/constants.ts new file mode 100644 index 0000000000000..547734955cbbb --- /dev/null +++ b/x-pack/platform/plugins/shared/aiops/public/cases/constants.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ChangePointDetectionViewType } from '@kbn/aiops-change-point-detection/constants'; +import { i18n } from '@kbn/i18n'; + +/** + * Titles for the cases toast messages + */ +export const CASES_TOAST_MESSAGES_TITLES = { + CHANGE_POINT_DETECTION: (viewType: ChangePointDetectionViewType, chartsCount: number) => + viewType === 'table' + ? i18n.translate('xpack.aiops.cases.changePointDetectionTableTitle', { + defaultMessage: 'Change point table', + }) + : i18n.translate('xpack.aiops.cases.changePointDetectionChartsTitle', { + defaultMessage: 'Change point {chartsCount, plural, one {chart} other {charts}}', + values: { + chartsCount, + }, + }), + LOG_RATE_ANALYSIS: i18n.translate('xpack.aiops.cases.logRateAnalysisTitle', { + defaultMessage: 'Log rate analysis', + }), + PATTERN_ANALYSIS: i18n.translate('xpack.aiops.cases.logPatternAnalysisTitle', { + defaultMessage: 'Log pattern analysis', + }), +}; diff --git a/x-pack/platform/plugins/shared/aiops/public/components/change_point_detection/fields_config.tsx b/x-pack/platform/plugins/shared/aiops/public/components/change_point_detection/fields_config.tsx index fb1a51c311668..226eb6fbbc2fc 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/change_point_detection/fields_config.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/change_point_detection/fields_config.tsx @@ -56,6 +56,7 @@ import { import { useChangePointResults } from './use_change_point_agg_request'; import { useSplitFieldCardinality } from './use_split_field_cardinality'; import { ViewTypeSelector } from './view_type_selector'; +import { CASES_TOAST_MESSAGES_TITLES } from '../../cases/constants'; const selectControlCss = { width: '350px' }; @@ -215,12 +216,18 @@ const FieldPanel: FC = ({ progress, } = useChangePointResults(fieldConfig, requestParams, combinedQuery, splitFieldCardinality); - const openCasesModalCallback = useCasesModal(EMBEDDABLE_CHANGE_POINT_CHART_TYPE); - const selectedPartitions = useMemo(() => { return (selectedChangePoints[panelIndex] ?? []).map((v) => v.group?.value as string); }, [selectedChangePoints, panelIndex]); + const openCasesModalCallback = useCasesModal( + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, + CASES_TOAST_MESSAGES_TITLES.CHANGE_POINT_DETECTION( + caseAttachment.viewType, + selectedPartitions.length + ) + ); + const caseAttachmentButtonDisabled = isDefined(fieldConfig.splitField) && selectedPartitions.length === 0; @@ -283,6 +290,7 @@ const FieldPanel: FC = ({ defaultMessage: 'To dashboard', }), panel: 'attachToDashboardPanel', + icon: 'dashboardApp', 'data-test-subj': 'aiopsChangePointDetectionAttachToDashboardButton', }, ] @@ -307,6 +315,7 @@ const FieldPanel: FC = ({ : {}), 'data-test-subj': 'aiopsChangePointDetectionAttachToCaseButton', panel: 'attachToCasePanel', + icon: 'casesApp', }, ] : []), @@ -513,42 +522,37 @@ const FieldPanel: FC = ({ return ( - + - - - !prevState)} - aria-label={i18n.translate('xpack.aiops.changePointDetection.expandConfigLabel', { - defaultMessage: 'Expand configuration', - })} - /> - - - - - - } - value={progress ?? 0} - max={100} - valueText - size="m" + !prevState)} + aria-label={i18n.translate('xpack.aiops.changePointDetection.expandConfigLabel', { + defaultMessage: 'Expand configuration', + })} + size="s" + /> + + + + + + - - - + } + value={progress ?? 0} + max={100} + valueText + size="m" + /> + - + @@ -565,8 +569,11 @@ const FieldPanel: FC = ({ defaultMessage: 'Context menu', } )} - iconType="boxesHorizontal" color="text" + display="base" + size="s" + isSelected={isActionMenuOpen} + iconType="boxesHorizontal" onClick={setIsActionMenuOpen.bind(null, !isActionMenuOpen)} /> } @@ -678,7 +685,7 @@ export const FieldsControls: FC> = ({ : undefined } > - + onChangeFn('fn', v)} /> diff --git a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/attachments_menu.tsx b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/attachments_menu.tsx index 409b489ff4510..a82e1a4b087ed 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/attachments_menu.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/attachments_menu.tsx @@ -34,6 +34,7 @@ import type { PatternAnalysisEmbeddableState } from '../../embeddables/pattern_a import type { RandomSamplerOption, RandomSamplerProbability } from './sampling_menu/random_sampler'; import { useCasesModal } from '../../hooks/use_cases_modal'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; +import { CASES_TOAST_MESSAGES_TITLES } from '../../cases/constants'; const SavedObjectSaveModalDashboard = withSuspense(LazySavedObjectSaveModalDashboard); @@ -66,7 +67,10 @@ export const AttachmentsMenu = ({ update: false, }; - const openCasesModalCallback = useCasesModal(EMBEDDABLE_PATTERN_ANALYSIS_TYPE); + const openCasesModalCallback = useCasesModal( + EMBEDDABLE_PATTERN_ANALYSIS_TYPE, + CASES_TOAST_MESSAGES_TITLES.PATTERN_ANALYSIS + ); const timeRange = useTimeRangeUpdates(); @@ -123,6 +127,7 @@ export const AttachmentsMenu = ({ defaultMessage: 'Add to dashboard', }), panel: 'attachToDashboardPanel', + icon: 'dashboardApp', 'data-test-subj': 'aiopsLogPatternAnalysisAttachToDashboardButton', }, ] @@ -133,6 +138,7 @@ export const AttachmentsMenu = ({ name: i18n.translate('xpack.aiops.logCategorization.attachToCaseLabel', { defaultMessage: 'Add to case', }), + icon: 'casesApp', 'data-test-subj': 'aiopsLogPatternAnalysisAttachToCaseButton', onClick: () => { setIsActionMenuOpen(false); @@ -218,8 +224,11 @@ export const AttachmentsMenu = ({ defaultMessage: 'Attachments', } )} - iconType="boxesHorizontal" + size="m" color="text" + display="base" + isSelected={isActionMenuOpen} + iconType="boxesHorizontal" onClick={() => setIsActionMenuOpen(!isActionMenuOpen)} /> } diff --git a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/log_categorization_page.tsx b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/log_categorization_page.tsx index 9bebf4d9b731a..482ef5801183d 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/log_categorization_page.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/log_categorization_page.tsx @@ -357,48 +357,56 @@ export const LogCategorizationPage: FC = () => { - - - - - - - - {loading === false ? ( - { - loadCategories(); - }} - data-test-subj="aiopsLogPatternAnalysisRunButton" + + + + - - - ) : ( - cancelRequest()} - > - Cancel - - )} - - - + + + + {loading === false ? ( + { + loadCategories(); + }} + data-test-subj="aiopsLogPatternAnalysisRunButton" + > + + + ) : ( + cancelRequest()} + > + Cancel + + )} + + + loadCategories()} /> diff --git a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx index d2dd9591e76f7..7da2736fdd453 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx @@ -8,7 +8,7 @@ import type { FC } from 'react'; import { useMemo } from 'react'; import React, { useState } from 'react'; -import { EuiPopover, EuiButtonEmpty, EuiPanel } from '@elastic/eui'; +import { EuiPopover, EuiPanel, EuiButton } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; import type { RandomSampler } from './random_sampler'; @@ -34,14 +34,16 @@ export const SamplingMenu: FC = ({ randomSampler, reload }) => { data-test-subj="aiopsRandomSamplerOptionsPopover" id="aiopsSamplingOptions" button={ - setShowSamplingOptionsPopover(!showSamplingOptionsPopover)} + color="text" iconSide="right" - iconType="arrowDown" + isSelected={showSamplingOptionsPopover} + iconType={showSamplingOptionsPopover ? 'arrowUp' : 'arrowDown'} > {buttonText} - +
} isOpen={showSamplingOptionsPopover} closePopover={() => setShowSamplingOptionsPopover(false)} diff --git a/x-pack/platform/plugins/shared/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx b/x-pack/platform/plugins/shared/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx index d7e68ae42799c..def6721c2adb3 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx @@ -28,6 +28,7 @@ import { } from '@elastic/eui'; import type { WindowParameters } from '@kbn/aiops-log-rate-analysis/window_parameters'; import type { SignificantItem } from '@kbn/ml-agg-utils'; +import { CASES_TOAST_MESSAGES_TITLES } from '../../../cases/constants'; import { useCasesModal } from '../../../hooks/use_cases_modal'; import { useDataSource } from '../../../hooks/use_data_source'; import type { LogRateAnalysisEmbeddableState } from '../../../embeddables/log_rate_analysis/types'; @@ -60,7 +61,10 @@ export const LogRateAnalysisAttachmentsMenu = ({ const timeRange = useTimeRangeUpdates(); const absoluteTimeRange = useTimeRangeUpdates(true); - const openCasesModalCallback = useCasesModal(EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE); + const openCasesModalCallback = useCasesModal( + EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE, + CASES_TOAST_MESSAGES_TITLES.LOG_RATE_ANALYSIS + ); const canEditDashboards = capabilities.dashboard.createNew; @@ -120,6 +124,7 @@ export const LogRateAnalysisAttachmentsMenu = ({ name: i18n.translate('xpack.aiops.logRateAnalysis.addToDashboardTitle', { defaultMessage: 'Add to dashboard', }), + icon: 'dashboardApp', panel: 'attachToDashboardPanel', 'data-test-subj': 'aiopsLogRateAnalysisAttachToDashboardButton', }, @@ -131,6 +136,7 @@ export const LogRateAnalysisAttachmentsMenu = ({ name: i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseLabel', { defaultMessage: 'Add to case', }), + icon: 'casesApp', 'data-test-subj': 'aiopsLogRateAnalysisAttachToCaseButton', disabled: !isCasesAttachmentEnabled, ...(!isCasesAttachmentEnabled @@ -217,8 +223,11 @@ export const LogRateAnalysisAttachmentsMenu = ({ aria-label={i18n.translate('xpack.aiops.logRateAnalysis.attachmentsMenuAriaLabel', { defaultMessage: 'Attachments', })} - iconType="boxesHorizontal" color="text" + display="base" + size="s" + isSelected={isActionMenuOpen} + iconType="boxesHorizontal" onClick={() => setIsActionMenuOpen(!isActionMenuOpen)} /> } diff --git a/x-pack/platform/plugins/shared/aiops/public/components/page_header/page_header.tsx b/x-pack/platform/plugins/shared/aiops/public/components/page_header/page_header.tsx index a01e715e86272..3efed2b74093e 100644 --- a/x-pack/platform/plugins/shared/aiops/public/components/page_header/page_header.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/components/page_header/page_header.tsx @@ -80,7 +80,6 @@ export const PageHeader: FC = () => { isAutoRefreshOnly={!hasValidTimeField} showRefresh={!hasValidTimeField} width="full" - flexGroup={!hasValidTimeField} />, hasValidTimeField && ( = * Returns a callback for opening the cases modal with provided attachment state. */ export const useCasesModal = ( - embeddableType: EmbeddableType + embeddableType: EmbeddableType, + title: string ) => { const { cases } = useAiopsAppContext(); - const selectCaseModal = cases?.hooks.useCasesAddToExistingCaseModal(); + const successMessage = useMemo(() => { + return i18n.translate('xpack.aiops.useCasesModal.successMessage', { + defaultMessage: '{title} added to case.', + values: { title }, + }); + }, [title]); + + const selectCaseModal = cases?.hooks.useCasesAddToExistingCaseModal({ + successToaster: { + content: successMessage, + }, + }); return useCallback( (persistableState: Partial, 'id'>>) => { @@ -64,7 +77,6 @@ export const useCasesModal = ( ], }); }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [embeddableType] + [embeddableType, selectCaseModal] ); }; diff --git a/x-pack/platform/plugins/shared/ml/public/application/contexts/kibana/use_cases_modal.ts b/x-pack/platform/plugins/shared/ml/public/application/contexts/kibana/use_cases_modal.ts index c6142e715bad7..f24a541884555 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/contexts/kibana/use_cases_modal.ts +++ b/x-pack/platform/plugins/shared/ml/public/application/contexts/kibana/use_cases_modal.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { stringHash } from '@kbn/ml-string-hash'; import { AttachmentType } from '@kbn/cases-plugin/common'; +import { i18n } from '@kbn/i18n'; import { useMlKibana } from './kibana_context'; import type { MappedEmbeddableTypeOf, MlEmbeddableTypes } from '../../../embeddables'; @@ -15,13 +16,25 @@ import type { MappedEmbeddableTypeOf, MlEmbeddableTypes } from '../../../embedda * Returns a callback for opening the cases modal with provided attachment state. */ export const useCasesModal = ( - embeddableType: EmbeddableType + embeddableType: EmbeddableType, + title: string ) => { const { services: { cases }, } = useMlKibana(); - const selectCaseModal = cases?.hooks.useCasesAddToExistingCaseModal(); + const successMessage = useMemo(() => { + return i18n.translate('xpack.ml.useCasesModal.successMessage', { + defaultMessage: '{title} added to case.', + values: { title }, + }); + }, [title]); + + const selectCaseModal = cases?.hooks.useCasesAddToExistingCaseModal({ + successToaster: { + content: successMessage, + }, + }); return useCallback( (persistableState: Partial, 'id'>>) => { @@ -48,7 +61,7 @@ export const useCasesModal = ( ], }); }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [embeddableType] + + [embeddableType, selectCaseModal] ); }; diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_context_menu.tsx b/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_context_menu.tsx index 7904a55264d08..ccee7f8fa1be5 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_context_menu.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_context_menu.tsx @@ -52,6 +52,7 @@ import { useMlKibana } from '../contexts/kibana'; import type { AppStateSelectedCells, ExplorerJob } from './explorer_utils'; import { getSelectionInfluencers, getSelectionTimeRange } from './explorer_utils'; import { getDefaultExplorerChartsPanelTitle } from '../../embeddables/anomaly_charts/utils'; +import { CASES_TOAST_MESSAGES_TITLES } from '../../cases/constants'; interface AnomalyContextMenuProps { selectedJobs: ExplorerJob[]; @@ -99,7 +100,10 @@ export const AnomalyContextMenu: FC = ({ [setIsMenuOpen] ); - const openCasesModal = useCasesModal(ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE); + const openCasesModal = useCasesModal( + ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + CASES_TOAST_MESSAGES_TITLES.ANOMALY_CHARTS(maxSeriesToPlot) + ); const canEditDashboards = capabilities.dashboard?.createNew ?? false; const casesPrivileges = cases?.helpers.canUseCases(); @@ -266,6 +270,7 @@ export const AnomalyContextMenu: FC = ({ /> ), panel: 'addToDashboardPanel', + icon: 'dashboardApp', 'data-test-subj': 'mlAnomalyAddChartsToDashboardButton', }); @@ -286,6 +291,7 @@ export const AnomalyContextMenu: FC = ({ name: ( ), + icon: 'casesApp', panel: 'addToCasePanel', 'data-test-subj': 'mlAnomalyAttachChartsToCasesButton', }); @@ -329,6 +335,7 @@ export const AnomalyContextMenu: FC = ({ defaultMessage: 'Actions', })} color="text" + display="base" iconType="boxesHorizontal" onClick={setIsMenuOpen.bind(null, !isMenuOpen)} data-test-subj="mlExplorerAnomalyPanelMenu" diff --git a/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_timeline.tsx b/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_timeline.tsx index cad2ef9376890..e70ca44772ed8 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_timeline.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/explorer/anomaly_timeline.tsx @@ -66,6 +66,7 @@ import { useAnomalyExplorerContext } from './anomaly_explorer_context'; import { getTimeBoundsFromSelection } from './hooks/use_selected_cells'; import { SwimLaneWrapper } from './alerts'; import { Y_AXIS_LABEL_WIDTH } from './constants'; +import { CASES_TOAST_MESSAGES_TITLES } from '../../cases/constants'; import type { ExplorerState } from './explorer_data'; import { useJobSelection } from './hooks/use_job_selection'; @@ -187,7 +188,10 @@ export const AnomalyTimeline: FC = React.memo( [severityUpdate, swimLaneSeverity] ); - const openCasesModalCallback = useCasesModal(ANOMALY_SWIMLANE_EMBEDDABLE_TYPE); + const openCasesModalCallback = useCasesModal( + ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, + CASES_TOAST_MESSAGES_TITLES.ANOMALY_TIMELINE + ); const openCasesModal = useCallback( (swimLaneType: SwimlaneType) => { @@ -235,6 +239,7 @@ export const AnomalyTimeline: FC = React.memo( /> ), panel: 'addToDashboardPanel', + icon: 'dashboardApp', 'data-test-subj': 'mlAnomalyTimelinePanelAddToDashboardButton', }); @@ -280,6 +285,7 @@ export const AnomalyTimeline: FC = React.memo( defaultMessage="Add to case" /> ), + icon: 'casesApp', 'data-test-subj': 'mlAnomalyTimelinePanelAttachToCaseButton', }); @@ -428,6 +434,8 @@ export const AnomalyTimeline: FC = React.memo( defaultMessage: 'Actions', })} color="text" + display="base" + isSelected={isMenuOpen} iconType="boxesHorizontal" onClick={setIsMenuOpen.bind(null, !isMenuOpen)} data-test-subj="mlAnomalyTimelinePanelMenu" diff --git a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecast_button.tsx b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecast_button.tsx index c989bb6ebd38d..cf94ada9c35c9 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecast_button.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecast_button.tsx @@ -20,6 +20,8 @@ export const ForecastButton: FC = ({ isDisabled, onClick, mode = 'full' } const Button = mode === 'full' ? EuiButton : EuiButtonEmpty; return (