[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
This commit is contained in:
Dima Arnautov 2021-01-26 17:36:44 +01:00 committed by GitHub
parent 110e880fbf
commit b35a4e645d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 13 deletions

View file

@ -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;

View file

@ -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',
});
});
});

View file

@ -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) => {

View file

@ -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 />