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": {