From 49324a9ee2c247a30a5ef296f106596a957e6e7f Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Fri, 14 Mar 2025 14:50:34 +0200 Subject: [PATCH] Provisioning: Load dashboard (#102050) * Provisioning: Load dashboard * Add v2 loader --- .../dashboard/services/DashboardLoaderSrv.ts | 5 ++ .../features/provisioning/dashboardLoader.ts | 63 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 public/app/features/provisioning/dashboardLoader.ts diff --git a/public/app/features/dashboard/services/DashboardLoaderSrv.ts b/public/app/features/dashboard/services/DashboardLoaderSrv.ts index 313e667f271..6148b42a193 100644 --- a/public/app/features/dashboard/services/DashboardLoaderSrv.ts +++ b/public/app/features/dashboard/services/DashboardLoaderSrv.ts @@ -13,6 +13,7 @@ import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { DashboardDTO } from 'app/types'; import { appEvents } from '../../../core/core'; +import { loadDashboardFromProvisioning } from '../../provisioning/dashboardLoader'; import { ResponseTransformers } from '../api/ResponseTransformers'; import { getDashboardAPI } from '../api/dashboard_api'; import { DashboardVersionError, DashboardWithAccessInfo } from '../api/types'; @@ -123,6 +124,8 @@ export class DashboardLoaderSrv extends DashboardLoaderSrvBase { if (type === 'script' && slug) { promise = this.loadScriptedDashboard(slug); + } else if (type === 'provisioning' && uid && slug) { + promise = loadDashboardFromProvisioning(slug, uid); // needed for the old architecture // in scenes this is handled through loadSnapshot method } else if (type === 'snapshot' && slug) { @@ -197,6 +200,8 @@ export class DashboardLoaderSrvV2 extends DashboardLoaderSrvBase { return ResponseTransformers.ensureV2Response(result); }); + } else if (type === 'provisioning' && uid && slug) { + promise = loadDashboardFromProvisioning(slug, uid).then((r) => ResponseTransformers.ensureV2Response(r)); } else if (uid) { if (!params) { const cachedDashboard = stateManager.getDashboardFromCache(uid); diff --git a/public/app/features/provisioning/dashboardLoader.ts b/public/app/features/provisioning/dashboardLoader.ts new file mode 100644 index 00000000000..6614a966eba --- /dev/null +++ b/public/app/features/provisioning/dashboardLoader.ts @@ -0,0 +1,63 @@ +import { getBackendSrv } from '@grafana/runtime'; +import { DashboardDTO } from 'app/types'; + +import { AnnoKeyManagerIdentity, AnnoKeyManagerKind, AnnoKeySourcePath } from '../apiserver/types'; + +import { BASE_URL } from './api/baseAPI'; + +/** + * + * Load a dashboard from repository + */ +export async function loadDashboardFromProvisioning(repo: string, path: string): Promise { + const params = new URLSearchParams(window.location.search); + const ref = params.get('ref'); // commit hash or branch + + const url = `${BASE_URL}/repositories/${repo}/files/${path}`; + return getBackendSrv() + .get(url, ref ? { ref } : undefined) + .then((v) => { + // Load the results from dryRun + const dryRun = v.resource.dryRun; + if (!dryRun) { + return Promise.reject('failed to read provisioned dashboard'); + } + + if (!dryRun.apiVersion.startsWith('dashboard.grafana.app')) { + return Promise.reject('unexpected resource type: ' + dryRun.apiVersion); + } + + // Make sure the annotation key exists + let anno = dryRun.metadata.annotations; + if (!anno) { + dryRun.metadata.annotations = {}; + } + anno[AnnoKeyManagerKind] = 'repo'; + anno[AnnoKeyManagerIdentity] = repo; + anno[AnnoKeySourcePath] = ref ? path + '#' + ref : path; + + return { + meta: { + canStar: false, + isSnapshot: false, + canShare: false, + + // Should come from the repo settings + canDelete: true, + canSave: true, + canEdit: true, + + // Includes additional k8s metadata + k8s: dryRun.metadata, + + // lookup info + provisioning: { + file: url, + ref: ref, + repo: repo, + }, + }, + dashboard: dryRun.spec, + }; + }); +}