Explore: Init with mixed DS if there's no root DS in the URL and queries have multiple datasources (#80068)

This commit is contained in:
Giordano Ricci 2024-01-05 14:19:39 +00:00 committed by GitHub
parent 329ec2624a
commit 8bd053e5f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 92 additions and 12 deletions

View File

@ -213,6 +213,69 @@ describe('useStateSync', () => {
expect(queries?.[0].datasource?.uid).toBe('loki-uid');
});
it('inits with mixed datasource if there are multiple datasources in queries and no root level datasource is defined', async () => {
const { location, waitForNextUpdate, store } = setup({
queryParams: {
panes: JSON.stringify({
one: {
queries: [
{ datasource: { name: 'loki', uid: 'loki-uid' } },
{ datasource: { name: 'elastic', uid: 'elastic-uid' } },
],
},
}),
schemaVersion: 1,
},
});
const initialHistoryLength = location.getHistory().length;
await waitForNextUpdate();
expect(location.getHistory().length).toBe(initialHistoryLength);
const search = location.getSearchObject();
expect(search.panes).toBeDefined();
const paneState = store.getState().explore.panes['one'];
expect(paneState?.datasourceInstance?.name).toBe(MIXED_DATASOURCE_NAME);
expect(paneState?.queries).toHaveLength(2);
expect(paneState?.queries?.[0].datasource?.uid).toBe('loki-uid');
expect(paneState?.queries?.[1].datasource?.uid).toBe('elastic-uid');
});
it("inits with a query's datasource if there are multiple datasources in queries, no root level datasource, and only one query has a valid datsource", async () => {
const { location, waitForNextUpdate, store } = setup({
queryParams: {
panes: JSON.stringify({
one: {
queries: [
{ datasource: { name: 'loki', uid: 'loki-uid' } },
{ datasource: { name: 'UNKNOWN', uid: 'UNKNOWN-UID' } },
],
},
}),
schemaVersion: 1,
},
});
const initialHistoryLength = location.getHistory().length;
await waitForNextUpdate();
expect(location.getHistory().length).toBe(initialHistoryLength);
const search = location.getSearchObject();
expect(search.panes).toBeDefined();
const paneState = store.getState().explore.panes['one'];
expect(paneState?.datasourceInstance?.getRef().uid).toBe('loki-uid');
expect(paneState?.queries).toHaveLength(1);
expect(paneState?.queries?.[0].datasource?.uid).toBe('loki-uid');
});
it('inits with the last used datasource from localStorage', async () => {
setLastUsedDatasourceUID(1, 'elastic-uid');
const { waitForNextUpdate, store } = setup({

View File

@ -1,7 +1,7 @@
import { identity, isEmpty, isEqual, isObject, mapValues, omitBy } from 'lodash';
import { useEffect, useRef } from 'react';
import { CoreApp, ExploreUrlState, DataSourceApi, toURLRange, EventBusSrv } from '@grafana/data';
import { CoreApp, ExploreUrlState, DataSourceApi, toURLRange, EventBusSrv, isTruthy } from '@grafana/data';
import { DataQuery, DataSourceRef } from '@grafana/schema';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { useAppNotification } from 'app/core/copy/appNotification';
@ -374,21 +374,38 @@ async function getPaneDatasource(
} catch (_) {}
}
// TODO: if queries have multiple datasources we should return mixed datasource
// Else we try to find a datasource in the queries, returning the first one that exists
const queriesWithDS = queries.filter((q) => q.datasource);
for (const query of queriesWithDS) {
try {
return await getDatasourceSrv().get(query.datasource);
} catch (_) {}
}
// Else we try to find a datasource in the queries
const queriesDatasources = [
...new Set(
queries
.map((q) => q.datasource)
.filter(isTruthy)
.map((ds) => (typeof ds === 'string' ? ds : ds.uid))
),
];
// If none of the queries specify a avalid datasource, we use the last used one
const lastUsedDSUID = getLastUsedDatasourceUID(orgId);
try {
if (queriesDatasources.length >= 1) {
const datasources = (await Promise.allSettled(queriesDatasources.map((ds) => getDatasourceSrv().get(ds)))).filter(
isFulfilled
);
// if queries have multiple (valid) datasources, we return the mixed datasource
if (datasources.length > 1) {
return await getDatasourceSrv().get(MIXED_DATASOURCE_NAME);
}
// otherwise we return the first datasource.
if (datasources.length === 1) {
return await getDatasourceSrv().get(queriesDatasources[0]);
}
}
} catch (_) {}
// If none of the queries specify a valid datasource, we use the last used one
return (
getDatasourceSrv()
.get(lastUsedDSUID)
.get(getLastUsedDatasourceUID(orgId))
// Or the default one
.catch(() => getDatasourceSrv().get())
.catch(() => undefined)