From 0e13ee345d28b17a3a93696b2edf0685a29b4028 Mon Sep 17 00:00:00 2001 From: Kristina Date: Mon, 25 Jul 2022 13:05:57 -0500 Subject: [PATCH] Explore: Change datasourceName usage to datasourceUID or datasourceRef where appropriate (#52479) * First pass at using datasource UID when appropriate * Fix tests * be more lenient with lookup to accomodate different URLs * Make test setup get mock work like real datasource get * Fix the typing issue and remaining tests * Fix PR feedback --- devenv/docker/blocks/tempo/README.md | 2 +- .../src/field/fieldOverrides.test.ts | 7 +-- packages/grafana-data/src/types/dataLink.ts | 2 +- .../grafana-data/src/utils/dataLinks.test.ts | 4 +- packages/grafana-data/src/utils/dataLinks.ts | 6 +-- .../app/features/explore/ExploreToolbar.tsx | 4 +- .../explore/RichHistory/RichHistoryCard.tsx | 10 ++-- .../RichHistory/RichHistoryQueriesTab.tsx | 2 +- .../RichHistory/RichHistoryStarredTab.tsx | 2 +- .../explore/TraceView/createSpanLink.test.ts | 46 +++++++++---------- .../features/explore/spec/helper/setup.tsx | 9 +++- .../app/features/explore/state/datasource.ts | 2 +- .../app/features/explore/state/explorePane.ts | 10 +++- public/app/features/explore/state/main.ts | 5 +- .../app/features/explore/state/utils.test.ts | 8 ++-- public/app/features/explore/state/utils.ts | 8 ++-- .../app/features/explore/utils/links.test.ts | 2 +- 17 files changed, 71 insertions(+), 58 deletions(-) diff --git a/devenv/docker/blocks/tempo/README.md b/devenv/docker/blocks/tempo/README.md index 1c343a873b3..bb9f2811df9 100644 --- a/devenv/docker/blocks/tempo/README.md +++ b/devenv/docker/blocks/tempo/README.md @@ -1,4 +1,4 @@ Right now Tempo is before stable release so this uses :latest tag which means there can be changes depending on when you pull the image. -For adding some traces easily you can run Loki block and enable tracing (see ../loki/README.md) +For adding some traces easily you can run Loki block and enable tracing (see ../loki-promtail/README.md) diff --git a/packages/grafana-data/src/field/fieldOverrides.test.ts b/packages/grafana-data/src/field/fieldOverrides.test.ts index 41dc112fdc4..a276248862b 100644 --- a/packages/grafana-data/src/field/fieldOverrides.test.ts +++ b/packages/grafana-data/src/field/fieldOverrides.test.ts @@ -606,6 +606,7 @@ describe('getLinksSupplier', () => { getTimeRangeForUrl: (() => {}) as any, }); + const datasourceUid = '1234'; const f0 = new MutableDataFrame({ name: 'A', fields: [ @@ -619,7 +620,7 @@ describe('getLinksSupplier', () => { url: '', title: '', internal: { - datasourceUid: '0', + datasourceUid: datasourceUid, datasourceName: 'testDS', query: '12345', }, @@ -640,12 +641,12 @@ describe('getLinksSupplier', () => { ); const links = supplier({ valueRowIndex: 0 }); - + const encodeURIParams = `{"datasource":"${datasourceUid}","queries":["12345"],"panelsState":{}}`; expect(links.length).toBe(1); expect(links[0]).toEqual( expect.objectContaining({ title: 'testDS', - href: `/explore?left=${encodeURIComponent('{"datasource":"testDS","queries":["12345"],"panelsState":{}}')}`, + href: `/explore?left=${encodeURIComponent(encodeURIParams)}`, onClick: undefined, }) ); diff --git a/packages/grafana-data/src/types/dataLink.ts b/packages/grafana-data/src/types/dataLink.ts index 6d741b2d801..13e33675dc3 100644 --- a/packages/grafana-data/src/types/dataLink.ts +++ b/packages/grafana-data/src/types/dataLink.ts @@ -44,7 +44,7 @@ export interface DataLink { export interface InternalDataLink { query: T; datasourceUid: string; - datasourceName: string; + datasourceName: string; // used as a title if `DataLink.title` is empty panelsState?: ExplorePanelsState; } diff --git a/packages/grafana-data/src/utils/dataLinks.test.ts b/packages/grafana-data/src/utils/dataLinks.test.ts index 93a249a1df7..accaf0aab22 100644 --- a/packages/grafana-data/src/utils/dataLinks.test.ts +++ b/packages/grafana-data/src/utils/dataLinks.test.ts @@ -33,7 +33,7 @@ describe('mapInternalLinkToExplore', () => { expect.objectContaining({ title: 'dsName', href: `/explore?left=${encodeURIComponent( - '{"datasource":"dsName","queries":[{"query":"12344"}],"panelsState":{}}' + '{"datasource":"uid","queries":[{"query":"12344"}],"panelsState":{}}' )}`, onClick: undefined, }) @@ -76,7 +76,7 @@ describe('mapInternalLinkToExplore', () => { expect.objectContaining({ title: 'dsName', href: `/explore?left=${encodeURIComponent( - '{"datasource":"dsName","queries":[{"query":"12344"}],"panelsState":{"trace":{"spanId":"abcdef"}}}' + '{"datasource":"uid","queries":[{"query":"12344"}],"panelsState":{"trace":{"spanId":"abcdef"}}}' )}`, onClick: undefined, }) diff --git a/packages/grafana-data/src/utils/dataLinks.ts b/packages/grafana-data/src/utils/dataLinks.ts index 71dabe78e51..218c97950a4 100644 --- a/packages/grafana-data/src/utils/dataLinks.ts +++ b/packages/grafana-data/src/utils/dataLinks.ts @@ -51,7 +51,7 @@ export function mapInternalLinkToExplore(options: LinkToExploreOptions): LinkMod title: replaceVariables(title, scopedVars), // In this case this is meant to be internal link (opens split view by default) the href will also points // to explore but this way you can open it in new tab. - href: generateInternalHref(internalLink.datasourceName, interpolatedQuery, range, interpolatedPanelsState), + href: generateInternalHref(internalLink.datasourceUid, interpolatedQuery, range, interpolatedPanelsState), onClick: onClickFn ? () => { onClickFn({ @@ -71,7 +71,7 @@ export function mapInternalLinkToExplore(options: LinkToExploreOptions): LinkMod * Generates href for internal derived field link. */ function generateInternalHref( - datasourceName: string, + datasourceUid: string, query: T, range: TimeRange, panelsState?: ExplorePanelsState @@ -80,7 +80,7 @@ function generateInternalHref( `/explore?left=${encodeURIComponent( serializeStateToUrlParam({ range: range.raw, - datasource: datasourceName, + datasource: datasourceUid, queries: [query], panelsState: panelsState, }) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 747845587cb..34ded3050a7 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -146,7 +146,7 @@ class UnConnectedExploreToolbar extends PureComponent { @@ -233,7 +233,7 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps) => { return { datasourceMissing, - datasourceName: datasourceInstance?.name, + datasourceRef: datasourceInstance?.getRef(), datasourceType: datasourceInstance?.type, loading, range, diff --git a/public/app/features/explore/RichHistory/RichHistoryCard.tsx b/public/app/features/explore/RichHistory/RichHistoryCard.tsx index df3efab5bde..b9f8cf52258 100644 --- a/public/app/features/explore/RichHistory/RichHistoryCard.tsx +++ b/public/app/features/explore/RichHistory/RichHistoryCard.tsx @@ -164,21 +164,21 @@ export function RichHistoryCard(props: Props) { useEffect(() => { const getQueryDsInstance = async () => { - const ds = await getDataSourceSrv().get(query.datasourceName); + const ds = await getDataSourceSrv().get(query.datasourceUid); setQueryDsInstance(ds); }; getQueryDsInstance(); - }, [query.datasourceName]); + }, [query.datasourceUid]); const theme = useTheme(); const styles = getStyles(theme, isRemoved); const onRunQuery = async () => { const queriesToRun = query.queries; - const differentDataSource = query.datasourceName !== datasourceInstance?.name; + const differentDataSource = query.datasourceUid !== datasourceInstance?.uid; if (differentDataSource) { - await changeDatasource(exploreId, query.datasourceName, { importQueries: true }); + await changeDatasource(exploreId, query.datasourceUid, { importQueries: true }); setQueries(exploreId, queriesToRun); } else { setQueries(exploreId, queriesToRun); @@ -329,7 +329,7 @@ export function RichHistoryCard(props: Props) { {!activeUpdateComment && (
)} diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx index fb35ca34ea4..f0a14352681 100644 --- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx +++ b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx @@ -243,7 +243,7 @@ export function RichHistoryQueriesTab(props: Props) { {mappedQueriesToHeadings[heading].map((q: RichHistoryQuery) => { - const idx = listOfDatasources.findIndex((d) => d.name === q.datasourceName); + const idx = listOfDatasources.findIndex((d) => d.uid === q.datasourceUid); return ( Loading results...} {!loading && queries.map((q) => { - const idx = listOfDatasources.findIndex((d) => d.name === q.datasourceName); + const idx = listOfDatasources.findIndex((d) => d.uid === q.datasourceUid); return ( { beforeAll(() => { setDataSourceSrv({ getInstanceSettings(uid: string): DataSourceInstanceSettings | undefined { - return { uid: 'loki1', name: 'loki1', type: 'loki' } as any; + return { uid: 'loki1_uid', name: 'loki1', type: 'loki' } as any; }, } as any); @@ -40,7 +40,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -65,7 +65,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{ip=\\"192.168.0.1\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -90,7 +90,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{ip=\\"192.168.0.1\\", host=\\"host\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\", host=\\"host\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -116,7 +116,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:01:00.000Z","to":"2020-10-14T01:01:01.000Z"},"datasource":"loki1","queries":[{"expr":"{hostname=\\"hostname1\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:01:00.000Z","to":"2020-10-14T01:01:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{hostname=\\"hostname1\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -133,7 +133,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"} |=\\"7946b05c2e2e4e5a\\" |=\\"6605c7b08e715d6c\\"","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"} |=\\"7946b05c2e2e4e5a\\" |=\\"6605c7b08e715d6c\\"","refId":""}],"panelsState":{}}' )}` ); }); @@ -186,7 +186,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{service=\\"serviceName\\", pod=\\"podName\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service=\\"serviceName\\", pod=\\"podName\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -216,7 +216,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1","queries":[{"expr":"{service.name=\\"serviceName\\", pod=\\"podName\\"}","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service.name=\\"serviceName\\", pod=\\"podName\\"}","refId":""}],"panelsState":{}}' )}` ); }); @@ -263,8 +263,8 @@ describe('createSpanLinkFactory', () => { const linkDef = links?.logLinks?.[0]; expect(linkDef).toBeDefined(); - expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"Splunk 8","queries":[{"query"')}`); - expect(linkDef!.href).not.toContain(`${encodeURIComponent('datasource":"Splunk 8","queries":[{"expr"')}`); + expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"query"')}`); + expect(linkDef!.href).not.toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"expr"')}`); }); it('automatically timeshifts the timerange by one second in a splunk query', () => { @@ -297,7 +297,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"Splunk 8","queries":[{"query":"cluster=\\"cluster1\\" hostname=\\"hostname1\\" \\"7946b05c2e2e4e5a\\" \\"6605c7b08e715d6c\\"","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"cluster=\\"cluster1\\" hostname=\\"hostname1\\" \\"7946b05c2e2e4e5a\\" \\"6605c7b08e715d6c\\"","refId":""}],"panelsState":{}}' )}` ); }); @@ -320,7 +320,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"Splunk 8","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}],"panelsState":{}}' )}` ); }); @@ -346,7 +346,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"Splunk 8","queries":[{"query":"hostname=\\"hostname1\\" ip=\\"192.168.0.1\\"","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"hostname=\\"hostname1\\" ip=\\"192.168.0.1\\"","refId":""}],"panelsState":{}}' )}` ); }); @@ -376,7 +376,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"Splunk 8","queries":[{"query":"service=\\"serviceName\\" pod=\\"podName\\"","refId":""}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"service=\\"serviceName\\" pod=\\"podName\\"","refId":""}],"panelsState":{}}' )}` ); }); @@ -386,7 +386,7 @@ describe('createSpanLinkFactory', () => { beforeAll(() => { setDataSourceSrv({ getInstanceSettings(uid: string): DataSourceInstanceSettings | undefined { - return { uid: 'prom1', name: 'prom1', type: 'prometheus' } as any; + return { uid: 'prom1Uid', name: 'prom1', type: 'prometheus' } as any; }, } as any); @@ -399,7 +399,7 @@ describe('createSpanLinkFactory', () => { const createLink = createSpanLinkFactory({ splitOpenFn, traceToMetricsOptions: { - datasourceUid: 'prom1', + datasourceUid: 'prom1Uid', queries: [{ query: 'customQuery' }], }, }); @@ -411,7 +411,7 @@ describe('createSpanLinkFactory', () => { expect(linkDef).toBeDefined(); expect(linkDef!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1","queries":[{"expr":"customQuery","refId":"A"}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}],"panelsState":{}}' )}` ); }); @@ -435,7 +435,7 @@ describe('createSpanLinkFactory', () => { const createLink = createSpanLinkFactory({ splitOpenFn, traceToMetricsOptions: { - datasourceUid: 'prom1', + datasourceUid: 'prom1Uid', queries: [ { name: 'Named Query', query: 'customQuery' }, { name: 'defaultQuery', query: '' }, @@ -454,7 +454,7 @@ describe('createSpanLinkFactory', () => { expect(namedLink!.title).toBe('Named Query'); expect(namedLink!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1","queries":[{"expr":"customQuery","refId":"A"}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}],"panelsState":{}}' )}` ); @@ -463,7 +463,7 @@ describe('createSpanLinkFactory', () => { expect(defaultLink!.title).toBe('defaultQuery'); expect(defaultLink!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1","queries":[{"expr":"histogram_quantile(0.5, sum(rate(tempo_spanmetrics_latency_bucket{operation=\\"operation\\"}[5m])) by (le))","refId":"A"}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"histogram_quantile(0.5, sum(rate(tempo_spanmetrics_latency_bucket{operation=\\"operation\\"}[5m])) by (le))","refId":"A"}],"panelsState":{}}' )}` ); @@ -472,7 +472,7 @@ describe('createSpanLinkFactory', () => { expect(unnamedQuery!.title).toBeUndefined(); expect(unnamedQuery!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1","queries":[{"expr":"no_name_here","refId":"A"}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"no_name_here","refId":"A"}],"panelsState":{}}' )}` ); }); @@ -483,7 +483,7 @@ describe('createSpanLinkFactory', () => { const createLink = createSpanLinkFactory({ splitOpenFn, traceToMetricsOptions: { - datasourceUid: 'prom1', + datasourceUid: 'prom1Uid', queries: [{ name: 'Named Query', query: 'metric{$__tags}[5m]' }], tags: [ { key: 'job', value: '' }, @@ -507,7 +507,7 @@ describe('createSpanLinkFactory', () => { expect(links).toBeDefined(); expect(links!.metricLinks![0]!.href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1","queries":[{"expr":"metric{job=\\"tns/app\\", pod=\\"sample-pod\\"}[5m]","refId":"A"}],"panelsState":{}}' + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"metric{job=\\"tns/app\\", pod=\\"sample-pod\\"}[5m]","refId":"A"}],"panelsState":{}}' )}` ); }); diff --git a/public/app/features/explore/spec/helper/setup.tsx b/public/app/features/explore/spec/helper/setup.tsx index 89abe13e394..1e9566e9614 100644 --- a/public/app/features/explore/spec/helper/setup.tsx +++ b/public/app/features/explore/spec/helper/setup.tsx @@ -58,9 +58,14 @@ export function setupExplore(options?: SetupOptions): { getInstanceSettings(ref: DataSourceRef) { return dsSettings.map((d) => d.settings).find((x) => x.name === ref || x.uid === ref || x.uid === ref.uid); }, - get(name?: string | null, scopedVars?: ScopedVars): Promise { + get(datasource?: string | DataSourceRef | null, scopedVars?: ScopedVars): Promise { + const datasourceStr = typeof datasource === 'string'; return Promise.resolve( - (name ? dsSettings.find((d) => d.api.name === name || d.api.uid === name) : dsSettings[0])!.api + (datasource + ? dsSettings.find((d) => + datasourceStr ? d.api.name === datasource || d.api.uid === datasource : d.api.uid === datasource?.uid + ) + : dsSettings[0])!.api ); }, } as any); diff --git a/public/app/features/explore/state/datasource.ts b/public/app/features/explore/state/datasource.ts index a4564d0fe5b..d06e675ff2a 100644 --- a/public/app/features/explore/state/datasource.ts +++ b/public/app/features/explore/state/datasource.ts @@ -41,7 +41,7 @@ export function changeDatasource( ): ThunkResult { return async (dispatch, getState) => { const orgId = getState().user.orgId; - const { history, instance } = await loadAndInitDatasource(orgId, datasourceUid); + const { history, instance } = await loadAndInitDatasource(orgId, { uid: datasourceUid }); const currentDataSourceInstance = getState().explore[exploreId]!.datasourceInstance; dispatch( diff --git a/public/app/features/explore/state/explorePane.ts b/public/app/features/explore/state/explorePane.ts index 32a69ff9649..fc066dd1d07 100644 --- a/public/app/features/explore/state/explorePane.ts +++ b/public/app/features/explore/state/explorePane.ts @@ -11,6 +11,7 @@ import { DataSourceApi, ExplorePanelsState, PreferredVisualisationType, + DataSourceRef, } from '@grafana/data'; import { getDataSourceSrv } from '@grafana/runtime'; import { keybindingSrv } from 'app/core/services/keybindingSrv'; @@ -135,10 +136,14 @@ export function changeGraphStyle(exploreId: ExploreId, graphStyle: ExploreGraphS /** * Initialize Explore state with state from the URL and the React component. * Call this only on components for with the Explore state has not been initialized. + * + * The `datasource` param will be passed to the datasource service `get` function + * and can be either a string that is the name or uid, or a datasourceRef + * This is to maximize compatability with how datasources are accessed from the URL param. */ export function initializeExplore( exploreId: ExploreId, - datasourceNameOrUid: string, + datasource: DataSourceRef | string, queries: DataQuery[], range: TimeRange, containerWidth: number, @@ -152,7 +157,7 @@ export function initializeExplore( if (exploreDatasources.length >= 1) { const orgId = getState().user.orgId; - const loadResult = await loadAndInitDatasource(orgId, datasourceNameOrUid); + const loadResult = await loadAndInitDatasource(orgId, datasource); instance = loadResult.instance; history = loadResult.history; } @@ -201,6 +206,7 @@ export function refreshExplore(exploreId: ExploreId, newUrlQuery: string): Thunk const { containerWidth, eventBridge } = itemState; + // datasource will either be name or UID here const { datasource, queries, range: urlRange, panelsState } = newUrlState; const refreshQueries: DataQuery[] = []; diff --git a/public/app/features/explore/state/main.ts b/public/app/features/explore/state/main.ts index 2fcf82ad40d..f4fd3263110 100644 --- a/public/app/features/explore/state/main.ts +++ b/public/app/features/explore/state/main.ts @@ -2,7 +2,7 @@ import { createAction } from '@reduxjs/toolkit'; import { AnyAction } from 'redux'; import { ExploreUrlState, serializeStateToUrlParam, SplitOpen, UrlQueryMap } from '@grafana/data'; -import { DataSourceSrv, getDataSourceSrv, locationService } from '@grafana/runtime'; +import { DataSourceSrv, locationService } from '@grafana/runtime'; import { GetExploreUrlArguments, stopQueryState } from 'app/core/utils/explore'; import { PanelModel } from 'app/features/dashboard/state'; import { ExploreId, ExploreItemState, ExploreState } from 'app/types/explore'; @@ -108,9 +108,8 @@ export const splitOpen: SplitOpen = (options): ThunkResult => { let rightUrlState: ExploreUrlState = leftUrlState; if (options) { - const datasourceName = getDataSourceSrv().getInstanceSettings(options.datasourceUid)?.name || ''; rightUrlState = { - datasource: datasourceName, + datasource: options.datasourceUid, queries: [options.query], range: options.range || leftState.range, panelsState: options.panelsState, diff --git a/public/app/features/explore/state/utils.test.ts b/public/app/features/explore/state/utils.test.ts index c2834f792b3..f05c1a252f6 100644 --- a/public/app/features/explore/state/utils.test.ts +++ b/public/app/features/explore/state/utils.test.ts @@ -24,10 +24,10 @@ describe('loadAndInitDatasource', () => { dataSourceMock.get.mockRejectedValueOnce(new Error('Datasource not found')); dataSourceMock.get.mockResolvedValue(DEFAULT_DATASOURCE); - const { instance } = await loadAndInitDatasource(1, 'Unknown'); + const { instance } = await loadAndInitDatasource(1, { uid: 'Unknown' }); expect(dataSourceMock.get).toBeCalledTimes(2); - expect(dataSourceMock.get).toBeCalledWith('Unknown'); + expect(dataSourceMock.get).toBeCalledWith({ uid: 'Unknown' }); expect(dataSourceMock.get).toBeCalledWith(); expect(instance).toMatchObject(DEFAULT_DATASOURCE); expect(store.set).toBeCalledWith(lastUsedDatasourceKeyForOrgId(1), DEFAULT_DATASOURCE.uid); @@ -36,10 +36,10 @@ describe('loadAndInitDatasource', () => { it('saves last loaded data source uid', async () => { dataSourceMock.get.mockResolvedValue(TEST_DATASOURCE); - const { instance } = await loadAndInitDatasource(1, 'Test'); + const { instance } = await loadAndInitDatasource(1, { uid: 'Test' }); expect(dataSourceMock.get).toBeCalledTimes(1); - expect(dataSourceMock.get).toBeCalledWith('Test'); + expect(dataSourceMock.get).toBeCalledWith({ uid: 'Test' }); expect(instance).toMatchObject(TEST_DATASOURCE); expect(store.set).toBeCalledWith(lastUsedDatasourceKeyForOrgId(1), TEST_DATASOURCE.uid); }); diff --git a/public/app/features/explore/state/utils.ts b/public/app/features/explore/state/utils.ts index 13ba2788f50..5a28d9ed7ae 100644 --- a/public/app/features/explore/state/utils.ts +++ b/public/app/features/explore/state/utils.ts @@ -3,6 +3,7 @@ import { isEmpty, isObject, mapValues, omitBy } from 'lodash'; import { AbsoluteTimeRange, DataSourceApi, + DataSourceRef, EventBusExtended, ExploreUrlState, getDefaultTimeRange, @@ -86,11 +87,12 @@ export const createEmptyQueryResponse = (): ExplorePanelData => ({ export async function loadAndInitDatasource( orgId: number, - datasourceUid?: string + datasource: DataSourceRef | string ): Promise<{ history: HistoryItem[]; instance: DataSourceApi }> { let instance; try { - instance = await getDatasourceSrv().get(datasourceUid); + // let datasource be a ref if we have the info, otherwise a name or uid will do for lookup + instance = await getDatasourceSrv().get(datasource); } catch (error) { // Falling back to the default data source in case the provided data source was not found. // It may happen if last used data source or the data source provided in the URL has been @@ -129,7 +131,7 @@ export function getUrlStateFromPaneState(pane: ExploreItemState): ExploreUrlStat return { // datasourceInstance should not be undefined anymore here but in case there is some path for it to be undefined // lets just fallback instead of crashing. - datasource: pane.datasourceInstance?.name || '', + datasource: pane.datasourceInstance?.uid || '', queries: pane.queries.map(clearQueryKeys), range: toRawTimeRange(pane.range), // don't include panelsState in the url unless a piece of state is actually set diff --git a/public/app/features/explore/utils/links.test.ts b/public/app/features/explore/utils/links.test.ts index 29e35f9a32e..8207fa21988 100644 --- a/public/app/features/explore/utils/links.test.ts +++ b/public/app/features/explore/utils/links.test.ts @@ -73,7 +73,7 @@ describe('getFieldLinksForExplore', () => { expect(links[0].href).toBe( `/explore?left=${encodeURIComponent( - '{"range":{"from":"now-1h","to":"now"},"datasource":"test_ds","queries":[{"query":"query_1"}],"panelsState":{"trace":{"spanId":"abcdef"}}}' + '{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"query_1"}],"panelsState":{"trace":{"spanId":"abcdef"}}}' )}` ); expect(links[0].title).toBe('test_ds');