mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Add Mixed Datasource (#51605)
* Toggle on the mixed mode option * Ensure switching to mixed gives existing query prev datasource * WIP - Populate datasource when switching between mixed and not * WIP - handle change from mixed * Remove preimport filter, refine filter to work for queries * WIP debugging datasource transition * Ensure creating a new query gets target data source if switching with no matches between * Add mixed datasource to rich history display * Cleanup console logs, add relevant comments * Add feature toggle for mixed datasource * Fix Wrapper tests * Fix tests! * Fix test types and add feature tracking * Remove unnecessary default, remove explore/mixed workarounds for D2E * Move display text logic to mixed datasource file * Add in the default query parameters to a generated empty query * Condense some code * Apply suggestions from code review Co-authored-by: Giordano Ricci <me@giordanoricci.com> Co-authored-by: Giordano Ricci <me@giordanoricci.com>
This commit is contained in:
co-authored by
Giordano Ricci
parent
a98920f910
commit
e2258120e7
@@ -7,6 +7,7 @@ import {
|
||||
DataQuery,
|
||||
DataQueryRequest,
|
||||
DataSourceApi,
|
||||
DataSourceRef,
|
||||
dateMath,
|
||||
DateTime,
|
||||
DefaultTimeZone,
|
||||
@@ -24,7 +25,7 @@ import {
|
||||
toUtc,
|
||||
urlUtil,
|
||||
} from '@grafana/data';
|
||||
import { DataSourceSrv } from '@grafana/runtime';
|
||||
import { DataSourceSrv, getDataSourceSrv } from '@grafana/runtime';
|
||||
import { RefreshPicker } from '@grafana/ui';
|
||||
import store from 'app/core/store';
|
||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
@@ -70,19 +71,6 @@ export async function getExploreUrl(args: GetExploreUrlArguments): Promise<strin
|
||||
let exploreTargets: DataQuery[] = panel.targets.map((t) => omit(t, 'legendFormat'));
|
||||
let url: string | undefined;
|
||||
|
||||
// Mixed datasources need to choose only one datasource
|
||||
if (exploreDatasource.meta?.id === 'mixed' && exploreTargets) {
|
||||
// Find first explore datasource among targets
|
||||
for (const t of exploreTargets) {
|
||||
const datasource = await datasourceSrv.get(t.datasource || undefined);
|
||||
if (datasource) {
|
||||
exploreDatasource = datasource;
|
||||
exploreTargets = panel.targets.filter((t) => t.datasource === datasource.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exploreDatasource) {
|
||||
const range = timeSrv.timeRangeForUrl();
|
||||
let state: Partial<ExploreUrlState> = { range };
|
||||
@@ -99,7 +87,7 @@ export async function getExploreUrl(args: GetExploreUrlArguments): Promise<strin
|
||||
...state,
|
||||
datasource: exploreDatasource.name,
|
||||
context: 'explore',
|
||||
queries: exploreTargets.map((t) => ({ ...t, datasource: exploreDatasource.getRef() })),
|
||||
queries: exploreTargets,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -254,8 +242,34 @@ export function generateKey(index = 0): string {
|
||||
return `Q-${uuidv4()}-${index}`;
|
||||
}
|
||||
|
||||
export function generateEmptyQuery(queries: DataQuery[], index = 0): DataQuery {
|
||||
return { refId: getNextRefIdChar(queries), key: generateKey(index) };
|
||||
export async function generateEmptyQuery(
|
||||
queries: DataQuery[],
|
||||
index = 0,
|
||||
dataSourceOverride?: DataSourceRef
|
||||
): Promise<DataQuery> {
|
||||
let datasourceInstance: DataSourceApi | undefined;
|
||||
let datasourceRef: DataSourceRef | null | undefined;
|
||||
let defaultQuery: Partial<DataQuery> | undefined;
|
||||
|
||||
// datasource override is if we have switched datasources with no carry-over - we want to create a new query with a datasource we define
|
||||
if (dataSourceOverride) {
|
||||
datasourceRef = dataSourceOverride;
|
||||
} else if (queries.length > 0 && queries[queries.length - 1].datasource) {
|
||||
// otherwise use last queries' datasource
|
||||
datasourceRef = queries[queries.length - 1].datasource;
|
||||
} else {
|
||||
// if neither exists, use the default datasource
|
||||
datasourceInstance = await getDataSourceSrv().get();
|
||||
defaultQuery = datasourceInstance.getDefaultQuery?.(CoreApp.Explore);
|
||||
datasourceRef = datasourceInstance.getRef();
|
||||
}
|
||||
|
||||
if (!datasourceInstance) {
|
||||
datasourceInstance = await getDataSourceSrv().get(datasourceRef);
|
||||
defaultQuery = datasourceInstance.getDefaultQuery?.(CoreApp.Explore);
|
||||
}
|
||||
|
||||
return { refId: getNextRefIdChar(queries), key: generateKey(index), datasource: datasourceRef, ...defaultQuery };
|
||||
}
|
||||
|
||||
export const generateNewKeyAndAddRefIdIfMissing = (target: DataQuery, queries: DataQuery[], index = 0): DataQuery => {
|
||||
@@ -267,8 +281,13 @@ export const generateNewKeyAndAddRefIdIfMissing = (target: DataQuery, queries: D
|
||||
|
||||
/**
|
||||
* Ensure at least one target exists and that targets have the necessary keys
|
||||
*
|
||||
* This will return an empty array if there are no datasources, as Explore is not usable in that state
|
||||
*/
|
||||
export function ensureQueries(queries?: DataQuery[]): DataQuery[] {
|
||||
export async function ensureQueries(
|
||||
queries?: DataQuery[],
|
||||
newQueryDataSourceOverride?: DataSourceRef
|
||||
): Promise<DataQuery[]> {
|
||||
if (queries && typeof queries === 'object' && queries.length > 0) {
|
||||
const allQueries = [];
|
||||
for (let index = 0; index < queries.length; index++) {
|
||||
@@ -287,7 +306,18 @@ export function ensureQueries(queries?: DataQuery[]): DataQuery[] {
|
||||
}
|
||||
return allQueries;
|
||||
}
|
||||
return [{ ...generateEmptyQuery(queries ?? []) }];
|
||||
|
||||
try {
|
||||
// if a datasourse override get its ref, otherwise get the default datasource
|
||||
const emptyQueryRef = newQueryDataSourceOverride ?? (await getDataSourceSrv().get()).getRef();
|
||||
|
||||
const emptyQuery = await generateEmptyQuery(queries ?? [], undefined, emptyQueryRef);
|
||||
return [emptyQuery];
|
||||
} catch {
|
||||
// if there are no datasources, return an empty array because we will not allow use of explore
|
||||
// this will occur on init of explore with no datasources defined
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,9 +374,9 @@ export function clearHistory(datasourceId: string) {
|
||||
store.delete(historyKey);
|
||||
}
|
||||
|
||||
export const getQueryKeys = (queries: DataQuery[], datasourceInstance?: DataSourceApi | null): string[] => {
|
||||
export const getQueryKeys = (queries: DataQuery[]): string[] => {
|
||||
const queryKeys = queries.reduce<string[]>((newQueryKeys, query, index) => {
|
||||
const primaryKey = datasourceInstance && datasourceInstance.name ? datasourceInstance.name : query.key;
|
||||
const primaryKey = query.datasource?.uid || query.key;
|
||||
return newQueryKeys.concat(`${primaryKey}-${index}`);
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user