diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
index 83e72d3b1ca..3303244cb22 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
@@ -14,6 +14,7 @@ import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from 'app/fe
import { DashboardRoutes } from 'app/types';
import { DashboardPrompt } from '../saving/DashboardPrompt';
+import { DashboardPreviewBanner } from '../saving/provisioned/DashboardPreviewBanner';
import { getDashboardScenePageStateManager } from './DashboardScenePageStateManager';
@@ -76,6 +77,7 @@ export function DashboardScenePage({ route, queryParams, location }: Props) {
return (
+
diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
index 2bd41da5e4f..ddb7496795e 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
@@ -61,8 +61,8 @@ interface DashboardCacheEntry {
export interface LoadDashboardOptions {
uid: string;
route: DashboardRoutes;
- type?: string;
slug?: string;
+ type?: string;
urlFolderUid?: string;
params?: {
version: number;
diff --git a/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
new file mode 100644
index 00000000000..f96bcbfd1b4
--- /dev/null
+++ b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
@@ -0,0 +1,119 @@
+import { config } from '@grafana/runtime';
+import { Alert, Icon, Stack } from '@grafana/ui';
+import { useGetRepositoryFilesWithPathQuery } from 'app/api/clients/provisioning';
+import { t, Trans } from 'app/core/internationalization';
+import { DashboardPageRouteSearchParams } from 'app/features/dashboard/containers/types';
+import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
+import { DashboardRoutes } from 'app/types';
+
+interface CommonBannerProps {
+ queryParams: DashboardPageRouteSearchParams;
+ path?: string;
+ slug?: string;
+}
+
+interface DashboardPreviewBannerProps extends CommonBannerProps {
+ route?: string;
+}
+
+interface DashboardPreviewBannerContentProps extends Required> {}
+
+const commonAlertProps = {
+ severity: 'info' as const,
+ style: { flex: 0 } as const,
+};
+
+function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPreviewBannerContentProps) {
+ const prParam = usePullRequestParam();
+ const file = useGetRepositoryFilesWithPathQuery({ name: slug, path, ref: queryParams.ref });
+
+ if (file.data?.errors) {
+ return (
+
+ {file.data.errors.map((error, index) => (
+ {error}
+ ))}
+
+ );
+ }
+
+ // This page was loaded with a `pull_request_url` in the URL
+ if (prParam?.length) {
+ return (
+
+
+ View pull request in GitHub
+
+
+
+ }
+ onRemove={() => window.open(prParam, '_blank')}
+ >
+
+ The value is not yet saved in the Grafana database
+
+
+ );
+ }
+
+ // Check if this is a GitHub link
+ const githubURL = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL;
+ if (githubURL) {
+ return (
+
+
+ Open pull request in GitHub
+
+
+
+ }
+ onRemove={() => window.open(githubURL, '_blank')}
+ >
+
+ The value is not yet saved in the Grafana database
+
+
+ );
+ }
+
+ return (
+
+
+ The value is not saved in the Grafana database
+
+
+ );
+}
+
+export function DashboardPreviewBanner({ queryParams, route, slug, path }: DashboardPreviewBannerProps) {
+ const provisioningEnabled = config.featureToggles.provisioning;
+ if (!provisioningEnabled || 'kiosk' in queryParams || !path || route !== DashboardRoutes.Provisioning || !slug) {
+ return null;
+ }
+
+ return ;
+}
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 910818911ef..9e12bd9e2c1 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -1438,6 +1438,17 @@
"it-cannot-contain-or": "It cannot contain '//' or '..'.",
"least-valid-character": "It must have at least one valid character."
},
+ "dashboard-preview-banner": {
+ "not-saved": "The value is not yet saved in the Grafana database",
+ "not-yet-saved": "The value is not saved in the Grafana database",
+ "open-pull-request-in-git-hub": "Open pull request in GitHub",
+ "title-dashboard-loaded-branch-git-hub": "This dashboard is loaded from a branch in GitHub.",
+ "title-dashboard-loaded-external-repository": "This dashboard is loaded from an external repository",
+ "title-dashboard-loaded-request-git-hub": "This dashboard is loaded from a pull request in GitHub.",
+ "title-error-loading-dashboard": "Error loading dashboard",
+ "value-not-saved": "The value is not yet saved in the Grafana database",
+ "view-pull-request-in-git-hub": "View pull request in GitHub"
+ },
"provisioned-resource-delete-modal": {
"file-path": "File path:",
"managed-by-version-control": "This {type} is managed by version control and cannot be deleted. To remove it, delete it from the repository and synchronise to apply the changes.",