Skip to content

Commit

Permalink
[Lens] Fix auto session-renewal on non-timebased data views (#129313)
Browse files Browse the repository at this point in the history
(cherry picked from commit f3f3b1a)
  • Loading branch information
flash1293 committed Apr 6, 2022
1 parent 8edbb89 commit 1b9994d
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2468,7 +2468,7 @@ describe('IndexPattern Data Source', () => {
});
describe('#isTimeBased', () => {
it('should return true if date histogram exists in any layer', () => {
const state = enrichBaseState({
let state = enrichBaseState({
currentIndexPatternId: '1',
layers: {
first: {
Expand Down Expand Up @@ -2521,10 +2521,17 @@ describe('IndexPattern Data Source', () => {
},
},
});
state = {
...state,
indexPatterns: {
...state.indexPatterns,
'1': { ...state.indexPatterns['1'], timeFieldName: undefined },
},
};
expect(indexPatternDatasource.isTimeBased(state)).toEqual(true);
});
it('should return false if date histogram exists but is detached from global time range in every layer', () => {
const state = enrichBaseState({
let state = enrichBaseState({
currentIndexPatternId: '1',
layers: {
first: {
Expand Down Expand Up @@ -2578,10 +2585,17 @@ describe('IndexPattern Data Source', () => {
},
},
});
state = {
...state,
indexPatterns: {
...state.indexPatterns,
'1': { ...state.indexPatterns['1'], timeFieldName: undefined },
},
};
expect(indexPatternDatasource.isTimeBased(state)).toEqual(false);
});
it('should return false if date histogram does not exist in any layer', () => {
const state = enrichBaseState({
let state = enrichBaseState({
currentIndexPatternId: '1',
layers: {
first: {
Expand All @@ -2599,8 +2613,36 @@ describe('IndexPattern Data Source', () => {
},
},
});
state = {
...state,
indexPatterns: {
...state.indexPatterns,
'1': { ...state.indexPatterns['1'], timeFieldName: undefined },
},
};
expect(indexPatternDatasource.isTimeBased(state)).toEqual(false);
});
it('should return true if the index pattern is time based even if date histogram does not exist in any layer', () => {
const state = enrichBaseState({
currentIndexPatternId: '1',
layers: {
first: {
indexPatternId: '1',
columnOrder: ['metric'],
columns: {
metric: {
label: 'Count of records',
dataType: 'number',
isBucketed: false,
sourceField: '___records___',
operationType: 'count',
},
},
},
},
});
expect(indexPatternDatasource.isTimeBased(state)).toEqual(true);
});
});

describe('#initializeDimension', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,18 +588,23 @@ export function getIndexPatternDatasource({
return ids.filter((id) => !state.indexPatterns[id]);
},
isTimeBased: (state) => {
const { layers } = state;
if (!state) return false;
const { layers, indexPatterns } = state;
return (
Boolean(layers) &&
Object.values(layers).some((layer) => {
const buckets = layer.columnOrder.filter((colId) => layer.columns[colId].isBucketed);
return buckets.some((colId) => {
const column = layer.columns[colId];
return (
isColumnOfType<DateHistogramIndexPatternColumn>('date_histogram', column) &&
!column.params.ignoreTimeRange
);
});
return (
Boolean(indexPatterns[layer.indexPatternId]?.timeFieldName) ||
layer.columnOrder
.filter((colId) => layer.columns[colId].isBucketed)
.some((colId) => {
const column = layer.columns[colId];
return (
isColumnOfType<DateHistogramIndexPatternColumn>('date_histogram', column) &&
!column.params.ignoreTimeRange
);
})
);
})
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ const createMiddleware = (data: DataPublicPluginStart, state?: Partial<LensAppSt
},
});
const store = {
getState: jest.fn(() => ({ lens: state || initialState })),
getState: jest.fn(() => ({
lens: state || {
...initialState,
activeDatasourceId: 'testDatasource',
datasourceStates: { testDatasource: { state: {} } },
},
})),
dispatch: jest.fn(),
};
const next = jest.fn();
Expand All @@ -39,6 +45,7 @@ describe('contextMiddleware', () => {
describe('time update', () => {
it('does update the searchSessionId when the state changes and too much time passed', () => {
const data = mockDataPlugin();
storeDeps.datasourceMap.testDatasource.isTimeBased = () => true;
(data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000));
(data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({
from: 'now-2m',
Expand Down Expand Up @@ -71,10 +78,46 @@ describe('contextMiddleware', () => {
});
expect(next).toHaveBeenCalledWith(action);
});
it('does not update the searchSessionId when current state is not time based', () => {
const data = mockDataPlugin();
storeDeps.datasourceMap.testDatasource.isTimeBased = () => false;
(data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000));
(data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({
from: 'now-2m',
to: 'now',
});
(data.query.timefilter.timefilter.getBounds as jest.Mock).mockReturnValue({
min: moment(Date.now() - 100000),
max: moment(Date.now() - 30000),
});
const { next, invoke, store } = createMiddleware(data);
const action = {
type: 'lens/setState',
payload: {
visualization: {
state: {},
activeId: 'id2',
},
},
};
invoke(action);
expect(store.dispatch).not.toHaveBeenCalledWith({
payload: {
resolvedDateRange: {
fromDate: '2021-01-10T04:00:00.000Z',
toDate: '2021-01-10T08:00:00.000Z',
},
searchSessionId: 'sessionId-1',
},
type: 'lens/setState',
});
expect(next).toHaveBeenCalledWith(action);
});
describe('when auto-apply is disabled', () => {
it('only updates searchSessionId when user applies changes', () => {
// setup
const data = mockDataPlugin();
storeDeps.datasourceMap.testDatasource.isTimeBased = () => true;
(data.nowProvider.get as jest.Mock).mockReturnValue(new Date(Date.now() - 30000));
(data.query.timefilter.timefilter.getTime as jest.Mock).mockReturnValue({
from: 'now-2m',
Expand All @@ -86,6 +129,8 @@ describe('contextMiddleware', () => {
});
const { invoke, store } = createMiddleware(data, {
...initialState,
activeDatasourceId: 'testDatasource',
datasourceStates: { testDatasource: { state: {}, isLoading: false } },
autoApplyDisabled: true,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,20 @@ import {
applyChanges,
selectAutoApplyEnabled,
} from '..';
import { LensAppState } from '../types';
import { LensAppState, LensState } from '../types';
import { getResolvedDateRange, containsDynamicMath } from '../../utils';
import { subscribeToExternalContext } from './subscribe_to_external_context';
import { onActiveDataChange } from '../lens_slice';
import { DatasourceMap } from '../../types';

function isTimeBased(state: LensState, datasourceMap: DatasourceMap) {
const { activeDatasourceId, datasourceStates } = state.lens;
return Boolean(
activeDatasourceId &&
datasourceStates[activeDatasourceId] &&
datasourceMap[activeDatasourceId].isTimeBased?.(datasourceStates[activeDatasourceId].state)
);
}

export const contextMiddleware = (storeDeps: LensStoreDeps) => (store: MiddlewareAPI) => {
const unsubscribeFromExternalContext = subscribeToExternalContext(
Expand All @@ -31,7 +41,8 @@ export const contextMiddleware = (storeDeps: LensStoreDeps) => (store: Middlewar
if (
!(action.payload as Partial<LensAppState>)?.searchSessionId &&
!onActiveDataChange.match(action) &&
(selectAutoApplyEnabled(store.getState()) || applyChanges.match(action))
(selectAutoApplyEnabled(store.getState()) || applyChanges.match(action)) &&
isTimeBased(store.getState(), storeDeps.datasourceMap)
) {
updateTimeRange(storeDeps.lensServices.data, store.dispatch);
}
Expand Down

0 comments on commit 1b9994d

Please sign in to comment.