/usr/share/grafana/public/app/features/dashboard/api
import { Dashboard } from '@grafana/schema'; import { Spec as DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2'; import { isResource } from 'app/features/apiserver/guards'; import { Resource, ResourceList } from 'app/features/apiserver/types'; import { DashboardDataDTO, DashboardDTO } from 'app/types/dashboard'; import { SaveDashboardCommand } from '../components/SaveDashboard/types'; import { DashboardAPI, DashboardVersionError, DashboardWithAccessInfo, ListDeletedDashboardsOptions } from './types'; import { failedFromVersion, isDashboardV2Spec, isV1DashboardCommand, isV2DashboardCommand, isV2StoredVersion, } from './utils'; import { K8sDashboardAPI } from './v1'; import { K8sDashboardV2API } from './v2'; export class UnifiedDashboardAPI implements DashboardAPI<DashboardDTO | DashboardWithAccessInfo<DashboardV2Spec>, Dashboard | DashboardV2Spec> { private v1Client: K8sDashboardAPI; private v2Client: K8sDashboardV2API; constructor() { this.v1Client = new K8sDashboardAPI(); this.v2Client = new K8sDashboardV2API(); } // Get operation depends on the dashboard format to use one of the two clients async getDashboardDTO(uid: string) { try { return await this.v1Client.getDashboardDTO(uid); } catch (error) { if (error instanceof DashboardVersionError && isV2StoredVersion(error.data.storedVersion)) { return await this.v2Client.getDashboardDTO(uid); } throw error; } } // Save operation depends on the dashboard format to use one of the two clients async saveDashboard(options: SaveDashboardCommand<Dashboard | DashboardV2Spec>) { if (isV2DashboardCommand(options)) { return await this.v2Client.saveDashboard(options); } if (isV1DashboardCommand(options)) { return await this.v1Client.saveDashboard(options); } throw new Error('Invalid dashboard command'); } // Delete operation for any version is supported in the v1 client async deleteDashboard(uid: string, showSuccessAlert: boolean) { return await this.v1Client.deleteDashboard(uid, showSuccessAlert); } /** * List deleted dashboards handling mixed v1/v2 versions or pure v2 dashboards. * * Steps: * 1. Call v1 client to get all deleted dashboards * 2. Check if any items have failed conversion from v2 versions * 3. If v2 dashboards are detected, call v2 client * 4. Filter and combine v1 and v2 dashboards into one response */ async listDeletedDashboards( options: ListDeletedDashboardsOptions ): Promise<ResourceList<Dashboard | DashboardV2Spec>> { const v1Response = await this.v1Client.listDeletedDashboards(options); const filteredV1Items = v1Response.items.filter((item) => !failedFromVersion(item, ['v2'])); if (filteredV1Items.length === v1Response.items.length) { return v1Response; } const v2Response = await this.v2Client.listDeletedDashboards(options); const filteredV2Items = v2Response.items.filter((item) => !failedFromVersion(item, ['v0', 'v1'])); return { ...v2Response, // Make sure we display only valid resources items: [...filteredV1Items, ...filteredV2Items].filter(isResource), }; } async restoreDashboard(dashboard: Resource<DashboardDataDTO | DashboardV2Spec>) { // Await returned promise to support proper error handling with try/catch if (isDashboardV2Spec(dashboard.spec) && isResource<DashboardV2Spec>(dashboard)) { return await this.v2Client.restoreDashboard(dashboard); } if (isResource<DashboardDataDTO>(dashboard)) { return await this.v1Client.restoreDashboard(dashboard); } throw new Error('Invalid dashboard resource for restore operation'); } }
.
Edit
..
Edit
ResponseTransformers.test.ts
Edit
ResponseTransformers.ts
Edit
UnifiedDashboardAPI.test.ts
Edit
UnifiedDashboardAPI.ts
Edit
dashboard_api.test.ts
Edit
dashboard_api.ts
Edit
legacy.test.ts
Edit
legacy.ts
Edit
publicDashboardApi.ts
Edit
types.ts
Edit
utils.test.ts
Edit
utils.ts
Edit
v1.test.ts
Edit
v1.ts
Edit
v2.test.ts
Edit
v2.ts
Edit