@@ -1,6 +1,6 @@
|
||||
import { defaultDataQueryKind, PanelQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
||||
|
||||
import { getRuntimePanelDataSource } from './utils';
|
||||
import { ensureUniqueRefIds, getRuntimePanelDataSource } from './utils';
|
||||
|
||||
describe('getRuntimePanelDataSource', () => {
|
||||
it('should return uid and type when explicit datasource UID is provided', () => {
|
||||
@@ -140,3 +140,76 @@ describe('getRuntimePanelDataSource', () => {
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ensureUniqueRefIds', () => {
|
||||
const createQuery = (refId: string): PanelQueryKind => ({
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
refId,
|
||||
hidden: false,
|
||||
query: {
|
||||
kind: 'DataQuery',
|
||||
version: defaultDataQueryKind().version,
|
||||
group: 'prometheus',
|
||||
spec: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
it('should assign unique refIds to queries without refIds', () => {
|
||||
const queries: PanelQueryKind[] = [createQuery(''), createQuery(''), createQuery('')];
|
||||
|
||||
const result = ensureUniqueRefIds(queries);
|
||||
|
||||
expect(result[0].spec.refId).toBe('A');
|
||||
expect(result[1].spec.refId).toBe('B');
|
||||
expect(result[2].spec.refId).toBe('C');
|
||||
});
|
||||
|
||||
it('should preserve existing refIds and fill gaps', () => {
|
||||
const queries: PanelQueryKind[] = [createQuery('A'), createQuery(''), createQuery('D'), createQuery('')];
|
||||
|
||||
const result = ensureUniqueRefIds(queries);
|
||||
|
||||
expect(result[0].spec.refId).toBe('A');
|
||||
expect(result[1].spec.refId).toBe('B');
|
||||
expect(result[2].spec.refId).toBe('D');
|
||||
expect(result[3].spec.refId).toBe('C');
|
||||
});
|
||||
|
||||
it('should handle all queries having existing refIds', () => {
|
||||
const queries: PanelQueryKind[] = [createQuery('A'), createQuery('B'), createQuery('C')];
|
||||
|
||||
const result = ensureUniqueRefIds(queries);
|
||||
|
||||
expect(result[0].spec.refId).toBe('A');
|
||||
expect(result[1].spec.refId).toBe('B');
|
||||
expect(result[2].spec.refId).toBe('C');
|
||||
});
|
||||
|
||||
it('should only modify queries without refIds', () => {
|
||||
const queries: PanelQueryKind[] = [createQuery('A'), createQuery(''), createQuery('C')];
|
||||
|
||||
const result = ensureUniqueRefIds(queries);
|
||||
|
||||
// Existing refIds should be preserved
|
||||
expect(result[0].spec.refId).toBe('A');
|
||||
expect(result[2].spec.refId).toBe('C');
|
||||
// Missing refId should be assigned
|
||||
expect(result[1].spec.refId).toBe('B');
|
||||
});
|
||||
|
||||
it('should handle empty array', () => {
|
||||
const result = ensureUniqueRefIds([]);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle single query without refId', () => {
|
||||
const queries: PanelQueryKind[] = [createQuery('')];
|
||||
|
||||
const result = ensureUniqueRefIds(queries);
|
||||
|
||||
expect(result[0].spec.refId).toBe('A');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getNextRefId } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import {
|
||||
SceneDataProvider,
|
||||
@@ -164,12 +165,15 @@ export function createPanelDataProvider(panelKind: PanelKind): SceneDataProvider
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Ensure all queries have unique refIds before converting to scene queries
|
||||
const queriesWithUniqueRefIds = ensureUniqueRefIds(targets);
|
||||
|
||||
let dataProvider: SceneDataProvider | undefined = undefined;
|
||||
const datasource = getPanelDataSource(panelKind);
|
||||
|
||||
dataProvider = new SceneQueryRunner({
|
||||
datasource,
|
||||
queries: targets.map(panelQueryKindToSceneQuery),
|
||||
queries: queriesWithUniqueRefIds.map(panelQueryKindToSceneQuery),
|
||||
maxDataPoints: panel.data.spec.queryOptions.maxDataPoints ?? undefined,
|
||||
maxDataPointsFromWidth: true,
|
||||
cacheTimeout: panel.data.spec.queryOptions.cacheTimeout,
|
||||
@@ -341,6 +345,21 @@ export function getDataSourceForQuery(querySpecDS: DataSourceRef | undefined | n
|
||||
};
|
||||
}
|
||||
|
||||
export function ensureUniqueRefIds(queries: PanelQueryKind[]): PanelQueryKind[] {
|
||||
// Adapter to make PanelQueryKind[] work with getNextRefId (which expects { refId }[])
|
||||
const refIdAdapter = queries.map((q) => ({ refId: q.spec.refId }));
|
||||
|
||||
for (let i = 0; i < queries.length; i++) {
|
||||
if (!queries[i].spec.refId) {
|
||||
const newRefId = getNextRefId(refIdAdapter);
|
||||
queries[i] = { ...queries[i], spec: { ...queries[i].spec, refId: newRefId } };
|
||||
refIdAdapter[i] = { refId: newRefId };
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
|
||||
// Add datasource to match Go backend V2→V1 conversion:
|
||||
// - If explicit UID (datasource.name) exists → add { uid, type }
|
||||
|
||||
Reference in New Issue
Block a user