diff --git a/packages/manager/.changeset/pr-9364-added-1688576551150.md b/packages/manager/.changeset/pr-9364-added-1688576551150.md new file mode 100644 index 00000000000..f810a048ed2 --- /dev/null +++ b/packages/manager/.changeset/pr-9364-added-1688576551150.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Added +--- + +Improved warning and error messaging for failed backup events ([#9364](https://github.com/linode/manager/pull/9364)) diff --git a/packages/manager/src/eventMessageGenerator.ts b/packages/manager/src/eventMessageGenerator.ts index d25a90398be..ea001dbee95 100644 --- a/packages/manager/src/eventMessageGenerator.ts +++ b/packages/manager/src/eventMessageGenerator.ts @@ -48,7 +48,13 @@ export const eventMessageCreators: { [index: string]: CreatorsForStatus } = { backups_restore: { scheduled: (e) => `Backup restoration scheduled for ${e.entity!.label}`, started: (e) => `Backup restoration started for ${e.entity!.label}`, - failed: (e) => `Backup restoration failed for ${e.entity!.label}.`, + failed: (e) => + `${formatEventWithAppendedText( + e, + `Backup restoration failed for ${e.entity!.label}.`, + 'Learn more about limits and considerations', + 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations' + )}`, finished: (e) => `Backup restoration completed for ${e.entity!.label}.`, notification: (e) => `Backup restoration completed for ${e.entity!.label}.`, }, @@ -508,7 +514,13 @@ export const eventMessageCreators: { [index: string]: CreatorsForStatus } = { `Linode ${e.entity!.label} is scheduled for a snapshot backup.`, started: (e) => `A snapshot backup is being created for Linode ${e.entity!.label}.`, - failed: (e) => `Snapshot backup failed on Linode ${e.entity!.label}.`, + failed: (e) => + `${formatEventWithAppendedText( + e, + `Snapshot backup failed on Linode ${e.entity!.label}.`, + 'Learn more about limits and considerations', + 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations' + )}`, finished: (e) => `A snapshot backup has been created for ${e.entity!.label}.`, }, diff --git a/packages/manager/src/features/Linodes/LinodesCreate/AddonsPanel.tsx b/packages/manager/src/features/Linodes/LinodesCreate/AddonsPanel.tsx index b20843e9d90..6657cf72663 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/AddonsPanel.tsx +++ b/packages/manager/src/features/Linodes/LinodesCreate/AddonsPanel.tsx @@ -14,6 +14,8 @@ import { TooltipIcon } from 'src/components/TooltipIcon/TooltipIcon'; import { CreateTypes } from 'src/store/linodeCreate/linodeCreate.actions'; import AttachVLAN from './AttachVLAN'; import { privateIPRegex } from 'src/utilities/ipUtils'; +import { useImageQuery } from 'src/queries/images'; +import { Notice } from 'src/components/Notice/Notice'; const useStyles = makeStyles((theme: Theme) => ({ vlan: { @@ -88,6 +90,11 @@ export const AddonsPanel = React.memo((props: AddonsPanelProps) => { const classes = useStyles(); + const { data: image } = useImageQuery( + selectedImageID ?? '', + Boolean(selectedImageID) + ); + // The VLAN section is shown when the user is not creating by cloning (cloning copies the network interfaces) const showVlans = createType !== 'fromLinode'; @@ -116,6 +123,29 @@ export const AddonsPanel = React.memo((props: AddonsPanelProps) => { ); }; + const checkBackupsWarning = () => { + if (accountBackups || props.backups) { + if (selectedLinodeID) { + const selectedLinode = linodesData?.find( + (linode) => linode.id === selectedLinodeID + ); + if ( + selectedLinode?.image?.includes('private/') || + !selectedLinode?.image + ) { + return true; + } + } else if (selectedImageID && !image?.is_public) { + return true; + } + } + + return false; + }; + + // The backups warning is shown when the user checks to enable backups, but they are using a custom image that may not be compatible. + const showBackupsWarning = checkBackupsWarning(); + // Check whether the source Linode has been allocated a private IP to select/unselect the 'Private IP' checkbox. React.useEffect(() => { if (selectedLinodeID) { @@ -158,6 +188,12 @@ export const AddonsPanel = React.memo((props: AddonsPanelProps) => { ) : null} + {showBackupsWarning && ( + + Linodes must have a disk formatted with an ext3 or ext4 file + system to use the backup service. + + )} { size of your Linode and the amount of data you have stored on it. The manual snapshot will not be overwritten by automatic backups. - + {hasErrorFor.none && ( {hasErrorFor.none} )} - - + + + + { return toastSuccessAndFailure({ enqueueSnackbar, eventStatus: event.status, - failureMessage: `There was an error creating a snapshot on Linode ${label}.`, + persistFailureMessage: true, + failureMessage: `Snapshot backup failed on Linode ${label}.`, + link: formatLink( + 'Learn more about limits and considerations.', + 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations' + ), + }); + case 'backups_restore': + return toastSuccessAndFailure({ + enqueueSnackbar, + eventStatus: event.status, + persistFailureMessage: true, + failureMessage: `Backup restoration failed for ${label}.`, + link: formatLink( + 'Learn more about limits and considerations.', + 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations' + ), }); /** * These create/delete failures are hypothetical. @@ -281,8 +298,14 @@ export default withSnackbar(ToastNotifications); const formatLink = (text: string, link: string, handleClick?: any) => { return ( - + {text} - + ); }; + +export const StyledToastNotificationLink = styled(Link, { + label: 'StyledToastNotificationLink', +})(({ theme }) => ({ + color: theme.textColors.linkActiveLight, +}));