Skip to content

Commit

Permalink
[ML] Fix swim lane time selection with a single time point and the Wa…
Browse files Browse the repository at this point in the history
…tcher URL (elastic#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
  • Loading branch information
darnautov committed Jan 26, 2021
1 parent 96095a2 commit 28af8a6
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 13 deletions.
13 changes: 12 additions & 1 deletion x-pack/plugins/ml/common/types/ml_url_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,38 @@ describe('useSelectedCells', () => {
},
});
});

test('should extend single time point selection with a bucket interval value', () => {
(useTimefilter() as jest.Mocked<TimefilterContract>).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',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<br />
<br />

<a href="<%= serverAddress %>#/explorer/?_g=(ml:(jobIds:!('{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0._source.job_id}}')),time:(from:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.start.0}}',mode:absolute,to:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.end.0}}'))&_a=(explorer:(mlExplorerSwimlane:(selectedLane:Overall,selectedTime:{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.timestamp_epoch.0}},selectedType:overall)),query:(query_string:(analyze_wildcard:!t,query:'*')))">
<a href="<%= serverAddress %>#/explorer/?_g=(ml:(jobIds:!('{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0._source.job_id}}')),time:(from:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.start.0}}',mode:absolute,to:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.end.0}}'))&_a=(explorer:(mlExplorerSwimlane:(selectedLanes:!(Overall),selectedTimes:{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.timestamp_epoch.0}},selectedType:overall)),query:(query_string:(analyze_wildcard:!t,query:'*')))">
<%= openInAnomalyExplorerLinkText %>
</a>
<br />
Expand Down

0 comments on commit 28af8a6

Please sign in to comment.