From 122cfb568b19e9bdf3dd0f1a2be79eb48ac8e4c8 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Sun, 23 Feb 2025 22:36:51 +0300 Subject: [PATCH] update preview banner --- .betterer.results | 25 +++-- .../apis/provisioning/resources/client.go | 5 +- .../pages/DashboardScenePage.tsx | 2 +- .../provisioned/DashboardPreviewBanner.tsx | 98 ++++++++++++------- .../provisioned/SaveProvisionedDashboard.tsx | 62 +++++++----- .../saving/provisioned/defaults.ts | 9 +- .../features/dashboard/containers/types.ts | 3 +- public/app/features/provisioning/utils/git.ts | 9 +- 8 files changed, 128 insertions(+), 85 deletions(-) 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 (
@@ -182,7 +201,7 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop control={control} name={'workflow'} render={({ field: { ref, ...field } }) => { - return ; + return ; }} /> @@ -198,15 +217,6 @@ export function SaveProvisionedDashboard({ drawer, changeInfo, dashboard }: Prop )} )} - - {prURL && ( - - A pull request has been created with changes to this dashboard:{' '} - - {prURL} - - - )}