[Lens] Disable the global timepicker for index pattern without primary timefield and visualizations without timefield (#108052)

This commit is contained in:
Marta Bondyra 2021-08-13 18:24:00 +02:00 committed by GitHub
parent dd85150f73
commit e33daccca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 154 additions and 8 deletions

View file

@ -269,6 +269,52 @@ describe('Lens App', () => {
});
});
describe('TopNavMenu#showDatePicker', () => {
it('shows date picker if any used index pattern isTimeBased', async () => {
const customServices = makeDefaultServices(sessionIdSubject);
customServices.data.indexPatterns.get = jest
.fn()
.mockImplementation((id) =>
Promise.resolve({ id, isTimeBased: () => true } as IndexPattern)
);
const { services } = await mountWith({ services: customServices });
expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith(
expect.objectContaining({ showDatePicker: true }),
{}
);
});
it('shows date picker if active datasource isTimeBased', async () => {
const customServices = makeDefaultServices(sessionIdSubject);
customServices.data.indexPatterns.get = jest
.fn()
.mockImplementation((id) =>
Promise.resolve({ id, isTimeBased: () => true } as IndexPattern)
);
const customProps = makeDefaultProps();
customProps.datasourceMap.testDatasource.isTimeBased = () => true;
const { services } = await mountWith({ props: customProps, services: customServices });
expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith(
expect.objectContaining({ showDatePicker: true }),
{}
);
});
it('does not show date picker if index pattern nor active datasource is not time based', async () => {
const customServices = makeDefaultServices(sessionIdSubject);
customServices.data.indexPatterns.get = jest
.fn()
.mockImplementation((id) =>
Promise.resolve({ id, isTimeBased: () => true } as IndexPattern)
);
const customProps = makeDefaultProps();
customProps.datasourceMap.testDatasource.isTimeBased = () => false;
const { services } = await mountWith({ props: customProps, services: customServices });
expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith(
expect.objectContaining({ showDatePicker: false }),
{}
);
});
});
describe('persistence', () => {
it('passes query and indexPatterns to TopNavMenu', async () => {
const { instance, lensStore, services } = await mountWith({ preloadedState: {} });
@ -294,7 +340,7 @@ describe('Lens App', () => {
expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith(
expect.objectContaining({
query: 'fake query',
indexPatterns: [{ id: 'mockip' }],
indexPatterns: [{ id: 'mockip', isTimeBased: expect.any(Function) }],
}),
{}
);

View file

@ -166,6 +166,7 @@ export const LensTopNavMenu = ({
activeDatasourceId,
datasourceStates,
} = useLensSelector((state) => state.lens);
const allLoaded = Object.values(datasourceStates).every(({ isLoading }) => isLoading === false);
useEffect(() => {
const activeDatasource =
@ -390,7 +391,16 @@ export const LensTopNavMenu = ({
dateRangeTo={to}
indicateNoData={indicateNoData}
showSearchBar={true}
showDatePicker={true}
showDatePicker={
indexPatterns.some((ip) => ip.isTimeBased()) ||
Boolean(
allLoaded &&
activeDatasourceId &&
datasourceMap[activeDatasourceId].isTimeBased(
datasourceStates[activeDatasourceId].state
)
)
}
showQueryBar={true}
showFilterBar={true}
data-test-subj="lnsApp_topNav"

View file

@ -1544,4 +1544,83 @@ describe('IndexPattern Data Source', () => {
});
});
});
describe('#isTimeBased', () => {
it('should return true if date histogram exists in any layer', () => {
const state = enrichBaseState({
currentIndexPatternId: '1',
layers: {
first: {
indexPatternId: '1',
columnOrder: ['metric'],
columns: {
metric: {
label: 'Count of records2',
dataType: 'number',
isBucketed: false,
sourceField: 'Records',
operationType: 'count',
},
},
},
second: {
indexPatternId: '1',
columnOrder: ['bucket1', 'bucket2', 'metric2'],
columns: {
metric2: {
label: 'Count of records',
dataType: 'number',
isBucketed: false,
sourceField: 'Records',
operationType: 'count',
},
bucket1: {
label: 'Date',
dataType: 'date',
isBucketed: true,
operationType: 'date_histogram',
sourceField: 'timestamp',
params: {
interval: '1d',
},
},
bucket2: {
label: 'Terms',
dataType: 'string',
isBucketed: true,
operationType: 'terms',
sourceField: 'geo.src',
params: {
orderBy: { type: 'alphabetical' },
orderDirection: 'asc',
size: 10,
},
},
},
},
},
});
expect(indexPatternDatasource.isTimeBased(state)).toEqual(true);
});
it('should return false 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(false);
});
});
});

View file

@ -474,6 +474,16 @@ export function getIndexPatternDatasource({
const ids = Object.values(state.layers || {}).map(({ indexPatternId }) => indexPatternId);
return ids.filter((id) => !state.indexPatterns[id]);
},
isTimeBased: (state) => {
const { layers } = state;
return (
Boolean(layers) &&
Object.values(layers).some((layer) => {
const buckets = layer.columnOrder.filter((colId) => layer.columns[colId].isBucketed);
return buckets.some((colId) => layer.columns[colId].operationType === 'date_histogram');
})
);
},
};
return indexPatternDatasource;

View file

@ -147,6 +147,7 @@ export function createMockDatasource(id: string): DatasourceMock {
publicAPIMock,
getErrorMessages: jest.fn((_state) => undefined),
checkIntegrity: jest.fn((_state) => []),
isTimeBased: jest.fn(),
};
}
@ -309,9 +310,7 @@ export function mockDataPlugin(sessionIdSubject = new Subject<string>()) {
state$: new Observable(),
},
indexPatterns: {
get: jest.fn((id) => {
return new Promise((resolve) => resolve({ id }));
}),
get: jest.fn().mockImplementation((id) => Promise.resolve({ id, isTimeBased: () => true })),
},
search: createMockSearchService(),
nowProvider: {

View file

@ -117,9 +117,7 @@ function makeDefaultData(): jest.Mocked<DataPublicPluginStart> {
state$: new Observable(),
},
indexPatterns: {
get: jest.fn((id) => {
return new Promise((resolve) => resolve({ id }));
}),
get: jest.fn().mockImplementation((id) => Promise.resolve({ id, isTimeBased: () => true })),
},
search: createMockSearchService(),
nowProvider: {

View file

@ -265,6 +265,10 @@ export interface Datasource<T = unknown, P = unknown> {
* The frame calls this function to display warnings about visualization
*/
getWarningMessages?: (state: T, frame: FramePublicAPI) => React.ReactNode[] | undefined;
/**
* Checks if the visualization created is time based, for example date histogram
*/
isTimeBased: (state: T) => boolean;
}
export interface DatasourceFixAction<T> {