From d2fa60ae1d7bd1afe46adfac6fe23917c10e5b9c Mon Sep 17 00:00:00 2001
From: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com>
Date: Tue, 11 Mar 2025 14:50:52 +0100
Subject: [PATCH] [ML] Anomaly Detection: Show `Switch to apply time range`
when opening job selector from left nav (#213382)
Fix for: https://github.com/elastic/kibana/issues/211018 and
https://github.com/elastic/kibana/issues/212407
Note: Previously, the `apply time range` setting was saved in local
storage even if the changes were not applied. After the fix, the setting
is saved in local storage only if the user applies the new selection.
After:
https://github.com/user-attachments/assets/1657f0f4-c580-4941-9582-bf5f9dc3cd55
(cherry picked from commit cbcb7edb94e44bc8edc1a4e6f21bff5504c4d61a)
---
.../components/job_selector/job_selector.tsx | 93 ++++++-------------
.../job_selector/job_selector_flyout.tsx | 17 ++--
.../contexts/ml/use_job_selection_flyout.tsx | 14 ++-
3 files changed, 50 insertions(+), 74 deletions(-)
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 (
-