diff --git a/packages/manager/.changeset/pr-10841-tech-stories-1724763185078.md b/packages/manager/.changeset/pr-10841-tech-stories-1724763185078.md
new file mode 100644
index 00000000000..6173b8d24de
--- /dev/null
+++ b/packages/manager/.changeset/pr-10841-tech-stories-1724763185078.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Tech Stories
+---
+
+Refactor useToastNotification async toasts ([#10841](https://github.com/linode/manager/pull/10841))
diff --git a/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts b/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts
index fbd28300d66..25339973135 100644
--- a/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts
+++ b/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts
@@ -81,9 +81,7 @@ const eventIntercept = (
* @param message - Expected failure message.
*/
const assertFailed = (label: string, id: string, message: string) => {
- ui.toast.assertMessage(
- `There was a problem uploading image ${label}: ${message}`
- );
+ ui.toast.assertMessage(`Image ${label} could not be uploaded: ${message}`);
cy.get(`[data-qa-image-cell="${id}"]`).within(() => {
fbtVisible(label);
diff --git a/packages/manager/cypress/e2e/core/images/smoke-create-image.spec.ts b/packages/manager/cypress/e2e/core/images/smoke-create-image.spec.ts
index f6e0a0e1cdc..1ee83565388 100644
--- a/packages/manager/cypress/e2e/core/images/smoke-create-image.spec.ts
+++ b/packages/manager/cypress/e2e/core/images/smoke-create-image.spec.ts
@@ -107,6 +107,6 @@ describe('create image (using mocks)', () => {
cy.wait('@getEvents');
// Verify a success toast shows
- ui.toast.assertMessage('Image My Config successfully created.');
+ ui.toast.assertMessage('Image My Config has been created.');
});
});
diff --git a/packages/manager/cypress/e2e/core/linodes/clone-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/clone-linode.spec.ts
index cd9a78f2258..c64e43abba6 100644
--- a/packages/manager/cypress/e2e/core/linodes/clone-linode.spec.ts
+++ b/packages/manager/cypress/e2e/core/linodes/clone-linode.spec.ts
@@ -106,7 +106,7 @@ describe('clone linode', () => {
ui.toast.assertMessage(`Your Linode ${newLinodeLabel} is being created.`);
ui.toast.assertMessage(
- `Linode ${linode.label} successfully cloned to ${newLinodeLabel}.`,
+ `Linode ${linode.label} has been cloned to ${newLinodeLabel}.`,
{ timeout: CLONE_TIMEOUT }
);
});
diff --git a/packages/manager/cypress/e2e/core/linodes/linode-config.spec.ts b/packages/manager/cypress/e2e/core/linodes/linode-config.spec.ts
index a6ea27fbc80..2e73ca80de0 100644
--- a/packages/manager/cypress/e2e/core/linodes/linode-config.spec.ts
+++ b/packages/manager/cypress/e2e/core/linodes/linode-config.spec.ts
@@ -381,7 +381,7 @@ describe('Linode Config management', () => {
// Confirm toast message and that UI updates to reflect clone in progress.
ui.toast.assertMessage(
- `Linode ${sourceLinode.label} successfully cloned to ${destLinode.label}.`
+ `Linode ${sourceLinode.label} has been cloned to ${destLinode.label}.`
);
cy.findByText(/CLONING \(\d+%\)/).should('be.visible');
});
diff --git a/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts b/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts
index 6cd87caaf14..0e256bbbb41 100644
--- a/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts
+++ b/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts
@@ -148,7 +148,9 @@ describe('linode storage tab', () => {
cy.wait('@deleteDisk').its('response.statusCode').should('eq', 200);
cy.findByText('Deleting', { exact: false }).should('be.visible');
ui.button.findByTitle('Add a Disk').should('be.enabled');
- ui.toast.assertMessage(`Disk ${diskName} successfully deleted.`);
+ ui.toast.assertMessage(
+ `Disk ${diskName} on Linode ${linode.label} has been deleted.`
+ );
cy.findByLabelText('List of Disks').within(() => {
cy.contains(diskName).should('not.exist');
});
@@ -209,7 +211,9 @@ describe('linode storage tab', () => {
cy.wait('@resizeDisk').its('response.statusCode').should('eq', 200);
ui.toast.assertMessage('Disk queued for resizing.');
// cy.findByText('Resizing', { exact: false }).should('be.visible');
- ui.toast.assertMessage(`Disk ${diskName} successfully resized.`);
+ ui.toast.assertMessage(
+ `Disk ${diskName} on Linode ${linode.label} has been resized.`
+ );
});
});
});
diff --git a/packages/manager/cypress/e2e/core/linodes/resize-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/resize-linode.spec.ts
index 0d003ddd864..ba2107cd62a 100644
--- a/packages/manager/cypress/e2e/core/linodes/resize-linode.spec.ts
+++ b/packages/manager/cypress/e2e/core/linodes/resize-linode.spec.ts
@@ -186,7 +186,9 @@ describe('resize linode', () => {
});
// Wait until the disk resize is done.
- ui.toast.assertMessage(`Disk ${diskName} successfully resized.`);
+ ui.toast.assertMessage(
+ `Disk ${diskName} on Linode ${linode.label} has been resized.`
+ );
interceptLinodeResize(linode.id).as('linodeResize');
cy.visitWithLogin(`/linodes/${linode.id}?resize=true`);
diff --git a/packages/manager/cypress/e2e/core/volumes/attach-volume.spec.ts b/packages/manager/cypress/e2e/core/volumes/attach-volume.spec.ts
index 6e2835aa20b..76c2ec63a0f 100644
--- a/packages/manager/cypress/e2e/core/volumes/attach-volume.spec.ts
+++ b/packages/manager/cypress/e2e/core/volumes/attach-volume.spec.ts
@@ -114,7 +114,9 @@ describe('volume attach and detach flows', () => {
// Confirm that volume has been attached to Linode.
cy.wait('@attachVolume').its('response.statusCode').should('eq', 200);
- ui.toast.assertMessage(`Volume ${volume.label} successfully attached.`);
+ ui.toast.assertMessage(
+ `Volume ${volume.label} has been attached to Linode ${linode.label}.`
+ );
cy.findByText(volume.label)
.should('be.visible')
.closest('tr')
diff --git a/packages/manager/cypress/e2e/core/volumes/delete-volume.spec.ts b/packages/manager/cypress/e2e/core/volumes/delete-volume.spec.ts
index fe441dcf865..7897d0c7f2c 100644
--- a/packages/manager/cypress/e2e/core/volumes/delete-volume.spec.ts
+++ b/packages/manager/cypress/e2e/core/volumes/delete-volume.spec.ts
@@ -87,7 +87,7 @@ describe('volume delete flow', () => {
// Confirm that volume is deleted.
cy.wait('@deleteVolume').its('response.statusCode').should('eq', 200);
cy.findByText(volume.label).should('not.exist');
- ui.toast.assertMessage('Volume successfully deleted.');
+ ui.toast.assertMessage(`Volume ${volume.label} has been deleted.`);
}
);
});
diff --git a/packages/manager/cypress/e2e/core/volumes/upgrade-volume.spec.ts b/packages/manager/cypress/e2e/core/volumes/upgrade-volume.spec.ts
index 59436b4e983..f6d807e4c15 100644
--- a/packages/manager/cypress/e2e/core/volumes/upgrade-volume.spec.ts
+++ b/packages/manager/cypress/e2e/core/volumes/upgrade-volume.spec.ts
@@ -87,7 +87,7 @@ describe('volume upgrade/migration', () => {
cy.findByText('active').should('be.visible');
- ui.toast.assertMessage(`Volume ${volume.label} successfully upgraded.`);
+ ui.toast.assertMessage(`Volume ${volume.label} has been migrated to NVMe.`);
});
it('can upgrade an attached volume from the volumes landing page', () => {
@@ -178,7 +178,7 @@ describe('volume upgrade/migration', () => {
cy.findByText('active').should('be.visible');
- ui.toast.assertMessage(`Volume ${volume.label} successfully upgraded.`);
+ ui.toast.assertMessage(`Volume ${volume.label} has been migrated to NVMe.`);
});
it('can upgrade an attached volume from the linode details page', () => {
@@ -265,6 +265,6 @@ describe('volume upgrade/migration', () => {
cy.findByText('active').should('be.visible');
- ui.toast.assertMessage(`Volume ${volume.label} successfully upgraded.`);
+ ui.toast.assertMessage(`Volume ${volume.label} has been migrated to NVMe.`);
});
});
diff --git a/packages/manager/src/features/Events/asyncToasts.test.tsx b/packages/manager/src/features/Events/asyncToasts.test.tsx
new file mode 100644
index 00000000000..0ed1b44a26a
--- /dev/null
+++ b/packages/manager/src/features/Events/asyncToasts.test.tsx
@@ -0,0 +1,140 @@
+import { createToast } from './asyncToasts';
+
+describe('createToast', () => {
+ it('should handle case with both failure and success options as true or empty objects', () => {
+ const trueOptions = { failure: true, success: true };
+ const emptyObjectOptions = { failure: {}, success: {} };
+
+ [trueOptions, emptyObjectOptions].forEach((options) => {
+ const result = createToast(options);
+ const expected = {
+ failure: {
+ message: expect.any(Function),
+ },
+ success: {
+ message: expect.any(Function),
+ },
+ };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ it('should handle case with only failure option as true or empty object or with success as false', () => {
+ const scenarios = [
+ { failure: true },
+ { failure: {} },
+ { failure: true, success: false },
+ { failure: {}, success: false },
+ ];
+
+ scenarios.forEach((options) => {
+ const result = createToast(options);
+ const expected = {
+ failure: {
+ message: expect.any(Function),
+ },
+ };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ it('should handle case with only success option as true or empty object or with failure as false', () => {
+ const scenarios = [
+ { success: true },
+ { success: {} },
+ { failure: false, success: true },
+ { failure: false, success: {} },
+ ];
+
+ scenarios.forEach((options) => {
+ const result = createToast(options);
+ const expected = {
+ success: {
+ message: expect.any(Function),
+ },
+ };
+
+ expect(result).toEqual(expected);
+ });
+ });
+
+ it('should return an empty object if both failure and success are false or not provided', () => {
+ const falseOptions = { failure: false, success: false };
+ const emptyOptions = {};
+ [falseOptions, emptyOptions].forEach((options) => {
+ const result = createToast(options);
+
+ expect(result).toEqual({});
+ });
+ });
+
+ it('should handle cases with specific values for only failure or success options', () => {
+ // Only the failure options with specific values
+ const failureOnlyOptions = {
+ failure: { persist: true },
+ };
+ const result1 = createToast(failureOnlyOptions);
+ const expected1 = {
+ failure: {
+ message: expect.any(Function),
+ persist: true,
+ },
+ };
+ expect(result1).toEqual(expected1);
+
+ // Only the success options with specific values
+ const successOnlyOptions = {
+ success: { invertVariant: true, persist: false },
+ };
+ const result2 = createToast(successOnlyOptions);
+ const expected2 = {
+ success: {
+ invertVariant: true,
+ message: expect.any(Function),
+ persist: false,
+ },
+ };
+ expect(result2).toEqual(expected2);
+ });
+
+ it('should handle case with both failure and success options with specific values', () => {
+ const options1 = {
+ failure: { invertVariant: true, persist: true },
+ success: { invertVariant: true, persist: false },
+ };
+ const result1 = createToast(options1);
+ const expected1 = {
+ failure: {
+ invertVariant: true,
+ message: expect.any(Function),
+ persist: true,
+ },
+ success: {
+ invertVariant: true,
+ message: expect.any(Function),
+ persist: false,
+ },
+ };
+ expect(result1).toEqual(expected1);
+
+ const options2 = {
+ failure: { persist: true },
+ success: { invertVariant: true },
+ };
+
+ const result2 = createToast(options2);
+ const expected2 = {
+ failure: {
+ message: expect.any(Function),
+ persist: true,
+ },
+ success: {
+ invertVariant: true,
+ message: expect.any(Function),
+ },
+ };
+ expect(result2).toEqual(expected2);
+ });
+});
diff --git a/packages/manager/src/features/Events/asyncToasts.tsx b/packages/manager/src/features/Events/asyncToasts.tsx
new file mode 100644
index 00000000000..5c3cdc9553e
--- /dev/null
+++ b/packages/manager/src/features/Events/asyncToasts.tsx
@@ -0,0 +1,95 @@
+import { getEventMessage } from './utils';
+
+import type { Event, EventAction } from '@linode/api-v4';
+
+interface ToastMessage {
+ /**
+ * If true, the toast will be displayed with an error variant for success messages \
+ * or a success variant for error messages.
+ */
+ invertVariant?: boolean;
+ message: ((event: Event) => JSX.Element | null | string | undefined) | string;
+ persist?: boolean;
+}
+
+interface Toast {
+ failure?: ToastMessage;
+ success?: ToastMessage;
+}
+
+type Toasts = {
+ [key in EventAction]?: Toast;
+};
+
+interface ToastOption {
+ invertVariant?: boolean;
+ persist?: boolean;
+}
+
+interface ToastOptions {
+ failure?: ToastOption | boolean;
+ success?: ToastOption | boolean;
+}
+
+export const createToast = (options: ToastOptions) => {
+ const toastConfig: Toast = {};
+
+ const getToastMessage = (option: ToastOption | boolean): ToastMessage => {
+ const message: ToastMessage['message'] = (e) => getEventMessage(e);
+
+ if (typeof option === 'boolean') {
+ return { message };
+ }
+
+ return {
+ message,
+ ...(option.invertVariant !== undefined && {
+ invertVariant: option.invertVariant,
+ }),
+ ...(option.persist !== undefined && { persist: option.persist }),
+ };
+ };
+
+ if (options.failure) {
+ toastConfig.failure = getToastMessage(options.failure);
+ }
+
+ if (options.success) {
+ toastConfig.success = getToastMessage(options.success);
+ }
+
+ return toastConfig;
+};
+
+/**
+ * This constant defines toast notifications that will be displayed
+ * when our events polling system gets a new event.
+ *
+ * Use this feature to notify users of *asynchronous tasks* such as migrating a Linode.
+ *
+ * DO NOT use this feature to notify the user of tasks like changing the label of a Linode.
+ * Toasts for that can be handled at the time of making the PUT request.
+ */
+export const toasts: Toasts = {
+ backups_restore: createToast({ failure: { persist: true } }),
+ disk_delete: createToast({ failure: false, success: true }),
+ disk_imagize: createToast({ failure: { persist: true }, success: true }),
+ disk_resize: createToast({ failure: { persist: true }, success: true }),
+ image_delete: createToast({ failure: true, success: true }),
+ image_upload: createToast({ failure: { persist: true }, success: true }),
+ linode_clone: createToast({ failure: true, success: true }),
+ linode_migrate: createToast({ failure: true, success: true }),
+ linode_migrate_datacenter: createToast({ failure: true, success: true }),
+ linode_resize: createToast({ failure: true, success: true }),
+ linode_snapshot: createToast({ failure: { persist: true } }),
+ longviewclient_create: createToast({ failure: true, success: true }),
+ tax_id_invalid: createToast({
+ failure: true,
+ success: { invertVariant: true, persist: true },
+ }),
+ volume_attach: createToast({ failure: true, success: true }),
+ volume_create: createToast({ failure: true, success: true }),
+ volume_delete: createToast({ failure: true, success: true }),
+ volume_detach: createToast({ failure: true, success: true }),
+ volume_migrate: createToast({ failure: true, success: true }),
+};
diff --git a/packages/manager/src/features/Events/factories/backup.tsx b/packages/manager/src/features/Events/factories/backup.tsx
index 31344a45197..0e45776e06d 100644
--- a/packages/manager/src/features/Events/factories/backup.tsx
+++ b/packages/manager/src/features/Events/factories/backup.tsx
@@ -22,11 +22,12 @@ export const backup: PartialEventMap<'backups'> = {
backups_restore: {
failed: (e) => (
<>
- Backup could not be restored for
+ Backup could not be restored for{' '}
{e.entity!.label}.{' '}
- Learn more about limits and considerations.
+ Learn more about limits and considerations
+ .
>
),
finished: (e) => (
diff --git a/packages/manager/src/features/Events/factories/disk.tsx b/packages/manager/src/features/Events/factories/disk.tsx
index 8168cdd76e4..761fceafb21 100644
--- a/packages/manager/src/features/Events/factories/disk.tsx
+++ b/packages/manager/src/features/Events/factories/disk.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { Link } from 'src/components/Link';
+import { sendLinodeDiskEvent } from 'src/utilities/analytics/customEventAnalytics';
import { EventLink } from '../EventLink';
@@ -76,32 +77,37 @@ export const disk: PartialEventMap<'disk'> = {
disk_duplicate: {
failed: (e) => (
<>
- Disk on Linode could{' '}
- not be duplicated.
+ Disk on Linode{' '}
+ could not be{' '}
+ duplicated.
>
),
finished: (e) => (
<>
- Disk on Linode has been{' '}
- duplicated.
+ Disk on Linode{' '}
+ has been duplicated
+ .
>
),
notification: (e) => (
<>
- Disk on Linode has been{' '}
- duplicated.
+ Disk on Linode{' '}
+ has been duplicated
+ .
>
),
scheduled: (e) => (
<>
- Disk on Linode is scheduled to be{' '}
+ Disk on Linode{' '}
+ is scheduled to be{' '}
duplicated.
>
),
started: (e) => (
<>
- Disk on Linode is being{' '}
- duplicated.
+ Disk on Linode{' '}
+ is being duplicated
+ .
>
),
},
@@ -111,7 +117,7 @@ export const disk: PartialEventMap<'disk'> = {
Image could{' '}
not be created.{' '}
- Learn more about image technical specifications.
+ Learn more about image technical specifications
.
>
@@ -138,36 +144,46 @@ export const disk: PartialEventMap<'disk'> = {
disk_resize: {
failed: (e) => (
<>
- A disk on Linode could{' '}
- not be resized.{' '}
-
+ Disk on Linode{' '}
+ could not be{' '}
+ resized.{' '}
+ {
+ sendLinodeDiskEvent(
+ 'Resize',
+ 'Click:link',
+ 'Disk resize failed toast'
+ );
+ }}
+ to="https://www.linode.com/docs/products/compute/compute-instances/guides/disks-and-storage/"
+ >
Learn more
>
),
-
finished: (e) => (
<>
- A disk on Linode has been{' '}
- resized.
+ Disk on Linode{' '}
+ has been resized.
>
),
notification: (e) => (
<>
- A disk on Linode has been{' '}
- resized.
+ Disk on Linode{' '}
+ has been resized.
>
),
scheduled: (e) => (
<>
- A disk on Linode is scheduled to be{' '}
+ Disk on Linode{' '}
+ is scheduled to be{' '}
resized.
>
),
started: (e) => (
<>
- A disk on Linode is being{' '}
- resized.
+ Disk on Linode{' '}
+ is being resized.
>
),
},
diff --git a/packages/manager/src/features/Events/factories/image.tsx b/packages/manager/src/features/Events/factories/image.tsx
index dbe4ef39cf2..a9912b6ab87 100644
--- a/packages/manager/src/features/Events/factories/image.tsx
+++ b/packages/manager/src/features/Events/factories/image.tsx
@@ -53,8 +53,7 @@ export const image: PartialEventMap<'image'> = {
finished: (e) => (
<>
- Image has been{' '}
- uploaded.
+ Image is now available.
>
),
notification: (e) => (
diff --git a/packages/manager/src/hooks/useToastNotifications.tsx b/packages/manager/src/hooks/useToastNotifications.tsx
index 51633c484b3..8198aa0bb9c 100644
--- a/packages/manager/src/hooks/useToastNotifications.tsx
+++ b/packages/manager/src/hooks/useToastNotifications.tsx
@@ -1,220 +1,21 @@
import { useSnackbar } from 'notistack';
-import * as React from 'react';
-import { Link } from 'src/components/Link';
-import { SupportLink } from 'src/components/SupportLink';
-import { Typography } from 'src/components/Typography';
-import { sendLinodeDiskEvent } from 'src/utilities/analytics/customEventAnalytics';
+import { toasts } from 'src/features/Events/asyncToasts';
-import type { Event, EventAction } from '@linode/api-v4';
+import type { Event } from '@linode/api-v4';
export const getLabel = (event: Event) => event.entity?.label ?? '';
export const getSecondaryLabel = (event: Event) =>
event.secondary_entity?.label ?? '';
-const formatLink = (text: string, link: string, handleClick?: () => void) => {
- return (
-
- {text}
-
- );
-};
-
-interface ToastMessage {
- link?: JSX.Element;
- message: ((event: Event) => string | undefined) | string;
- persist?: boolean;
-}
-
-interface Toast {
- failure?: ToastMessage;
- /**
- * If true, the toast will be displayed with an error variant.
- */
- invertVariant?: boolean;
- success?: ToastMessage;
-}
-
-type Toasts = {
- [key in EventAction]?: Toast;
-};
-
-/**
- * This constant defines toast notifications that will be displayed
- * when our events polling system gets a new event.
- *
- * Use this feature to notify users of *asynchronous tasks* such as migrating a Linode.
- *
- * DO NOT use this feature to notify the user of tasks like changing the label of a Linode.
- * Toasts for that can be handled at the time of making the PUT request.
- */
-const toasts: Toasts = {
- backups_restore: {
- failure: {
- link: formatLink(
- 'Learn more about limits and considerations.',
- 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations'
- ),
- message: (e) => `Backup restoration failed for ${getLabel(e)}.`,
- persist: true,
- },
- },
- disk_delete: {
- failure: {
- message: (e) =>
- `Unable to delete disk ${getSecondaryLabel(e)} ${
- getLabel(e) ? ` on ${getLabel(e)}` : ''
- }. Is it attached to a configuration profile that is in use?`,
- },
- success: {
- message: (e) => `Disk ${getSecondaryLabel(e)} successfully deleted.`,
- },
- },
- disk_imagize: {
- failure: {
- link: formatLink(
- 'Learn more about image technical specifications.',
- 'https://www.linode.com/docs/products/tools/images/#technical-specifications'
- ),
- message: (e) =>
- `There was a problem creating Image ${getSecondaryLabel(e)}.`,
- persist: true,
- },
-
- success: {
- message: (e) => `Image ${getSecondaryLabel(e)} successfully created.`,
- },
- },
- disk_resize: {
- failure: {
- link: formatLink(
- 'Learn more about resizing restrictions.',
- 'https://www.linode.com/docs/products/compute/compute-instances/guides/disks-and-storage/',
- () =>
- sendLinodeDiskEvent(
- 'Resize',
- 'Click:link',
- 'Disk resize failed toast'
- )
- ),
- message: `Disk resize failed.`,
- persist: true,
- },
- success: {
- message: (e) => `Disk ${getSecondaryLabel(e)} successfully resized.`,
- },
- },
- image_delete: {
- failure: { message: (e) => `Error deleting Image ${getLabel(e)}.` },
- success: { message: (e) => `Image ${getLabel(e)} successfully deleted.` },
- },
- image_upload: {
- failure: {
- message: (e) => {
- const isDeletion = e.message === 'Upload canceled.';
-
- if (isDeletion) {
- return undefined;
- }
-
- return `There was a problem uploading image ${getLabel(
- e
- )}: ${e.message?.replace(/(\d+)/g, '$1 MB')}`;
- },
- persist: true,
- },
- success: { message: (e) => `Image ${getLabel(e)} is now available.` },
- },
- linode_clone: {
- failure: { message: (e) => `Error cloning Linode ${getLabel(e)}.` },
- success: {
- message: (e) =>
- `Linode ${getLabel(e)} successfully cloned to ${getSecondaryLabel(e)}.`,
- },
- },
- linode_migrate: {
- failure: { message: (e) => `Error migrating Linode ${getLabel(e)}.` },
- success: { message: (e) => `Linode ${getLabel(e)} successfully migrated.` },
- },
- linode_migrate_datacenter: {
- failure: { message: (e) => `Error migrating Linode ${getLabel(e)}.` },
- success: { message: (e) => `Linode ${getLabel(e)} successfully migrated.` },
- },
- linode_resize: {
- failure: { message: (e) => `Error resizing Linode ${getLabel(e)}.` },
- success: { message: (e) => `Linode ${getLabel(e)} successfully resized.` },
- },
- linode_snapshot: {
- failure: {
- link: formatLink(
- 'Learn more about limits and considerations.',
- 'https://www.linode.com/docs/products/storage/backups/#limits-and-considerations'
- ),
- message: (e) => `Snapshot backup failed on Linode ${getLabel(e)}.`,
- persist: true,
- },
- },
- longviewclient_create: {
- failure: {
- message: (e) => `Error creating Longview Client ${getLabel(e)}.`,
- },
- success: {
- message: (e) => `Longview Client ${getLabel(e)} successfully created.`,
- },
- },
- tax_id_invalid: {
- failure: { message: 'Error validating Tax Identification Number.' },
- invertVariant: true,
- success: {
- message:
- 'Tax Identification Number could not be verified. Please check your Tax ID for accuracy or contact support for assistance.',
- persist: true,
- },
- },
- volume_attach: {
- failure: { message: (e) => `Error attaching Volume ${getLabel(e)}.` },
- success: { message: (e) => `Volume ${getLabel(e)} successfully attached.` },
- },
- volume_create: {
- failure: { message: (e) => `Error creating Volume ${getLabel(e)}.` },
- success: { message: (e) => `Volume ${getLabel(e)} successfully created.` },
- },
- volume_delete: {
- failure: { message: 'Error deleting Volume.' },
- success: { message: 'Volume successfully deleted.' },
- },
- volume_detach: {
- failure: { message: (e) => `Error detaching Volume ${getLabel(e)}.` },
- success: { message: (e) => `Volume ${getLabel(e)} successfully detached.` },
- },
- volume_migrate: {
- failure: { message: (e) => `Error upgrading Volume ${getLabel(e)}.` },
- success: { message: (e) => `Volume ${getLabel(e)} successfully upgraded.` },
- },
-};
const getToastMessage = (
- toastMessage: ((event: Event) => string | undefined) | string,
+ toastMessage:
+ | ((event: Event) => JSX.Element | null | string | undefined)
+ | string,
event: Event
-): string | undefined =>
+): JSX.Element | null | string | undefined =>
typeof toastMessage === 'function' ? toastMessage(event) : toastMessage;
-const createFormattedMessage = (
- message: string | undefined,
- link: JSX.Element | undefined,
- hasSupportLink: boolean
-) => (
-
- {message?.replace(/ contact Support/i, '') ?? message}
- {hasSupportLink && (
- <>
-
- .
- >
- )}
- {link && <> {link}>}
-
-);
-
export const useToastNotifications = (): {
handleGlobalToast: (event: Event) => void;
} => {
@@ -229,41 +30,25 @@ export const useToastNotifications = (): {
const isSuccessEvent = ['finished', 'notification'].includes(event.status);
if (isSuccessEvent && toastInfo.success) {
- const { link, message, persist } = toastInfo.success;
+ const { invertVariant, message, persist } = toastInfo.success;
const successMessage = getToastMessage(message, event);
if (successMessage) {
- const formattedSuccessMessage = createFormattedMessage(
- successMessage,
- link,
- false
- );
-
- enqueueSnackbar(formattedSuccessMessage, {
+ enqueueSnackbar(successMessage, {
persist: persist ?? false,
- variant: toastInfo.invertVariant ? 'error' : 'success',
+ variant: invertVariant ? 'error' : 'success',
});
}
}
if (event.status === 'failed' && toastInfo.failure) {
- const { link, message, persist } = toastInfo.failure;
+ const { invertVariant, message, persist } = toastInfo.failure;
const failureMessage = getToastMessage(message, event);
if (failureMessage) {
- const hasSupportLink = failureMessage
- .toLowerCase()
- .includes('contact support');
-
- const formattedFailureMessage = createFormattedMessage(
- failureMessage,
- link,
- hasSupportLink
- );
-
- enqueueSnackbar(formattedFailureMessage, {
+ enqueueSnackbar(failureMessage, {
persist: persist ?? false,
- variant: toastInfo.invertVariant ? 'success' : 'error',
+ variant: invertVariant ? 'success' : 'error',
});
}
}