diff --git a/public/app/features/browse-dashboards/components/BulkActions/BulkDeleteProvisionedResource.tsx b/public/app/features/browse-dashboards/components/BulkActions/BulkDeleteProvisionedResource.tsx
index 77730c5320c..d5fd35ff1bd 100644
--- a/public/app/features/browse-dashboards/components/BulkActions/BulkDeleteProvisionedResource.tsx
+++ b/public/app/features/browse-dashboards/components/BulkActions/BulkDeleteProvisionedResource.tsx
@@ -15,6 +15,7 @@ import { AnnoKeySourcePath } from 'app/features/apiserver/types';
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
import { getDefaultWorkflow, getWorkflowOptions } from 'app/features/dashboard-scene/saving/provisioned/defaults';
import { generateTimestamp } from 'app/features/dashboard-scene/saving/provisioned/utils/timestamp';
+import { buildResourceBranchRedirectUrl } from 'app/features/dashboard-scene/settings/utils';
import { useGetResourceRepositoryView } from 'app/features/provisioning/hooks/useGetResourceRepositoryView';
import { WorkflowOption } from 'app/features/provisioning/types';
import { useSelector } from 'app/types/store';
@@ -89,7 +90,13 @@ function FormContent({ initialValues, selectedItems, repository, workflowOptions
if (workflow === 'branch') {
onDismiss?.();
if (successState.repoUrl) {
- navigate({ search: `?repo_url=${encodeURIComponent(successState.repoUrl)}` });
+ const url = buildResourceBranchRedirectUrl({
+ paramName: 'repo_url',
+ paramValue: successState.repoUrl,
+ repoType: repository.type,
+ });
+
+ navigate(url);
return;
}
window.location.reload();
diff --git a/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.test.tsx b/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.test.tsx
index 7bd6c28587a..00687677e94 100644
--- a/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.test.tsx
+++ b/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.test.tsx
@@ -297,9 +297,11 @@ describe('DeleteProvisionedFolderForm', () => {
const { mockNavigate } = setup({}, { ...defaultHookData, initialValues: branchFormData }, successState);
await waitFor(() => {
- expect(mockNavigate).toHaveBeenCalledWith(
- '/dashboards?new_pull_request_url=https://github.com/test/repo/pull/new'
- );
+ const expectedParams = new URLSearchParams();
+ expectedParams.set('new_pull_request_url', 'https://github.com/test/repo/pull/new');
+ const expectedUrl = `/dashboards?${expectedParams.toString()}`;
+
+ expect(mockNavigate).toHaveBeenCalledWith(expectedUrl);
});
});
});
diff --git a/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.tsx b/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.tsx
index ccf09a2f7c7..70638377a3a 100644
--- a/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.tsx
+++ b/public/app/features/browse-dashboards/components/DeleteProvisionedFolderForm.tsx
@@ -11,6 +11,7 @@ import { RepositoryView, useDeleteRepositoryFilesWithPathMutation } from 'app/ap
import { AnnoKeySourcePath } from 'app/features/apiserver/types';
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
+import { buildResourceBranchRedirectUrl } from 'app/features/dashboard-scene/settings/utils';
import { FolderDTO } from 'app/types/folders';
import { useProvisionedFolderFormData } from '../hooks/useProvisionedFolderFormData';
@@ -61,7 +62,12 @@ function FormContent({ initialValues, parentFolder, repository, workflowOptions,
if (request.isSuccess && repository) {
const prUrl = request.data?.urls?.newPullRequestURL;
if (workflow === 'branch' && prUrl) {
- navigate(`/dashboards?new_pull_request_url=${prUrl}`);
+ const url = buildResourceBranchRedirectUrl({
+ paramName: 'new_pull_request_url',
+ paramValue: prUrl,
+ repoType: request.data?.repository?.type,
+ });
+ navigate(url);
return;
}
diff --git a/public/app/features/browse-dashboards/components/NewProvisionedFolderForm.tsx b/public/app/features/browse-dashboards/components/NewProvisionedFolderForm.tsx
index 9e35078c946..a453490e07c 100644
--- a/public/app/features/browse-dashboards/components/NewProvisionedFolderForm.tsx
+++ b/public/app/features/browse-dashboards/components/NewProvisionedFolderForm.tsx
@@ -12,6 +12,7 @@ import { RepositoryView, useCreateRepositoryFilesWithPathMutation } from 'app/ap
import { AnnoKeySourcePath, Resource } from 'app/features/apiserver/types';
import { ResourceEditFormSharedFields } from 'app/features/dashboard-scene/components/Provisioned/ResourceEditFormSharedFields';
import { BaseProvisionedFormData } from 'app/features/dashboard-scene/saving/shared';
+import { buildResourceBranchRedirectUrl } from 'app/features/dashboard-scene/settings/utils';
import { PROVISIONING_URL } from 'app/features/provisioning/constants';
import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
import { FolderDTO } from 'app/types/folders';
@@ -61,6 +62,17 @@ function FormContent({ initialValues, repository, workflowOptions, folder, onDis
],
});
+ const prUrl = request.data?.urls?.newPullRequestURL;
+ if (workflow === 'branch' && prUrl) {
+ const url = buildResourceBranchRedirectUrl({
+ paramName: 'new_pull_request_url',
+ paramValue: prUrl,
+ repoType: request.data?.repository?.type,
+ });
+ navigate(url);
+ return;
+ }
+
// TODO: Update when the upsert type is fixed
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const folder = request.data.resource?.upsert as Resource;
diff --git a/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
index f44552cbd69..2c23481b5eb 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/DashboardPreviewBanner.tsx
@@ -48,10 +48,10 @@ function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPre
return ;
}
- // Check if this is a GitHub link
- const githubURL = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL;
- if (githubURL) {
- return ;
+ // Check if this is a repo link
+ const repoUrl = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL;
+ if (repoUrl) {
+ return ;
}
return (
diff --git a/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.test.tsx b/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.test.tsx
index 94964f8004a..b742368dbce 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.test.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.test.tsx
@@ -2,8 +2,10 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { textUtil } from '@grafana/data';
+import { RepoType } from 'app/features/provisioning/Wizard/types';
+import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
-import { PreviewBannerViewPR } from './PreviewBannerViewPR';
+import { isValidRepoType, PreviewBannerViewPR } from './PreviewBannerViewPR';
jest.mock('@grafana/data', () => ({
...jest.requireActual('@grafana/data'),
@@ -12,23 +14,33 @@ jest.mock('@grafana/data', () => ({
},
}));
-jest.mock('@grafana/i18n', () => ({
- t: jest.fn((key: string, defaultValue: string) => defaultValue),
- Trans: ({ children }: { children: React.ReactNode }) => children,
+jest.mock('app/features/provisioning/hooks/usePullRequestParam', () => ({
+ usePullRequestParam: jest.fn(),
}));
const mockTextUtil = jest.mocked(textUtil);
-function setup(props: { prParam: string; isFolder?: boolean; isNewPr?: boolean } = { prParam: 'test-url' }) {
- const defaultProps = {
- isFolder: false,
- isNewPr: false,
- ...props,
+const mockUsePullRequestParam = jest.mocked(usePullRequestParam);
+
+function setup(
+ options: { prParam: string; isNewPr?: boolean; repoType?: RepoType } = { prParam: 'test-url', repoType: 'github' }
+) {
+ const componentProps = {
+ prParam: options.prParam,
+ isNewPr: options.isNewPr || false,
};
- const renderResult = render();
+ // Mock the hook BEFORE rendering the component
+ mockUsePullRequestParam.mockReturnValue({
+ prURL: undefined,
+ newPrURL: undefined,
+ repoURL: undefined,
+ repoType: options.repoType || 'github',
+ });
- return { renderResult, props: defaultProps };
+ const renderResult = render();
+
+ return { renderResult, props: componentProps };
}
describe('PreviewBannerViewPR', () => {
@@ -57,55 +69,63 @@ describe('PreviewBannerViewPR', () => {
describe('Dashboard scenarios', () => {
it('should render correct text for new PR dashboard', () => {
- setup({ prParam: 'test-url', isFolder: false, isNewPr: true });
+ setup({ prParam: 'test-url', isNewPr: true });
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByText('A new resource has been created in a branch in GitHub.')).toBeInTheDocument();
});
it('should render correct text for existing PR dashboard', () => {
- setup({ prParam: 'test-url', isFolder: false, isNewPr: false });
+ setup({ prParam: 'test-url', isNewPr: false });
expect(screen.getByRole('status')).toBeInTheDocument();
- expect(screen.getByText('This resource is loaded from a pull request in GitHub.')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'The rest of Grafana users in your organization will still see the current version saved to configured default branch until this branch is merged'
+ )
+ ).toBeInTheDocument();
});
it('should render correct button text for new PR dashboard', () => {
- setup({ prParam: 'test-url', isFolder: false, isNewPr: true });
+ setup({ prParam: 'test-url', isNewPr: true });
expect(screen.getByText('Open pull request in GitHub')).toBeInTheDocument();
});
it('should render correct button text for existing PR dashboard', () => {
- setup({ prParam: 'test-url', isFolder: false, isNewPr: false });
+ setup({ prParam: 'test-url', isNewPr: false });
expect(screen.getByText('View pull request in GitHub')).toBeInTheDocument();
});
});
- describe('Folder scenarios', () => {
- it('should render correct text for new PR folder', () => {
- setup({ prParam: 'test-url', isFolder: true, isNewPr: true });
+ describe('Additional scenarios', () => {
+ it('should render correct text for new PR resource', () => {
+ setup({ prParam: 'test-url', isNewPr: true });
expect(screen.getByRole('status')).toBeInTheDocument();
expect(screen.getByText('A new resource has been created in a branch in GitHub.')).toBeInTheDocument();
});
- it('should render correct text for existing PR folder', () => {
- setup({ prParam: 'test-url', isFolder: true, isNewPr: false });
+ it('should render correct text for existing PR resource', () => {
+ setup({ prParam: 'test-url', isNewPr: false });
expect(screen.getByRole('status')).toBeInTheDocument();
- expect(screen.getByText('This resource is loaded from a pull request in GitHub.')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'This resource is loaded from the branch you just created in GitHub and it is only visible to you'
+ )
+ ).toBeInTheDocument();
});
- it('should render correct button text for new PR folder', () => {
- setup({ prParam: 'test-url', isFolder: true, isNewPr: true });
+ it('should render correct button text for new PR resource', () => {
+ setup({ prParam: 'test-url', isNewPr: true });
expect(screen.getByText('Open pull request in GitHub')).toBeInTheDocument();
});
- it('should render correct button text for existing PR folder', () => {
- setup({ prParam: 'test-url', isFolder: true, isNewPr: false });
+ it('should render correct button text for existing PR resource', () => {
+ setup({ prParam: 'test-url', isNewPr: false });
expect(screen.getByText('View pull request in GitHub')).toBeInTheDocument();
});
@@ -113,7 +133,7 @@ describe('PreviewBannerViewPR', () => {
describe('Button functionality', () => {
it('should open URL in new tab when button is clicked', async () => {
- const testUrl = 'https://github.com/test/repo/pull/123';
+ const testUrl = 'https://GitHub.com/test/repo/pull/123';
setup({ prParam: testUrl });
const button = screen.getByRole('button', { name: /close alert/i });
@@ -122,4 +142,46 @@ describe('PreviewBannerViewPR', () => {
expect(windowOpenSpy).toHaveBeenCalledWith(testUrl, '_blank');
});
});
+
+ describe('Different repository types', () => {
+ it('should handle GitLab repository type', () => {
+ setup({ prParam: 'test-url', isNewPr: false, repoType: 'gitlab' });
+
+ expect(screen.getByRole('status')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'This resource is loaded from the branch you just created in GitLab and it is only visible to you'
+ )
+ ).toBeInTheDocument();
+ });
+
+ it('should handle Bitbucket repository type', () => {
+ setup({ prParam: 'test-url', isNewPr: false, repoType: 'bitbucket' });
+
+ expect(screen.getByRole('status')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'This resource is loaded from the branch you just created in Bitbucket and it is only visible to you'
+ )
+ ).toBeInTheDocument();
+ });
+ });
+});
+
+describe('isValidRepoType', () => {
+ it('should return true for valid repo types', () => {
+ expect(isValidRepoType('github')).toBe(true);
+ expect(isValidRepoType('gitlab')).toBe(true);
+ expect(isValidRepoType('bitbucket')).toBe(true);
+ expect(isValidRepoType('git')).toBe(true);
+ });
+
+ it('should return false for invalid repo types', () => {
+ expect(isValidRepoType('unknown')).toBe(false);
+ expect(isValidRepoType('apple')).toBe(false);
+ expect(isValidRepoType('')).toBe(false);
+ expect(isValidRepoType(undefined)).toBe(false);
+ // @ts-expect-error testing invalid type
+ expect(isValidRepoType(null)).toBe(false);
+ });
});
diff --git a/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.tsx b/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.tsx
index 54eef1b265b..da711f084ca 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/PreviewBannerViewPR.tsx
@@ -1,6 +1,8 @@
import { textUtil } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { Alert, Icon, Stack } from '@grafana/ui';
+import { RepoTypeDisplay, RepoType } from 'app/features/provisioning/Wizard/types';
+import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam';
import { commonAlertProps } from './DashboardPreviewBanner';
@@ -14,17 +16,27 @@ interface Props {
}
/**
- * @description This component is used to display a banner when a provisioned dashboard/folder is created or loaded from a new branch in Github.
+ * @description This component is used to display a banner when a provisioned dashboard/folder is created or loaded from a new branch in repo.
*/
export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }: Props) {
+ const { repoType } = usePullRequestParam();
+
+ const capitalizedRepoType = isValidRepoType(repoType) ? RepoTypeDisplay[repoType] : 'repository';
+
const titleText = isNewPr
? t(
- 'provisioned-resource-preview-banner.title-created-branch-git-hub',
- 'A new resource has been created in a branch in GitHub.'
+ 'provisioned-resource-preview-banner.title-created-branch-in-repo',
+ 'A new resource has been created in a branch in {{repoType}}.',
+ {
+ repoType: capitalizedRepoType,
+ }
)
: t(
- 'provisioned-resource-preview-banner.title-loaded-pull-request-git-hub',
- 'This resource is loaded from a pull request in GitHub.'
+ 'provisioned-resource-preview-banner.title-loaded-pull-request-in-repo',
+ 'This resource is loaded from the branch you just created in {{repoType}} and it is only visible to you',
+ {
+ repoType: capitalizedRepoType,
+ }
);
if (behindBranch) {
@@ -33,18 +45,26 @@ export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }:
{...commonAlertProps}
buttonContent={
- {t('provisioned-resource-preview-banner.preview-banner.open-git-hub', 'Open in Github')}
+ {t('provisioned-resource-preview-banner.preview-banner.open-in-repo-button', 'Open in {{repoType}}', {
+ repoType: capitalizedRepoType,
+ })}
}
title={t(
- 'provisioned-resource-preview-banner.preview-banner.behind-branch',
- 'This resource is behind the branch in GitHub.'
+ 'provisioned-resource-preview-banner.preview-banner.behind-branch-text',
+ 'This resource is behind the branch in {{repoType}}.',
+ {
+ repoType: capitalizedRepoType,
+ }
)}
onRemove={repoUrl ? () => window.open(textUtil.sanitizeUrl(repoUrl), '_blank') : undefined}
>
-
- View it in GitHub to see the latest changes.
+
+ View it in {{ repoType }} to see the latest changes.
);
@@ -58,12 +78,14 @@ export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }:
{isNewPr
? t(
- 'provisioned-resource-preview-banner.preview-banner.open-pull-request-in-git-hub',
- 'Open pull request in GitHub'
+ 'provisioned-resource-preview-banner.preview-banner.open-pull-request-in-repo',
+ 'Open pull request in {{repoType}}',
+ { repoType: capitalizedRepoType }
)
: t(
- 'provisioned-resource-preview-banner.preview-banner.view-pull-request-in-git-hub',
- 'View pull request in GitHub'
+ 'provisioned-resource-preview-banner.preview-banner.view-pull-request-in-repo',
+ 'View pull request in {{repoType}}',
+ { repoType: capitalizedRepoType }
)}
@@ -71,8 +93,16 @@ export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }:
onRemove={prParam ? () => window.open(textUtil.sanitizeUrl(prParam), '_blank') : undefined}
>
- The value is not yet saved in the Grafana database
+ The rest of Grafana users in your organization will still see the current version saved to configured default
+ branch until this branch is merged
);
}
+
+export function isValidRepoType(repoType: string | undefined): repoType is RepoType {
+ if (typeof repoType !== 'string') {
+ return false;
+ }
+ return repoType in RepoTypeDisplay;
+}
diff --git a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboardForm.tsx b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboardForm.tsx
index e20e4c811b0..4387af82439 100644
--- a/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard-scene/saving/provisioned/SaveProvisionedDashboardForm.tsx
@@ -16,6 +16,7 @@ import { PROVISIONING_URL } from 'app/features/provisioning/constants';
import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile';
import { ResourceEditFormSharedFields } from '../../components/Provisioned/ResourceEditFormSharedFields';
+import { buildResourceBranchRedirectUrl } from '../../settings/utils';
import { getDashboardUrl } from '../../utils/getDashboardUrl';
import { useProvisionedRequestHandler } from '../../utils/useProvisionedRequestHandler';
import { SaveDashboardFormCommonOptions } from '../SaveDashboardForm';
@@ -92,7 +93,14 @@ export function SaveProvisionedDashboardForm({
const onBranchSuccess = (ref: string, path: string) => {
panelEditor?.onDiscard();
drawer.onClose();
- navigate(`${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}?ref=${ref}`);
+
+ const url = buildResourceBranchRedirectUrl({
+ baseUrl: `${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}`,
+ paramName: 'ref',
+ paramValue: ref,
+ repoType: request.data?.repository?.type,
+ });
+ navigate(url);
};
useProvisionedRequestHandler({
diff --git a/public/app/features/dashboard-scene/settings/DeleteProvisionedDashboardForm.tsx b/public/app/features/dashboard-scene/settings/DeleteProvisionedDashboardForm.tsx
index d7b62a5cf22..53bb342cd21 100644
--- a/public/app/features/dashboard-scene/settings/DeleteProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard-scene/settings/DeleteProvisionedDashboardForm.tsx
@@ -13,6 +13,8 @@ import { ProvisionedDashboardFormData } from '../saving/shared';
import { DashboardScene } from '../scene/DashboardScene';
import { useProvisionedRequestHandler } from '../utils/useProvisionedRequestHandler';
+import { buildResourceBranchRedirectUrl } from './utils';
+
export interface Props {
dashboard: DashboardScene;
defaultValues: ProvisionedDashboardFormData;
@@ -82,9 +84,13 @@ export function DeleteProvisionedDashboardForm({
const onBranchSuccess = (path: string, urls?: Record) => {
panelEditor?.onDiscard();
onDismiss();
- navigate(
- `${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}?pull_request_url=${urls?.newPullRequestURL}`
- );
+ const url = buildResourceBranchRedirectUrl({
+ baseUrl: `${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}`,
+ paramName: 'pull_request_url',
+ paramValue: urls?.newPullRequestURL,
+ repoType: request.data?.repository?.type,
+ });
+ navigate(url);
};
useProvisionedRequestHandler({
diff --git a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx
index 2c52d7ddb9a..30600a0e6df 100644
--- a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx
@@ -27,6 +27,13 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => ({
useGetRepositoryFilesWithPathQuery: jest.fn(),
useCreateRepositoryFilesWithPathMutation: jest.fn(),
useDeleteRepositoryFilesWithPathMutation: jest.fn(),
+ provisioningAPIv0alpha1: {
+ endpoints: {
+ listRepository: {
+ select: jest.fn(() => () => ({ data: { items: [] } })),
+ },
+ },
+ },
}));
jest.mock('app/api/clients/folder/v1beta1', () => ({
diff --git a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx
index 94951c10f46..a9e62edc3db 100644
--- a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx
@@ -20,6 +20,8 @@ import { ProvisionedDashboardFormData } from '../saving/shared';
import { DashboardScene } from '../scene/DashboardScene';
import { useProvisionedRequestHandler } from '../utils/useProvisionedRequestHandler';
+import { buildResourceBranchRedirectUrl } from './utils';
+
export interface Props {
dashboard: DashboardScene;
defaultValues: ProvisionedDashboardFormData;
@@ -144,7 +146,12 @@ export function MoveProvisionedDashboardForm({
const onBranchSuccess = () => {
panelEditor?.onDiscard();
- navigate(`/dashboards?new_pull_request_url=${createRequest.data?.urls?.newPullRequestURL}`);
+ const url = buildResourceBranchRedirectUrl({
+ paramName: 'new_pull_request_url',
+ paramValue: createRequest?.data?.urls?.newPullRequestURL,
+ repoType: createRequest?.data?.repository?.type,
+ });
+ navigate(url);
};
useProvisionedRequestHandler({
diff --git a/public/app/features/dashboard-scene/settings/utils.ts b/public/app/features/dashboard-scene/settings/utils.ts
index 88011f08b00..741830b8ec5 100644
--- a/public/app/features/dashboard-scene/settings/utils.ts
+++ b/public/app/features/dashboard-scene/settings/utils.ts
@@ -111,3 +111,30 @@ export function createDashboardEditViewFor(editview: string): DashboardEditView
return new GeneralSettingsEditView({});
}
}
+
+export type ResourceBranchUrlOptions = {
+ baseUrl?: string;
+ paramName?: string;
+ paramValue?: string;
+ repoType?: string;
+};
+
+export function buildResourceBranchRedirectUrl({
+ baseUrl = '/dashboards',
+ paramName,
+ paramValue,
+ repoType,
+}: ResourceBranchUrlOptions): string {
+ const params = new URLSearchParams();
+
+ if (paramName && paramValue) {
+ params.set(paramName, paramValue);
+ }
+
+ if (repoType) {
+ params.set('repo_type', repoType);
+ }
+
+ const queryString = params.toString();
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
+}
diff --git a/public/app/features/provisioning/Wizard/types.ts b/public/app/features/provisioning/Wizard/types.ts
index fd9fcd00f1c..18c9fe36149 100644
--- a/public/app/features/provisioning/Wizard/types.ts
+++ b/public/app/features/provisioning/Wizard/types.ts
@@ -26,6 +26,16 @@ export interface ModeOption {
subtitle: string;
}
+export type StepStatus = 'idle' | 'running' | 'error' | 'success';
+
+export const RepoTypeDisplay: { [key in RepoType]: string } = {
+ github: 'GitHub',
+ gitlab: 'GitLab',
+ bitbucket: 'Bitbucket',
+ git: 'Git',
+ local: 'Local',
+};
+
export type StepStatusInfo =
| { status: 'idle' | 'running' | 'success' }
| { status: 'error'; error: string | ProvisioningErrorInfo }
diff --git a/public/app/features/provisioning/hooks/usePullRequestParam.ts b/public/app/features/provisioning/hooks/usePullRequestParam.ts
index 4934fff1ffc..81d10210503 100644
--- a/public/app/features/provisioning/hooks/usePullRequestParam.ts
+++ b/public/app/features/provisioning/hooks/usePullRequestParam.ts
@@ -6,10 +6,12 @@ export const usePullRequestParam = () => {
const prParam = params.get('pull_request_url');
const newPrParam = params.get('new_pull_request_url');
const repoUrl = params.get('repo_url');
+ const repoType = params.get('repo_type');
return {
prURL: prParam ? textUtil.sanitizeUrl(prParam) : undefined,
newPrURL: newPrParam ? textUtil.sanitizeUrl(newPrParam) : undefined,
repoURL: repoUrl ? textUtil.sanitizeUrl(repoUrl) : undefined,
+ repoType: repoType ? textUtil.sanitizeUrl(repoType) : undefined,
};
};
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 4de18dad330..20f007d6edf 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -10952,15 +10952,15 @@
},
"provisioned-resource-preview-banner": {
"preview-banner": {
- "behind-branch": "This resource is behind the branch in GitHub.",
- "new-branch": "View it in GitHub to see the latest changes.",
- "not-saved": "The value is not yet saved in the Grafana database",
- "open-git-hub": "Open in Github",
- "open-pull-request-in-git-hub": "Open pull request in GitHub",
- "view-pull-request-in-git-hub": "View pull request in GitHub"
+ "behind-branch-text": "This resource is behind the branch in {{repoType}}.",
+ "not-saved": "The rest of Grafana users in your organization will still see the current version saved to configured default branch until this branch is merged",
+ "open-in-repo-button": "Open in {{repoType}}",
+ "open-pull-request-in-repo": "Open pull request in {{repoType}}",
+ "view-in-repo-button": "View it in {{repoType}} to see the latest changes.",
+ "view-pull-request-in-repo": "View pull request in {{repoType}}"
},
- "title-created-branch-git-hub": "A new resource has been created in a branch in GitHub.",
- "title-loaded-pull-request-git-hub": "This resource is loaded from a pull request in GitHub."
+ "title-created-branch-in-repo": "A new resource has been created in a branch in {{repoType}}.",
+ "title-loaded-pull-request-in-repo": "This resource is loaded from the branch you just created in {{repoType}} and it is only visible to you"
},
"provisioning": {
"banner": {