diff --git a/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector.tsx b/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector.tsx index a01157b362c41..fd26e2baa2fab 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector.tsx @@ -5,33 +5,26 @@ * 2.0. */ -import React, { useState, useEffect, useCallback, useMemo } from 'react'; - -import { - EuiButtonEmpty, - EuiFlexItem, - EuiFlexGroup, - EuiFlyout, - EuiHorizontalRule, -} from '@elastic/eui'; +import React, { useState, useEffect, useMemo, useCallback } from 'react'; + +import { EuiButtonEmpty, EuiFlexItem, EuiFlexGroup, EuiHorizontalRule } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import './_index.scss'; -import { useStorage } from '@kbn/ml-local-storage'; import { ML_PAGES } from '../../../locator'; import type { Dictionary } from '../../../../common/types/common'; import { IdBadges } from './id_badges'; -import type { JobSelectorFlyoutProps } from './job_selector_flyout'; -import { BADGE_LIMIT, JobSelectorFlyoutContent } from './job_selector_flyout'; + +import { BADGE_LIMIT } from './job_selector_flyout'; import type { MlJobWithTimeRange, MlSummaryJob, } from '../../../../common/types/anomaly_detection_jobs'; -import { ML_APPLY_TIME_RANGE_CONFIG } from '../../../../common/types/storage'; import { FeedBackButton } from '../feedback_button'; import { JobInfoFlyoutsProvider } from '../../jobs/components/job_details_flyout'; import { JobInfoFlyoutsManager } from '../../jobs/components/job_details_flyout/job_details_context_manager'; +import { useJobSelectionFlyout } from '../../contexts/ml/use_job_selection_flyout'; export interface GroupObj { groupId: string; @@ -108,17 +101,13 @@ export function JobSelector({ selectedJobs = [], onSelectionChange, }: JobSelectorProps) { - const [applyTimeRangeConfig, setApplyTimeRangeConfig] = useStorage( - ML_APPLY_TIME_RANGE_CONFIG, - true - ); - const [selectedIds, setSelectedIds] = useState( mergeSelection(selectedJobIds, selectedGroups, singleSelection) ); const [showAllBarBadges, setShowAllBarBadges] = useState(false); - const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); + + const openJobSelectionFlyout = useJobSelectionFlyout(); // Ensure JobSelectionBar gets updated when selection via globalState changes. useEffect(() => { @@ -126,27 +115,24 @@ export function JobSelector({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify([selectedJobIds, selectedGroups])]); - function closeFlyout() { - setIsFlyoutVisible(false); - } - - function showFlyout() { - setIsFlyoutVisible(true); - } - - function handleJobSelectionClick() { - showFlyout(); - } - - const applySelection: JobSelectorFlyoutProps['onSelectionConfirmed'] = useCallback( - ({ newSelection, jobIds, time }) => { - setSelectedIds(newSelection); - - onSelectionChange?.({ jobIds, time }); - closeFlyout(); - }, - [onSelectionChange] - ); + const handleJobSelectionClick = useCallback(async () => { + try { + const result = await openJobSelectionFlyout({ + singleSelection, + withTimeRangeSelector: true, + timeseriesOnly, + selectedIds, + }); + + if (result) { + const { newSelection, jobIds, time } = result; + setSelectedIds(newSelection); + onSelectionChange?.({ jobIds, time }); + } + } catch { + // Flyout closed without selection + } + }, [onSelectionChange, openJobSelectionFlyout, selectedIds, singleSelection, timeseriesOnly]); const page = useMemo(() => { return singleSelection ? ML_PAGES.SINGLE_METRIC_VIEWER : ML_PAGES.ANOMALY_EXPLORER; @@ -154,7 +140,8 @@ export function JobSelector({ const removeJobId = (jobOrGroupId: string[]) => { const newSelection = selectedIds.filter((id) => !jobOrGroupId.includes(id)); - applySelection({ newSelection, jobIds: newSelection, time: undefined }); + setSelectedIds(newSelection); + onSelectionChange?.({ jobIds: newSelection, time: undefined }); }; function renderJobSelectionBar() { return ( @@ -213,34 +200,10 @@ export function JobSelector({ ); } - function renderFlyout() { - if (isFlyoutVisible) { - return ( - - - - ); - } - } - return (
{renderJobSelectionBar()} - {renderFlyout()}
diff --git a/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector_flyout.tsx b/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector_flyout.tsx index 58948161af298..0fec01c82c0a1 100644 --- a/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector_flyout.tsx +++ b/x-pack/platform/plugins/shared/ml/public/application/components/job_selector/job_selector_flyout.tsx @@ -73,7 +73,7 @@ export const JobSelectorFlyoutContent: FC = ({ onJobsFetched, onSelectionConfirmed, onFlyoutClose, - applyTimeRangeConfig, + applyTimeRangeConfig: initialApplyTimeRangeConfig, onTimeRangeConfigChange, withTimeRangeSelector = true, }) => { @@ -85,6 +85,9 @@ export const JobSelectorFlyoutContent: FC = ({ } = useMlKibana(); const [newSelection, setNewSelection] = useState(selectedIds); + const [applyTimeRangeConfig, setApplyTimeRangeConfig] = useState( + initialApplyTimeRangeConfig ?? false + ); const [isLoading, setIsLoading] = useState(true); const [showAllBadges, setShowAllBadges] = useState(false); @@ -113,6 +116,10 @@ export const JobSelectorFlyoutContent: FC = ({ const finalSelection = [...selectedGroupIds, ...standaloneJobs]; const time = applyTimeRangeConfig ? getTimeRangeFromSelection(jobs, finalSelection) : undefined; + if (onTimeRangeConfigChange && initialApplyTimeRangeConfig !== applyTimeRangeConfig) { + onTimeRangeConfigChange(applyTimeRangeConfig); + } + onSelectionConfirmed({ newSelection: finalSelection, jobIds: finalSelection, @@ -126,9 +133,7 @@ export const JobSelectorFlyoutContent: FC = ({ } function toggleTimerangeSwitch() { - if (onTimeRangeConfigChange) { - onTimeRangeConfigChange(!applyTimeRangeConfig); - } + setApplyTimeRangeConfig((prev) => !prev); } function clearSelection() { @@ -242,9 +247,7 @@ export const JobSelectorFlyoutContent: FC = ({ )} - {withTimeRangeSelector && - applyTimeRangeConfig !== undefined && - jobs.length !== 0 ? ( + {withTimeRangeSelector && jobs.length !== 0 ? ( ; */ export function useJobSelectionFlyout() { const { overlays, services } = useMlKibana(); + const [applyTimeRangeConfig, setApplyTimeRangeConfig] = useStorage( + ML_APPLY_TIME_RANGE_CONFIG, + true + ); const flyoutRef = useRef>(); @@ -40,10 +46,12 @@ export function useJobSelectionFlyout() { singleSelection?: boolean; withTimeRangeSelector?: boolean; timeseriesOnly?: boolean; + selectedIds?: string[]; } = { singleSelection: false, withTimeRangeSelector: true, timeseriesOnly: false, + selectedIds: [], } ): Promise => { const { uiSettings } = services; @@ -56,8 +64,10 @@ export function useJobSelectionFlyout() { flyoutRef.current = overlays.openFlyout(