Skip to content

Commit

Permalink
feat: [M3-6789] - Improve failed backup error messaging (#9364)
Browse files Browse the repository at this point in the history
* Update linode_snapshot event toast

* Update backup restore and snapshot error events and toasts

* Fix styling regression for snapshot error notice

* Add backups warning for create flow with private images

* Add changeset

* Address feedback

* Add mock failed backups_restore event to be removed before merging

* Address naming and copy feedback

* Fix toast link text color in dark mode

* Revert unintentional commit to include failed event in mocks
  • Loading branch information
mjac0bs authored Jul 6, 2023
1 parent 5b5cf30 commit c52feed
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 23 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-9364-added-1688576551150.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Improved warning and error messaging for failed backup events ([#9364](https://github.com/linode/manager/pull/9364))
16 changes: 14 additions & 2 deletions packages/manager/src/eventMessageGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}.`,
},
Expand Down Expand Up @@ -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}.`,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -158,6 +188,12 @@ export const AddonsPanel = React.memo((props: AddonsPanelProps) => {
) : null}
</Typography>
<Grid container>
{showBackupsWarning && (
<Notice warning>
Linodes must have a disk formatted with an ext3 or ext4 file
system to use the backup service.
</Notice>
)}
<Grid xs={12}>
<FormControlLabel
className={classes.label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CaptureSnapshotConfirmationDialog } from './CaptureSnapshotConfirmation
import { Button } from 'src/components/Button/Button';
import { resetEventsPolling } from 'src/eventsPolling';
import { getErrorMap } from 'src/utilities/errorUtils';
import { Box } from 'src/components/Box';

interface Props {
linodeId: number;
Expand Down Expand Up @@ -79,29 +80,31 @@ export const CaptureSnapshot = ({ linodeId, isReadOnly }: Props) => {
size of your Linode and the amount of data you have stored on it. The
manual snapshot will not be overwritten by automatic backups.
</Typography>
<FormControl className={classes.snapshotFormControl}>
<FormControl>
{hasErrorFor.none && (
<Notice spacingBottom={8} error>
{hasErrorFor.none}
</Notice>
)}
<TextField
errorText={hasErrorFor.label}
label="Name Snapshot"
name="label"
value={snapshotForm.values.label}
onChange={snapshotForm.handleChange}
data-qa-manual-name
className={classes.snapshotNameField}
/>
<Button
buttonType="primary"
onClick={() => setIsSnapshotConfirmationDialogOpen(true)}
data-qa-snapshot-button
disabled={snapshotForm.values.label === '' || isReadOnly}
>
Take Snapshot
</Button>
<Box className={classes.snapshotFormControl}>
<TextField
errorText={hasErrorFor.label}
label="Name Snapshot"
name="label"
value={snapshotForm.values.label}
onChange={snapshotForm.handleChange}
data-qa-manual-name
className={classes.snapshotNameField}
/>
<Button
buttonType="primary"
onClick={() => setIsSnapshotConfirmationDialogOpen(true)}
data-qa-snapshot-button
disabled={snapshotForm.values.label === '' || isReadOnly}
>
Take Snapshot
</Button>
</Box>
</FormControl>
<CaptureSnapshotConfirmationDialog
open={isSnapshotConfirmationDialogOpen}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Event, EventStatus } from '@linode/api-v4/lib/account/types';
import { styled } from '@mui/material/styles';
import { withSnackbar, WithSnackbarProps } from 'notistack';
import * as React from 'react';
import 'rxjs/add/operator/bufferTime';
Expand Down Expand Up @@ -172,7 +173,23 @@ class ToastNotifications extends React.PureComponent<WithSnackbarProps, {}> {
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.
Expand Down Expand Up @@ -281,8 +298,14 @@ export default withSnackbar(ToastNotifications);

const formatLink = (text: string, link: string, handleClick?: any) => {
return (
<Link to={link} onClick={handleClick}>
<StyledToastNotificationLink to={link} onClick={handleClick}>
{text}
</Link>
</StyledToastNotificationLink>
);
};

export const StyledToastNotificationLink = styled(Link, {
label: 'StyledToastNotificationLink',
})(({ theme }) => ({
color: theme.textColors.linkActiveLight,
}));

0 comments on commit c52feed

Please sign in to comment.