[9.0] [ML] Anomaly Detection: Show Switch to apply time range when opening job selector from left nav (#213382) (#213925)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[ML] Anomaly Detection: Show `Switch to apply time range` when
opening job selector from left nav
(#213382)](https://github.com/elastic/kibana/pull/213382)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Robert
Jaszczurek","email":"92210485+rbrtj@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-03-11T13:50:52Z","message":"[ML]
Anomaly Detection: Show `Switch to apply time range` when opening job
selector from left nav (#213382)\n\nFix for:
https://github.com/elastic/kibana/issues/211018
and\nhttps://github.com/elastic/kibana/issues/212407\n\nNote:
Previously, the `apply time range` setting was saved in local\nstorage
even if the changes were not applied. After the fix, the setting\nis
saved in local storage only if the user applies the new
selection.\n\nAfter:\n\n\nhttps://github.com/user-attachments/assets/1657f0f4-c580-4941-9582-bf5f9dc3cd55","sha":"cbcb7edb94e44bc8edc1a4e6f21bff5504c4d61a","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix",":ml","Feature:Anomaly
Detection","v9.0.0","Team:ML","backport:version","v8.18.0","v9.1.0"],"title":"[ML]
Anomaly Detection: Show `Switch to apply time range` when opening job
selector from left
nav","number":213382,"url":"https://github.com/elastic/kibana/pull/213382","mergeCommit":{"message":"[ML]
Anomaly Detection: Show `Switch to apply time range` when opening job
selector from left nav (#213382)\n\nFix for:
https://github.com/elastic/kibana/issues/211018
and\nhttps://github.com/elastic/kibana/issues/212407\n\nNote:
Previously, the `apply time range` setting was saved in local\nstorage
even if the changes were not applied. After the fix, the setting\nis
saved in local storage only if the user applies the new
selection.\n\nAfter:\n\n\nhttps://github.com/user-attachments/assets/1657f0f4-c580-4941-9582-bf5f9dc3cd55","sha":"cbcb7edb94e44bc8edc1a4e6f21bff5504c4d61a"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/213382","number":213382,"mergeCommit":{"message":"[ML]
Anomaly Detection: Show `Switch to apply time range` when opening job
selector from left nav (#213382)\n\nFix for:
https://github.com/elastic/kibana/issues/211018
and\nhttps://github.com/elastic/kibana/issues/212407\n\nNote:
Previously, the `apply time range` setting was saved in local\nstorage
even if the changes were not applied. After the fix, the setting\nis
saved in local storage only if the user applies the new
selection.\n\nAfter:\n\n\nhttps://github.com/user-attachments/assets/1657f0f4-c580-4941-9582-bf5f9dc3cd55","sha":"cbcb7edb94e44bc8edc1a4e6f21bff5504c4d61a"}}]}]
BACKPORT-->

Co-authored-by: Robert Jaszczurek <92210485+rbrtj@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2025-03-12 02:46:51 +11:00 committed by GitHub
parent 52f23ee058
commit c68d82ee86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 48 additions and 72 deletions

View file

@ -5,33 +5,26 @@
* 2.0.
*/
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import {
EuiButtonEmpty,
EuiFlexItem,
EuiFlexGroup,
EuiFlyout,
EuiHorizontalRule,
} from '@elastic/eui';
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);
}
const handleJobSelectionClick = useCallback(async () => {
try {
const result = await openJobSelectionFlyout({
singleSelection,
withTimeRangeSelector: true,
timeseriesOnly,
selectedIds,
});
function showFlyout() {
setIsFlyoutVisible(true);
}
function handleJobSelectionClick() {
showFlyout();
}
const applySelection: JobSelectorFlyoutProps['onSelectionConfirmed'] = useCallback(
({ newSelection, jobIds, time }) => {
setSelectedIds(newSelection);
onSelectionChange?.({ jobIds, time });
closeFlyout();
},
[onSelectionChange]
);
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 (
<EuiFlyout
onClose={closeFlyout}
data-test-subj="mlFlyoutJobSelector"
aria-labelledby="jobSelectorFlyout"
>
<JobSelectorFlyoutContent
dateFormatTz={dateFormatTz}
timeseriesOnly={timeseriesOnly}
singleSelection={singleSelection}
selectedIds={selectedIds}
onSelectionConfirmed={applySelection}
onFlyoutClose={closeFlyout}
applyTimeRangeConfig={applyTimeRangeConfig}
onTimeRangeConfigChange={setApplyTimeRangeConfig}
/>
</EuiFlyout>
);
}
}
return (
<div>
<JobInfoFlyoutsProvider>
{renderJobSelectionBar()}
{renderFlyout()}
<JobInfoFlyoutsManager />
</JobInfoFlyoutsProvider>
</div>

View file

@ -73,7 +73,7 @@ export const JobSelectorFlyoutContent: FC<JobSelectorFlyoutProps> = ({
onJobsFetched,
onSelectionConfirmed,
onFlyoutClose,
applyTimeRangeConfig,
applyTimeRangeConfig: initialApplyTimeRangeConfig,
onTimeRangeConfigChange,
withTimeRangeSelector = true,
}) => {
@ -85,6 +85,9 @@ export const JobSelectorFlyoutContent: FC<JobSelectorFlyoutProps> = ({
} = 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<JobSelectorFlyoutProps> = ({
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<JobSelectorFlyoutProps> = ({
}
function toggleTimerangeSwitch() {
if (onTimeRangeConfigChange) {
onTimeRangeConfigChange(!applyTimeRangeConfig);
}
setApplyTimeRangeConfig((prev) => !prev);
}
function clearSelection() {
@ -242,9 +247,7 @@ export const JobSelectorFlyoutContent: FC<JobSelectorFlyoutProps> = ({
</EuiButtonEmpty>
)}
</EuiFlexItem>
{withTimeRangeSelector &&
applyTimeRangeConfig !== undefined &&
jobs.length !== 0 ? (
{withTimeRangeSelector && jobs.length !== 0 ? (
<EuiFlexItem grow={false}>
<EuiSwitch
label={i18n.translate(

View file

@ -9,6 +9,8 @@ import React, { useCallback, useEffect, useRef } from 'react';
import moment from 'moment';
import type { KibanaReactOverlays } from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { useStorage } from '@kbn/ml-local-storage';
import { ML_APPLY_TIME_RANGE_CONFIG } from '../../../../common/types/storage';
import { useMlKibana } from '../kibana';
import {
JobSelectorFlyoutContent,
@ -23,6 +25,10 @@ export type GetJobSelection = ReturnType<typeof useJobSelectionFlyout>;
*/
export function useJobSelectionFlyout() {
const { overlays, services } = useMlKibana();
const [applyTimeRangeConfig, setApplyTimeRangeConfig] = useStorage(
ML_APPLY_TIME_RANGE_CONFIG,
true
);
const flyoutRef = useRef<ReturnType<KibanaReactOverlays['openFlyout']>>();
@ -40,10 +46,12 @@ export function useJobSelectionFlyout() {
singleSelection?: boolean;
withTimeRangeSelector?: boolean;
timeseriesOnly?: boolean;
selectedIds?: string[];
} = {
singleSelection: false,
withTimeRangeSelector: true,
timeseriesOnly: false,
selectedIds: [],
}
): Promise<JobSelectionResult> => {
const { uiSettings } = services;
@ -56,8 +64,10 @@ export function useJobSelectionFlyout() {
flyoutRef.current = overlays.openFlyout(
<KibanaContextProvider services={services}>
<JobSelectorFlyoutContent
selectedIds={[]}
selectedIds={config.selectedIds}
withTimeRangeSelector={config.withTimeRangeSelector}
applyTimeRangeConfig={applyTimeRangeConfig}
onTimeRangeConfigChange={setApplyTimeRangeConfig}
dateFormatTz={dateFormatTz}
singleSelection={!!config.singleSelection}
timeseriesOnly={!!config.timeseriesOnly}
@ -77,6 +87,6 @@ export function useJobSelectionFlyout() {
}
});
},
[overlays, services]
[services, overlays, applyTimeRangeConfig, setApplyTimeRangeConfig]
);
}