diff --git a/.betterer.results b/.betterer.results
index 1eb89909a65..4730a6d0a3b 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -3364,10 +3364,21 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
],
"public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx:5381": [
- [0, 0, 0, "No untranslated strings. Wrap text with ", "0"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "1"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "2"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "3"]
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"],
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"],
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "4"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "5"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "6"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "7"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "8"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "9"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "10"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "11"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "12"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "13"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "14"]
],
"public/app/features/dashboard-scene/saving/provisioned/ProvisionedResourceDeleteModal.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
@@ -3389,15 +3400,13 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "9"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "10"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "11"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "12"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "13"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "14"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "15"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "16"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "17"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "18"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "19"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "20"]
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "18"]
],
"public/app/features/dashboard-scene/saving/shared.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
diff --git a/pkg/registry/apis/provisioning/resources/client.go b/pkg/registry/apis/provisioning/resources/client.go
index 5143478f797..6dc252a99a6 100644
--- a/pkg/registry/apis/provisioning/resources/client.go
+++ b/pkg/registry/apis/provisioning/resources/client.go
@@ -54,7 +54,10 @@ func (c *ClientFactory) New(ns string) (*DynamicClient, KindsLookup, error) {
if err != nil {
return nil, nil, err
}
- config := c.configProvider.GetRestConfig(ctx)
+ config, err := c.configProvider.GetRestConfig(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
client, err := dynamic.NewForConfig(config)
if err != nil {
return nil, nil, err
diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
index 9f02500d65e..20686a31027 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
@@ -79,7 +79,7 @@ export function DashboardScenePage({ route, queryParams, location }: Props) {
return (
-
+
diff --git a/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
index 54dcdf61445..1b2de2b3fac 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
@@ -1,56 +1,80 @@
import { Alert, Icon, Stack } from '@grafana/ui';
import { DashboardPageRouteSearchParams } from 'app/features/dashboard/containers/types';
+import { useGetRepositoryFilesWithPathQuery, useGetRepositoryQuery } from 'app/features/provisioning/api';
+import { usePullRequestParam } from 'app/features/provisioning/hooks';
import { DashboardRoutes } from 'app/types';
interface DashboardPreviewBannerProps {
queryParams: DashboardPageRouteSearchParams;
route?: string;
+ slug?: string;
path?: string;
}
-export function DashboardPreviewBanner({ queryParams, route, path }: DashboardPreviewBannerProps) {
- const hasPrLink = Boolean(queryParams.prLink);
- const isProvisioned = Boolean(route === DashboardRoutes.Provisioning && path);
-
- if ('kiosk' in queryParams || (!queryParams.isPreview && !isProvisioned)) {
+export function DashboardPreviewBanner({ queryParams, route, slug, path }: DashboardPreviewBannerProps) {
+ if ('kiosk' in queryParams || !path || route !== DashboardRoutes.Provisioning || !slug) {
return null;
}
+ const prParam = usePullRequestParam(); // pull_request_url
+ const file = useGetRepositoryFilesWithPathQuery({ name: slug, path, ref: queryParams.ref });
- const title = getTitle({ isProvisioned, hasPR: hasPrLink });
- return (
- ;
+ }
+
+ console.log('BANNER', { queryParams, file: file.data, repo: repo.data });
+
+ // This page was loaded with a `pull_request_url` in the URL
+ // This is typically from an external link in a rendered pull request
+ if (prParam?.length) {
+ return (
+
- {isProvisioned ? 'View' : 'Open'} pull request in GitHub
+ View pull request in GitHub
- )
- }
- onRemove={hasPrLink ? () => window.open(queryParams.prLink, '_blank') : undefined}
- >
- {isProvisioned ? (
- <>
- The value is not saved in the grafana database.
- >
- ) : null}
+ }
+ onRemove={() => window.open(prParam, '_blank')}
+ >
+ The value is not yet saved in the grafana database
+
+ );
+ }
+
+ // Check if this is a github link
+ if (queryParams.ref?.length && repo.data?.spec?.type === 'github') {
+ const spec = repo.data?.spec.github!;
+ const url = `${spec.url}/compare/${spec.branch}...${queryParams.ref}?quick_pull=1&labels=grafana`;
+
+ return (
+
+ Open pull request in GitHub
+
+
+ }
+ onRemove={() => window.open(url, '_blank')}
+ >
+ The value is not yet saved in the grafana database
+
+ );
+ }
+
+ return (
+
+ The value is not saved in the grafana database
);
}
-
-type Opts = {
- isProvisioned?: boolean;
- hasPR: boolean;
-};
-function getTitle({ isProvisioned, hasPR }: Opts) {
- if (isProvisioned) {
- return 'This dashboard is loaded from an external repository';
- }
- if (hasPR) {
- return "This dashboard is a draft. The changes aren't live yet. You can review them in GitHub.";
- }
- return 'This dashboard is a draft. The changes aren’t live yet. Submit a pull request for review.';
-}
diff --git a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
index 298ea7125d0..7115744096d 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboard.tsx
@@ -1,16 +1,19 @@
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
+import { useNavigate } from 'react-router-dom-v5-compat';
import { AppEvents } from '@grafana/data';
import { getAppEvents, locationService } from '@grafana/runtime';
-import { Alert, Button, Field, Input, RadioButtonGroup, Stack, TextArea, TextLink } from '@grafana/ui';
+import { Alert, Button, Field, Input, RadioButtonGroup, Stack, TextArea } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
+import { useUrlParams } from 'app/core/navigation/hooks';
import { AnnoKeyRepoName } from 'app/features/apiserver/types';
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
import { RepositoryView } from 'app/features/provisioning/api';
-import { useCreateOrUpdateRepositoryFile, usePullRequestParam } from 'app/features/provisioning/hooks';
+import { PROVISIONING_URL } from 'app/features/provisioning/constants';
+import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks';
import { WorkflowOption } from 'app/features/provisioning/types';
-import { createPRLink, validateBranchName } from 'app/features/provisioning/utils/git';
+import { validateBranchName } from 'app/features/provisioning/utils/git';
import { DashboardScene } from '../../scene/DashboardScene';
import { SaveDashboardDrawer } from '../SaveDashboardDrawer';
@@ -42,7 +45,8 @@ export interface Props {
export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Props) {
const { meta, title: defaultTitle, description: defaultDescription } = dashboard.useState();
- const prURL = usePullRequestParam();
+ const navigate = useNavigate();
+ const [params] = useUrlParams();
const {
values: defaultValues,
@@ -59,9 +63,9 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop
control,
setValue,
} = useForm({ defaultValues });
- const [title, ref, workflow, comment] = watch(['title', 'ref', 'workflow', 'comment']);
+
+ const [ref, workflow, path] = watch(['ref', 'workflow', 'path']);
const { isDirty } = dashboard.state;
- const href = createPRLink(repositoryConfig, title, ref, comment);
useEffect(() => {
const appEvents = getAppEvents();
@@ -70,21 +74,34 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop
if (isNew) {
dashboard.setRepoName(defaultValues.repo);
}
- const prLink = workflow !== 'write' ? href : undefined;
- dashboard.closeModal();
- locationService.partial({
- viewPanel: null,
- editPanel: null,
- isPreview: true,
- prLink,
- });
+ if (workflow === 'branch' && ref !== '' && path !== '') {
+ // Redirect to the provisioning preview pages
+ navigate(`${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}?ref=${ref}`);
+ } else {
+ dashboard.closeModal();
+ locationService.partial({
+ viewPanel: null,
+ editPanel: null,
+ });
+ }
} else if (request.isError) {
appEvents.publish({
type: AppEvents.alertError.name,
payload: ['Error saving dashboard', request.error],
});
}
- }, [request.isSuccess, request.isError, request.error, dashboard, workflow, href, isNew, defaultValues.repo]);
+ }, [
+ request.isSuccess,
+ request.isError,
+ request.error,
+ dashboard,
+ workflow,
+ isNew,
+ defaultValues.repo,
+ ref,
+ path,
+ navigate,
+ ]);
useEffect(() => {
setValue('workflow', getDefaultWorkflow(repositoryConfig));
@@ -103,12 +120,14 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop
});
if (workflow === 'write') {
- ref = undefined;
+ ref = params.get('ref') ?? undefined; // the original ref from URL or undefined
}
action({ ref, name: repo, path, message: comment, body: saveModel });
};
+ const workflows = getWorkflowOptions(repositoryConfig, ref);
+
return (