From b1e76a70369d91729be625682b41e1617093814b Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 7 Jul 2023 14:46:53 +0100 Subject: [PATCH] Dashboards: Keep save drawer open for unhandled errors (#70434) * user essentials mob! :trident: * user essentials mob! :trident: lastFile:public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx * user essentials mob! :trident: lastFile:public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx * user essentials mob! :trident: lastFile:public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx * rename isHandledError fn * fix prettier --------- Co-authored-by: Joao Silva Co-authored-by: Laura Benz Co-authored-by: Ashley Harrison --- .../SaveDashboard/SaveDashboardDrawer.tsx | 21 +++++++++---------- .../SaveDashboard/SaveDashboardErrorProxy.tsx | 4 ++-- .../forms/SaveDashboardAsForm.test.tsx | 1 + .../forms/SaveDashboardAsForm.tsx | 13 +++++++++--- .../forms/SaveDashboardForm.test.tsx | 3 +++ .../SaveDashboard/forms/SaveDashboardForm.tsx | 6 ++++-- .../forms/SaveProvisionedDashboardForm.tsx | 2 +- .../components/SaveDashboard/types.ts | 1 + 8 files changed, 32 insertions(+), 19 deletions(-) diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx index 18a2c6157fb..56abc04a20d 100644 --- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx @@ -2,14 +2,14 @@ import React, { useMemo, useState } from 'react'; import { useAsync } from 'react-use'; import { config, isFetchError } from '@grafana/runtime'; -import { Drawer, Spinner, Tab, TabsBar } from '@grafana/ui'; +import { Drawer, Tab, TabsBar } from '@grafana/ui'; import { backendSrv } from 'app/core/services/backend_srv'; import { jsonDiff } from '../VersionHistory/utils'; import DashboardValidation from './DashboardValidation'; import { SaveDashboardDiff } from './SaveDashboardDiff'; -import { SaveDashboardErrorProxy } from './SaveDashboardErrorProxy'; +import { proxyHandlesError, SaveDashboardErrorProxy } from './SaveDashboardErrorProxy'; import { SaveDashboardAsForm } from './forms/SaveDashboardAsForm'; import { SaveDashboardForm } from './forms/SaveDashboardForm'; import { SaveProvisionedDashboardForm } from './forms/SaveProvisionedDashboardForm'; @@ -72,18 +72,11 @@ export const SaveDashboardDrawer = ({ dashboard, onDismiss, onSaveSuccess, isCop return ; } - if (state.loading) { - return ( -
- -
- ); - } - if (isNew || isCopy) { return ( { - if (error.data && isHandledError(error.data.status)) { + if (error.data && proxyHandlesError(error.data.status)) { error.isHandled = true; } }, [error]); @@ -109,7 +109,7 @@ const ConfirmPluginDashboardSaveModal = ({ onDismiss, dashboard }: SaveDashboard ); }; -const isHandledError = (errorStatus: string) => { +export const proxyHandlesError = (errorStatus: string) => { switch (errorStatus) { case 'version-mismatch': case 'name-exists': diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx index 8def9b180e1..665251f5c2c 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx @@ -37,6 +37,7 @@ const renderAndSubmitForm = async ( ) => { render( {}} onSuccess={() => {}} diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx index 2c07960bc98..ed78b95e3ff 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx @@ -40,7 +40,14 @@ export interface SaveDashboardAsFormProps extends SaveDashboardFormProps { isNew?: boolean; } -export const SaveDashboardAsForm = ({ dashboard, isNew, onSubmit, onCancel, onSuccess }: SaveDashboardAsFormProps) => { +export const SaveDashboardAsForm = ({ + dashboard, + isLoading, + isNew, + onSubmit, + onCancel, + onSuccess, +}: SaveDashboardAsFormProps) => { const defaultValues: SaveDashboardAsFormDTO = { title: isNew ? dashboard.title : `${dashboard.title} Copy`, $folder: { @@ -129,8 +136,8 @@ export const SaveDashboardAsForm = ({ dashboard, isNew, onSubmit, onCancel, onSu - diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx index 0988e2e7356..bcbad4676d7 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx @@ -34,6 +34,7 @@ const prepareDashboardMock = ( const renderAndSubmitForm = async (dashboard: DashboardModel, submitSpy: jest.Mock) => { render( {}} onSuccess={() => {}} @@ -62,6 +63,7 @@ describe('SaveDashboardAsForm', () => { it('renders switches when variables or timerange', () => { render( {}} onSuccess={() => {}} @@ -124,6 +126,7 @@ describe('SaveDashboardAsForm', () => { it('renders saved message draft if it was filled before', () => { render( {}} onSuccess={() => {}} diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx index f0b41b2337b..76d8c9fe2bd 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx @@ -13,6 +13,7 @@ interface FormDTO { export type SaveProps = { dashboard: DashboardModel; // original + isLoading: boolean; saveModel: SaveDashboardData; // already cloned onCancel: () => void; onSuccess: () => void; @@ -23,6 +24,7 @@ export type SaveProps = { export const SaveDashboardForm = ({ dashboard, + isLoading, saveModel, options, onSubmit, @@ -108,11 +110,11 @@ export const SaveDashboardForm = ({ {!saveModel.hasChanges &&
No changes to save
} diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx index d62bee8c9a2..984d5b46683 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx @@ -7,7 +7,7 @@ import { Button, ClipboardButton, HorizontalGroup, TextArea } from '@grafana/ui' import { SaveDashboardFormProps } from '../types'; -export const SaveProvisionedDashboardForm = ({ dashboard, onCancel }: SaveDashboardFormProps) => { +export const SaveProvisionedDashboardForm = ({ dashboard, onCancel }: Omit) => { const [dashboardJSON, setDashboardJson] = useState(() => { const clone = dashboard.getSaveModelClone(); delete clone.id; diff --git a/public/app/features/dashboard/components/SaveDashboard/types.ts b/public/app/features/dashboard/components/SaveDashboard/types.ts index 9f0dcd447c0..1e757c0bad0 100644 --- a/public/app/features/dashboard/components/SaveDashboard/types.ts +++ b/public/app/features/dashboard/components/SaveDashboard/types.ts @@ -26,6 +26,7 @@ export interface SaveDashboardCommand { export interface SaveDashboardFormProps { dashboard: DashboardModel; + isLoading: boolean; onCancel: () => void; onSuccess: () => void; onSubmit?: (clone: DashboardModel, options: SaveDashboardOptions, dashboard: DashboardModel) => Promise;