mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Lens] Disable the global timepicker for index pattern without primary timefield and visualizations without timefield (#108052)
This commit is contained in:
parent
dd85150f73
commit
e33daccca3
7 changed files with 154 additions and 8 deletions
|
@ -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) }],
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue