diff --git a/.betterer.results b/.betterer.results index cfc75962fc6..ee5b0e9e79d 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2401,6 +2401,13 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"] ], + "public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx:5381": [ + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"], + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"] + ], + "public/app/features/dashboard-scene/saving/shared.tsx:5381": [ + [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] + ], "public/app/features/dashboard-scene/scene/DashboardScene.test.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], diff --git a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts index 0324a580a28..315381d1632 100644 --- a/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts +++ b/public/app/features/browse-dashboards/api/browseDashboardsAPI.ts @@ -275,9 +275,10 @@ export const browseDashboardsAPI = createApi({ }), // save an existing dashboard saveDashboard: builder.mutation({ - query: ({ dashboard, folderUid, message, overwrite }) => ({ + query: ({ dashboard, folderUid, message, overwrite, showErrorAlert }) => ({ url: `/dashboards/db`, method: 'POST', + showErrorAlert, data: { dashboard, folderUid, diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx new file mode 100644 index 00000000000..d8a72c7beba --- /dev/null +++ b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx @@ -0,0 +1,196 @@ +import React from 'react'; +import { UseFormSetValue, useForm } from 'react-hook-form'; + +import { Dashboard } from '@grafana/schema'; +import { Button, Input, Switch, Field, Label, TextArea, Stack, Alert, Box } from '@grafana/ui'; +import { FolderPicker } from 'app/core/components/Select/FolderPicker'; +import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv'; + +import { DashboardScene } from '../scene/DashboardScene'; + +import { SaveDashboardDrawer } from './SaveDashboardDrawer'; +import { DashboardChangeInfo, NameAlreadyExistsError, SaveButton, isNameExistsError } from './shared'; +import { useDashboardSave } from './useSaveDashboard'; + +interface SaveDashboardAsFormDTO { + firstName?: string; + title: string; + description: string; + folder: { uid?: string; title?: string }; + copyTags: boolean; +} + +export interface Props { + dashboard: DashboardScene; + drawer: SaveDashboardDrawer; + changeInfo: DashboardChangeInfo; +} + +export function SaveDashboardAsForm({ dashboard, drawer, changeInfo }: Props) { + const { changedSaveModel } = changeInfo; + + const { register, handleSubmit, setValue, formState, getValues } = useForm({ + mode: 'onBlur', + defaultValues: { + title: changeInfo.isNew ? changedSaveModel.title! : `${changedSaveModel.title} Copy`, + description: changedSaveModel.description ?? '', + folder: { + uid: dashboard.state.meta.folderUid, + title: dashboard.state.meta.folderTitle, + }, + copyTags: false, + }, + }); + const { errors, isValid, defaultValues } = formState; + const formValues = getValues(); + + const { state, onSaveDashboard } = useDashboardSave(false); + + const onSave = async (overwrite: boolean) => { + const data = getValues(); + + const dashboardToSave: Dashboard = getSaveAsDashboardSaveModel(changedSaveModel, data, changeInfo.isNew); + const result = await onSaveDashboard(dashboard, dashboardToSave, { overwrite, folderUid: data.folder.uid }); + + if (result.status === 'success') { + dashboard.closeModal(); + } + }; + + const cancelButton = ( + + ); + + const saveButton = (overwrite: boolean) => ( + + ); + + function renderFooter(error?: Error) { + if (isNameExistsError(error)) { + return ; + } + + return ( + <> + {error && ( + +

{error.message}

+
+ )} + + {cancelButton} + {saveButton(false)} + + + ); + } + + return ( +
onSave(false))}> + } + invalid={!!errors.title} + error={errors.title?.message} + > + + + } + invalid={!!errors.description} + error={errors.description?.message} + > +