From b35a4e645d2ae2a4f44a8e127bd75d4b53e2ab50 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 26 Jan 2021 17:36:44 +0100 Subject: [PATCH] [ML] Fix swim lane time selection with a single time point and the Watcher URL (#89125) * [ML] fix swim lane selected times with only start boundaries * [ML] unit test * [ML] update url variables * [ML] selectedLanes to an array type * [ML] handle legacy query params --- .../ml/common/types/ml_url_generator.ts | 13 ++++++- .../explorer/hooks/use_selected_cells.test.ts | 34 +++++++++++++++++ .../explorer/hooks/use_selected_cells.ts | 37 +++++++++++++------ .../components/create_watch_flyout/email.html | 2 +- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/ml/common/types/ml_url_generator.ts b/x-pack/plugins/ml/common/types/ml_url_generator.ts index 3ff57fc622da..d7fded829995 100644 --- a/x-pack/plugins/ml/common/types/ml_url_generator.ts +++ b/x-pack/plugins/ml/common/types/ml_url_generator.ts @@ -93,7 +93,18 @@ export interface ExplorerAppState { mlExplorerSwimlane: { selectedType?: 'overall' | 'viewBy'; selectedLanes?: string[]; - selectedTimes?: [number, number]; + /** + * @deprecated legacy query param variable, use `selectedLanes` + */ + selectedLane?: string[] | string; + /** + * It's possible to have only "from" time boundaries, e.g. in the Watcher URL + */ + selectedTimes?: [number, number] | number; + /** + * @deprecated legacy query param variable, use `selectedTimes` + */ + selectedTime?: [number, number] | number; showTopFieldValues?: boolean; viewByFieldName?: string; viewByPerPage?: number; diff --git a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.test.ts b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.test.ts index 08c8d11987f1..2308d4ae4f15 100644 --- a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.test.ts +++ b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.test.ts @@ -130,4 +130,38 @@ describe('useSelectedCells', () => { }, }); }); + + test('should extend single time point selection with a bucket interval value', () => { + (useTimefilter() as jest.Mocked).getBounds.mockReturnValue({ + min: moment(1498824778 * 1000), + max: moment(1502366798 * 1000), + }); + + const urlState = { + mlExplorerSwimlane: { + selectedType: 'overall', + selectedLanes: ['Overall'], + selectedTimes: 1498780800, + showTopFieldValues: true, + viewByFieldName: 'apache2.access.remote_ip', + viewByFromPage: 1, + viewByPerPage: 10, + }, + mlExplorerFilter: {}, + } as ExplorerAppState; + + const setUrlState = jest.fn(); + + const bucketInterval = 86400; + + const { result } = renderHook(() => useSelectedCells(urlState, setUrlState, bucketInterval)); + + expect(result.current[0]).toEqual({ + lanes: ['Overall'], + showTopFieldValues: true, + times: [1498780800, 1498867200], + type: 'overall', + viewByFieldName: 'apache2.access.remote_ip', + }); + }); }); diff --git a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts index 4ce828b0b763..becc6197af88 100644 --- a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts +++ b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts @@ -19,18 +19,33 @@ export const useSelectedCells = ( const timeBounds = timeFilter.getBounds(); // keep swimlane selection, restore selectedCells from AppState - const selectedCells = useMemo(() => { - return appState?.mlExplorerSwimlane?.selectedType !== undefined - ? { - type: appState.mlExplorerSwimlane.selectedType, - lanes: appState.mlExplorerSwimlane.selectedLanes!, - times: appState.mlExplorerSwimlane.selectedTimes!, - showTopFieldValues: appState.mlExplorerSwimlane.showTopFieldValues, - viewByFieldName: appState.mlExplorerSwimlane.viewByFieldName, - } - : undefined; + const selectedCells: AppStateSelectedCells | undefined = useMemo(() => { + if (!appState?.mlExplorerSwimlane?.selectedType) { + return; + } + + let times = + appState.mlExplorerSwimlane.selectedTimes ?? appState.mlExplorerSwimlane.selectedTime!; + if (typeof times === 'number' && bucketIntervalInSeconds) { + times = [times, times + bucketIntervalInSeconds]; + } + + let lanes = + appState.mlExplorerSwimlane.selectedLanes ?? appState.mlExplorerSwimlane.selectedLane!; + + if (typeof lanes === 'string') { + lanes = [lanes]; + } + + return { + type: appState.mlExplorerSwimlane.selectedType, + lanes, + times, + showTopFieldValues: appState.mlExplorerSwimlane.showTopFieldValues, + viewByFieldName: appState.mlExplorerSwimlane.viewByFieldName, + } as AppStateSelectedCells; // TODO fix appState to use memoization - }, [JSON.stringify(appState?.mlExplorerSwimlane)]); + }, [JSON.stringify(appState?.mlExplorerSwimlane), bucketIntervalInSeconds]); const setSelectedCells = useCallback( (swimlaneSelectedCells?: AppStateSelectedCells) => { diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/email.html b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/email.html index 2e93c7eefcf1..713a68ba0c03 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/email.html +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/create_watch_flyout/email.html @@ -22,7 +22,7 @@

- + <%= openInAnomalyExplorerLinkText %>