| 
									
										
										
										
											2024-06-25 19:43:47 +08:00
										 |  |  | import { useState } from 'react'; | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import { selectors } from '@grafana/e2e-selectors'; | 
					
						
							|  |  |  | import { Button, Checkbox, TextArea, Stack, Alert, Box, Field } from '@grafana/ui'; | 
					
						
							| 
									
										
										
										
											2025-01-21 22:50:24 +08:00
										 |  |  | import { Trans, t } from 'app/core/internationalization'; | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  | import { SaveDashboardOptions } from 'app/features/dashboard/components/SaveDashboard/types'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { DashboardScene } from '../scene/DashboardScene'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { SaveDashboardDrawer } from './SaveDashboardDrawer'; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   DashboardChangeInfo, | 
					
						
							|  |  |  |   NameAlreadyExistsError, | 
					
						
							|  |  |  |   SaveButton, | 
					
						
							|  |  |  |   isNameExistsError, | 
					
						
							|  |  |  |   isPluginDashboardError, | 
					
						
							|  |  |  |   isVersionMismatchError, | 
					
						
							|  |  |  | } from './shared'; | 
					
						
							| 
									
										
										
										
											2024-02-08 01:58:23 +08:00
										 |  |  | import { useSaveDashboard } from './useSaveDashboard'; | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export interface Props { | 
					
						
							|  |  |  |   dashboard: DashboardScene; | 
					
						
							|  |  |  |   drawer: SaveDashboardDrawer; | 
					
						
							|  |  |  |   changeInfo: DashboardChangeInfo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function SaveDashboardForm({ dashboard, drawer, changeInfo }: Props) { | 
					
						
							| 
									
										
										
										
											2025-03-13 01:43:32 +08:00
										 |  |  |   const { hasChanges, hasMigratedToV2, changedSaveModel } = changeInfo; | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-08 01:58:23 +08:00
										 |  |  |   const { state, onSaveDashboard } = useSaveDashboard(false); | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |   const [options, setOptions] = useState<SaveDashboardOptions>({ | 
					
						
							|  |  |  |     folderUid: dashboard.state.meta.folderUid, | 
					
						
							| 
									
										
										
										
											2025-01-27 21:14:19 +08:00
										 |  |  |     // we need to set the uid here in order to save the dashboard
 | 
					
						
							|  |  |  |     // in schema v2 we don't have the uid in the spec
 | 
					
						
							|  |  |  |     k8s: { | 
					
						
							|  |  |  |       ...dashboard.state.meta.k8s, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const onSave = async (overwrite: boolean) => { | 
					
						
							| 
									
										
										
										
											2025-03-03 23:07:02 +08:00
										 |  |  |     const result = await onSaveDashboard(dashboard, { ...options, rawDashboardJSON: changedSaveModel, overwrite }); | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |     if (result.status === 'success') { | 
					
						
							|  |  |  |       dashboard.closeModal(); | 
					
						
							| 
									
										
										
										
											2024-03-12 23:12:00 +08:00
										 |  |  |       drawer.state.onSaveSuccess?.(); | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const cancelButton = ( | 
					
						
							|  |  |  |     <Button variant="secondary" onClick={() => dashboard.closeModal()} fill="outline"> | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |       <Trans i18nKey="dashboard-scene.save-dashboard-form.cancel-button.cancel">Cancel</Trans> | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |     </Button> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const saveButton = (overwrite: boolean) => ( | 
					
						
							|  |  |  |     <SaveButton isValid={hasChanges} isLoading={state.loading} onSave={onSave} overwrite={overwrite} /> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-21 22:50:24 +08:00
										 |  |  |   const isMessageTooLongError = (message?: string) => { | 
					
						
							|  |  |  |     return message && message.length > 500; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |   function renderFooter(error?: Error) { | 
					
						
							| 
									
										
										
										
											2025-01-21 22:50:24 +08:00
										 |  |  |     if (isMessageTooLongError(options.message)) { | 
					
						
							|  |  |  |       const messageLength = options.message?.length ?? 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return ( | 
					
						
							|  |  |  |         <Alert title={t('save-dashboards.message-length.title', 'Message too long')} severity="error"> | 
					
						
							|  |  |  |           <p> | 
					
						
							|  |  |  |             <Trans i18nKey="save-dashboards.message-length.info"> | 
					
						
							|  |  |  |               The message is {{ messageLength }} characters, which exceeds the maximum length of 500 characters. Please | 
					
						
							|  |  |  |               shorten it before saving. | 
					
						
							|  |  |  |             </Trans> | 
					
						
							|  |  |  |           </p> | 
					
						
							|  |  |  |         </Alert> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |     if (isVersionMismatchError(error)) { | 
					
						
							|  |  |  |       return ( | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |         <Alert | 
					
						
							|  |  |  |           title={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form.render-footer.title-someone-else-has-updated-this-dashboard', | 
					
						
							|  |  |  |             'Someone else has updated this dashboard' | 
					
						
							|  |  |  |           )} | 
					
						
							|  |  |  |           severity="error" | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <p> | 
					
						
							|  |  |  |             <Trans i18nKey="dashboard-scene.save-dashboard-form.render-footer.would-still-dashboard"> | 
					
						
							|  |  |  |               Would you still like to save this dashboard? | 
					
						
							|  |  |  |             </Trans> | 
					
						
							|  |  |  |           </p> | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |           <Box paddingTop={2}> | 
					
						
							|  |  |  |             <Stack alignItems="center"> | 
					
						
							|  |  |  |               {cancelButton} | 
					
						
							|  |  |  |               {saveButton(true)} | 
					
						
							|  |  |  |             </Stack> | 
					
						
							|  |  |  |           </Box> | 
					
						
							|  |  |  |         </Alert> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isNameExistsError(error)) { | 
					
						
							|  |  |  |       return <NameAlreadyExistsError cancelButton={cancelButton} saveButton={saveButton} />; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isPluginDashboardError(error)) { | 
					
						
							|  |  |  |       return ( | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |         <Alert | 
					
						
							|  |  |  |           title={t('dashboard-scene.save-dashboard-form.render-footer.title-plugin-dashboard', 'Plugin dashboard')} | 
					
						
							|  |  |  |           severity="error" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |           <p> | 
					
						
							|  |  |  |             Your changes will be lost when you update the plugin. Use <strong>Save As</strong> to create custom version. | 
					
						
							|  |  |  |           </p> | 
					
						
							|  |  |  |           <Box paddingTop={2}> | 
					
						
							|  |  |  |             <Stack alignItems="center"> | 
					
						
							|  |  |  |               {cancelButton} | 
					
						
							|  |  |  |               {saveButton(true)} | 
					
						
							|  |  |  |             </Stack> | 
					
						
							|  |  |  |           </Box> | 
					
						
							|  |  |  |         </Alert> | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <> | 
					
						
							|  |  |  |         {error && ( | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           <Alert | 
					
						
							|  |  |  |             title={t( | 
					
						
							|  |  |  |               'dashboard-scene.save-dashboard-form.render-footer.title-failed-to-save-dashboard', | 
					
						
							|  |  |  |               'Failed to save dashboard' | 
					
						
							|  |  |  |             )} | 
					
						
							|  |  |  |             severity="error" | 
					
						
							|  |  |  |           > | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |             <p>{error.message}</p> | 
					
						
							|  |  |  |           </Alert> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  |         <Stack alignItems="center"> | 
					
						
							|  |  |  |           {cancelButton} | 
					
						
							|  |  |  |           {saveButton(false)} | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           {!hasChanges && ( | 
					
						
							|  |  |  |             <div> | 
					
						
							|  |  |  |               <Trans i18nKey="dashboard-scene.save-dashboard-form.render-footer.no-changes-to-save"> | 
					
						
							|  |  |  |                 No changes to save | 
					
						
							|  |  |  |               </Trans> | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |         </Stack> | 
					
						
							|  |  |  |       </> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |     <Stack gap={2} direction="column"> | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  |       <SaveDashboardFormCommonOptions drawer={drawer} changeInfo={changeInfo} /> | 
					
						
							| 
									
										
										
										
											2025-03-13 01:43:32 +08:00
										 |  |  |       {hasMigratedToV2 && ( | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |         <Alert | 
					
						
							|  |  |  |           title={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form.title-dashboard-drastically-changed', | 
					
						
							|  |  |  |             'Dashboard drastically changed' | 
					
						
							|  |  |  |           )} | 
					
						
							|  |  |  |           severity="warning" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2025-03-13 01:43:32 +08:00
										 |  |  |           <p> | 
					
						
							|  |  |  |             Because you're using new dashboards features only supported on new Grafana dashboard schema format, the | 
					
						
							|  |  |  |             dashboard will be saved in the new format. Please make sure you want to perform this action or you prefer to | 
					
						
							|  |  |  |             save the dashboard as a new copy. | 
					
						
							|  |  |  |           </p> | 
					
						
							|  |  |  |         </Alert> | 
					
						
							|  |  |  |       )} | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |       <Field label={t('dashboard-scene.save-dashboard-form.label-message', 'Message')}> | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |         <TextArea | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           aria-label={t('dashboard-scene.save-dashboard-form.aria-label-message', 'message')} | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |           value={options.message ?? ''} | 
					
						
							|  |  |  |           onChange={(e) => { | 
					
						
							|  |  |  |             setOptions({ | 
					
						
							|  |  |  |               ...options, | 
					
						
							|  |  |  |               message: e.currentTarget.value, | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           }} | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           placeholder={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form.placeholder-describe-changes-optional', | 
					
						
							|  |  |  |             'Add a note to describe your changes (optional).' | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |           autoFocus | 
					
						
							|  |  |  |           rows={5} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </Field> | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |       {renderFooter(state.error)} | 
					
						
							| 
									
										
										
										
											2024-01-29 19:04:45 +08:00
										 |  |  |     </Stack> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export interface SaveDashboardFormCommonOptionsProps { | 
					
						
							|  |  |  |   drawer: SaveDashboardDrawer; | 
					
						
							|  |  |  |   changeInfo: DashboardChangeInfo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function SaveDashboardFormCommonOptions({ drawer, changeInfo }: SaveDashboardFormCommonOptionsProps) { | 
					
						
							| 
									
										
										
										
											2024-04-05 23:31:40 +08:00
										 |  |  |   const { saveVariables = false, saveTimeRange = false, saveRefresh = false } = drawer.useState(); | 
					
						
							|  |  |  |   const { hasTimeChanges, hasVariableValueChanges, hasRefreshChange } = changeInfo; | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |     <Stack direction={'column'} alignItems={'flex-start'}> | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  |       {hasTimeChanges && ( | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |         <Checkbox | 
					
						
							|  |  |  |           id="save-timerange" | 
					
						
							|  |  |  |           checked={saveTimeRange} | 
					
						
							|  |  |  |           onChange={drawer.onToggleSaveTimeRange} | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           label={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form-common-options.save-timerange-label-update-default-time-range', | 
					
						
							|  |  |  |             'Update default time range' | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |           description={'Will make current time range the new default'} | 
					
						
							|  |  |  |           data-testid={selectors.pages.SaveDashboardModal.saveTimerange} | 
					
						
							|  |  |  |         /> | 
					
						
							| 
									
										
										
										
											2024-04-05 23:31:40 +08:00
										 |  |  |       )} | 
					
						
							|  |  |  |       {hasRefreshChange && ( | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |         <Checkbox | 
					
						
							|  |  |  |           id="save-refresh" | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           label={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form-common-options.save-refresh-label-update-default-refresh-value', | 
					
						
							|  |  |  |             'Update default refresh value' | 
					
						
							|  |  |  |           )} | 
					
						
							|  |  |  |           description={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form-common-options.save-refresh-description-current-refresh-default', | 
					
						
							|  |  |  |             'Will make the current refresh the new default' | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |           checked={saveRefresh} | 
					
						
							|  |  |  |           onChange={drawer.onToggleSaveRefresh} | 
					
						
							|  |  |  |           data-testid={selectors.pages.SaveDashboardModal.saveRefresh} | 
					
						
							|  |  |  |         /> | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  |       )} | 
					
						
							|  |  |  |       {hasVariableValueChanges && ( | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |         <Checkbox | 
					
						
							|  |  |  |           id="save-variables" | 
					
						
							| 
									
										
										
										
											2025-04-02 17:03:12 +08:00
										 |  |  |           label={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form-common-options.save-variables-label-update-default-variable-values', | 
					
						
							|  |  |  |             'Update default variable values' | 
					
						
							|  |  |  |           )} | 
					
						
							|  |  |  |           description={t( | 
					
						
							|  |  |  |             'dashboard-scene.save-dashboard-form-common-options.save-variables-description-current-values-default', | 
					
						
							|  |  |  |             'Will make the current values the new default' | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |           checked={saveVariables} | 
					
						
							|  |  |  |           onChange={drawer.onToggleSaveVariables} | 
					
						
							|  |  |  |           data-testid={selectors.pages.SaveDashboardModal.saveVariables} | 
					
						
							|  |  |  |         /> | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  |       )} | 
					
						
							| 
									
										
										
										
											2024-04-18 16:15:06 +08:00
										 |  |  |     </Stack> | 
					
						
							| 
									
										
										
										
											2024-01-30 03:03:57 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | } |