From 38cacc116da51e85ae1d69aafad6391d1c71f959 Mon Sep 17 00:00:00 2001
From: David Edler
Date: Fri, 19 Jan 2024 19:04:38 +0100
Subject: [PATCH] chore(notify) update react-components and react-router-dom,
fix notify.queue calls to not directly submit a notification, but to queue it
for the next page
Signed-off-by: David Edler
---
package.json | 4 +-
src/Root.tsx | 10 +-
src/pages/cluster/ClusterGroupForm.tsx | 5 +-
.../cluster/actions/DeleteClusterGroupBtn.tsx | 8 +-
src/pages/instances/InstanceDetailHeader.tsx | 4 +-
.../instances/actions/DeleteInstanceBtn.tsx | 3 +-
src/pages/networks/CreateNetwork.tsx | 4 +-
src/pages/networks/NetworkDetailHeader.tsx | 4 +-
.../networks/actions/DeleteNetworkBtn.tsx | 8 +-
src/pages/profiles/CreateProfile.tsx | 3 +-
src/pages/profiles/ProfileDetailHeader.tsx | 4 +-
.../profiles/actions/DeleteProfileBtn.tsx | 3 +-
src/pages/projects/CreateProject.tsx | 4 +-
.../projects/ProjectConfigurationHeader.tsx | 4 +-
.../projects/actions/DeleteProjectBtn.tsx | 3 +-
src/pages/storage/StoragePoolHeader.tsx | 4 +-
src/pages/storage/StorageVolumeHeader.tsx | 4 +-
src/pages/storage/StorageVolumeSnapshots.tsx | 23 +---
.../storage/actions/DeleteStoragePoolBtn.tsx | 3 +-
.../snapshots/VolumeConfigureSnapshotBtn.tsx | 13 +-
.../VolumeConfigureSnapshotModal.tsx | 16 +--
.../snapshots/VolumeSnapshotActions.tsx | 25 ++--
.../snapshots/VolumeSnapshotBulkDelete.tsx | 19 +--
.../forms/CreateVolumeSnapshotForm.tsx | 2 +-
.../storage/forms/EditVolumeSnapshotForm.tsx | 2 +-
yarn.lock | 119 ++++++++----------
26 files changed, 136 insertions(+), 165 deletions(-)
diff --git a/package.json b/package.json
index d5fe2ccad4..210594ccc7 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"serve": "./entrypoint",
"test-js": "react-scripts test src/ --watchAll=false"},
"dependencies": {
- "@canonical/react-components": "0.47.1",
+ "@canonical/react-components": "0.47.3",
"@monaco-editor/react": "4.6.0",
"@tanstack/react-query": "5.17.15",
"@use-it/event-listener": "0.1.7",
@@ -36,7 +36,7 @@
"react": "18.2.0",
"react-cytoscapejs": "2.0.0",
"react-dom": "18.2.0",
- "react-router-dom": "6.17.0",
+ "react-router-dom": "6.21.3",
"react-scripts": "5.0.1",
"react-useportal": "1.0.19",
"serve": "14.2.1",
diff --git a/src/Root.tsx b/src/Root.tsx
index e99a8776ef..532edf715a 100644
--- a/src/Root.tsx
+++ b/src/Root.tsx
@@ -1,6 +1,9 @@
import React, { FC } from "react";
import Navigation from "components/Navigation";
-import { NotificationProvider } from "@canonical/react-components";
+import {
+ NotificationProvider,
+ QueuedNotification,
+} from "@canonical/react-components";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import Panels from "components/Panels";
import { AuthProvider } from "context/auth";
@@ -11,13 +14,16 @@ import Events from "pages/instances/Events";
import App from "./App";
import ErrorBoundary from "components/ErrorBoundary";
import ErrorPage from "components/ErrorPage";
+import { useLocation } from "react-router-dom";
const queryClient = new QueryClient();
const Root: FC = () => {
+ const location = useLocation() as QueuedNotification;
+
return (
-
+
diff --git a/src/pages/cluster/ClusterGroupForm.tsx b/src/pages/cluster/ClusterGroupForm.tsx
index 42a974518a..81d79c2eb3 100644
--- a/src/pages/cluster/ClusterGroupForm.tsx
+++ b/src/pages/cluster/ClusterGroupForm.tsx
@@ -5,6 +5,7 @@ import {
Form,
Input,
Row,
+ success,
useNotify,
} from "@canonical/react-components";
import { useQuery, useQueryClient } from "@tanstack/react-query";
@@ -84,9 +85,7 @@ const ClusterGroupForm: FC = ({ group }) => {
const verb = group ? "saved" : "created";
navigate(
`/ui/cluster/groups/detail/${values.name}`,
- notify.queue(
- notify.success(`Cluster group ${values.name} ${verb}.`),
- ),
+ notify.queue(success(`Cluster group ${values.name} ${verb}.`)),
);
})
.catch((e: Error) => {
diff --git a/src/pages/cluster/actions/DeleteClusterGroupBtn.tsx b/src/pages/cluster/actions/DeleteClusterGroupBtn.tsx
index 1decd5c28b..23203bcb89 100644
--- a/src/pages/cluster/actions/DeleteClusterGroupBtn.tsx
+++ b/src/pages/cluster/actions/DeleteClusterGroupBtn.tsx
@@ -4,7 +4,11 @@ import ItemName from "components/ItemName";
import { deleteClusterGroup } from "api/cluster";
import { queryKeys } from "util/queryKeys";
import { useQueryClient } from "@tanstack/react-query";
-import { ConfirmationButton, useNotify } from "@canonical/react-components";
+import {
+ ConfirmationButton,
+ success,
+ useNotify,
+} from "@canonical/react-components";
interface Props {
group: string;
@@ -22,7 +26,7 @@ const DeleteClusterGroupBtn: FC = ({ group }) => {
.then(() => {
navigate(
`/ui/cluster`,
- notify.queue(notify.success(`Cluster group ${group} deleted.`)),
+ notify.queue(success(`Cluster group ${group} deleted.`)),
);
})
.catch((e) => {
diff --git a/src/pages/instances/InstanceDetailHeader.tsx b/src/pages/instances/InstanceDetailHeader.tsx
index ada6116a65..5e7c644c5c 100644
--- a/src/pages/instances/InstanceDetailHeader.tsx
+++ b/src/pages/instances/InstanceDetailHeader.tsx
@@ -8,7 +8,7 @@ import InstanceStateActions from "pages/instances/actions/InstanceStateActions";
import { useFormik } from "formik";
import * as Yup from "yup";
import { checkDuplicateName } from "util/helpers";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
import { useEventQueue } from "context/eventQueue";
interface Props {
@@ -59,7 +59,7 @@ const InstanceDetailHeader: FC = ({ name, instance, project }) => {
() => {
navigate(
`/ui/project/${project}/instances/detail/${values.name}`,
- notify.queue(notify.success("Instance renamed.")),
+ notify.queue(success("Instance renamed.")),
);
void formik.setFieldValue("isRenaming", false);
},
diff --git a/src/pages/instances/actions/DeleteInstanceBtn.tsx b/src/pages/instances/actions/DeleteInstanceBtn.tsx
index d377c8b7b4..819814cf99 100644
--- a/src/pages/instances/actions/DeleteInstanceBtn.tsx
+++ b/src/pages/instances/actions/DeleteInstanceBtn.tsx
@@ -8,6 +8,7 @@ import { useDeleteIcon } from "context/useDeleteIcon";
import {
ConfirmationButton,
Icon,
+ success,
useNotify,
} from "@canonical/react-components";
import classnames from "classnames";
@@ -38,7 +39,7 @@ const DeleteInstanceBtn: FC = ({ instance }) => {
});
navigate(
`/ui/project/${instance.project}/instances`,
- notify.queue(notify.success(`Instance ${instance.name} deleted.`)),
+ notify.queue(success(`Instance ${instance.name} deleted.`)),
);
},
(msg) =>
diff --git a/src/pages/networks/CreateNetwork.tsx b/src/pages/networks/CreateNetwork.tsx
index 6b7410b2d3..8a6dc55620 100644
--- a/src/pages/networks/CreateNetwork.tsx
+++ b/src/pages/networks/CreateNetwork.tsx
@@ -1,5 +1,5 @@
import React, { FC, useState } from "react";
-import { Button, useNotify } from "@canonical/react-components";
+import { Button, success, useNotify } from "@canonical/react-components";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useQuery, useQueryClient } from "@tanstack/react-query";
@@ -91,7 +91,7 @@ const CreateNetwork: FC = () => {
});
navigate(
`/ui/project/${project}/networks`,
- notify.queue(notify.success(`Network ${values.name} created.`)),
+ notify.queue(success(`Network ${values.name} created.`)),
);
})
.catch((e) => {
diff --git a/src/pages/networks/NetworkDetailHeader.tsx b/src/pages/networks/NetworkDetailHeader.tsx
index d62ae45d98..e34ebac12a 100644
--- a/src/pages/networks/NetworkDetailHeader.tsx
+++ b/src/pages/networks/NetworkDetailHeader.tsx
@@ -7,7 +7,7 @@ import { checkDuplicateName } from "util/helpers";
import { LxdNetwork } from "types/network";
import { renameNetwork } from "api/networks";
import DeleteNetworkBtn from "pages/networks/actions/DeleteNetworkBtn";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
interface Props {
name: string;
@@ -48,7 +48,7 @@ const NetworkDetailHeader: FC = ({ name, network, project }) => {
.then(() => {
navigate(
`/ui/project/${project}/networks/detail/${values.name}`,
- notify.queue(notify.success("Network renamed.")),
+ notify.queue(success("Network renamed.")),
);
void formik.setFieldValue("isRenaming", false);
})
diff --git a/src/pages/networks/actions/DeleteNetworkBtn.tsx b/src/pages/networks/actions/DeleteNetworkBtn.tsx
index c8b7ce2727..ad863dcf40 100644
--- a/src/pages/networks/actions/DeleteNetworkBtn.tsx
+++ b/src/pages/networks/actions/DeleteNetworkBtn.tsx
@@ -5,7 +5,11 @@ import { LxdNetwork } from "types/network";
import { deleteNetwork } from "api/networks";
import { queryKeys } from "util/queryKeys";
import { useQueryClient } from "@tanstack/react-query";
-import { ConfirmationButton, useNotify } from "@canonical/react-components";
+import {
+ ConfirmationButton,
+ success,
+ useNotify,
+} from "@canonical/react-components";
interface Props {
network: LxdNetwork;
@@ -30,7 +34,7 @@ const DeleteNetworkBtn: FC = ({ network, project }) => {
});
navigate(
`/ui/project/${project}/networks`,
- notify.queue(notify.success(`Network ${network.name} deleted.`)),
+ notify.queue(success(`Network ${network.name} deleted.`)),
);
})
.catch((e) => {
diff --git a/src/pages/profiles/CreateProfile.tsx b/src/pages/profiles/CreateProfile.tsx
index 0babba1445..952d6d0c2b 100644
--- a/src/pages/profiles/CreateProfile.tsx
+++ b/src/pages/profiles/CreateProfile.tsx
@@ -5,6 +5,7 @@ import {
Form,
Notification,
Row,
+ success,
useNotify,
} from "@canonical/react-components";
import { useFormik } from "formik";
@@ -110,7 +111,7 @@ const CreateProfile: FC = () => {
.then(() => {
navigate(
`/ui/project/${project}/profiles`,
- notify.queue(notify.success(`Profile ${values.name} created.`)),
+ notify.queue(success(`Profile ${values.name} created.`)),
);
})
.catch((e: Error) => {
diff --git a/src/pages/profiles/ProfileDetailHeader.tsx b/src/pages/profiles/ProfileDetailHeader.tsx
index e66df63951..c6e6333485 100644
--- a/src/pages/profiles/ProfileDetailHeader.tsx
+++ b/src/pages/profiles/ProfileDetailHeader.tsx
@@ -7,7 +7,7 @@ import { renameProfile } from "api/profiles";
import { useFormik } from "formik";
import * as Yup from "yup";
import { checkDuplicateName } from "util/helpers";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
interface Props {
name: string;
@@ -54,7 +54,7 @@ const ProfileDetailHeader: FC = ({
.then(() => {
navigate(
`/ui/project/${project}/profiles/detail/${values.name}`,
- notify.queue(notify.success("Profile renamed.")),
+ notify.queue(success("Profile renamed.")),
);
void formik.setFieldValue("isRenaming", false);
})
diff --git a/src/pages/profiles/actions/DeleteProfileBtn.tsx b/src/pages/profiles/actions/DeleteProfileBtn.tsx
index 123658f5b2..0218e8f474 100644
--- a/src/pages/profiles/actions/DeleteProfileBtn.tsx
+++ b/src/pages/profiles/actions/DeleteProfileBtn.tsx
@@ -7,6 +7,7 @@ import { useDeleteIcon } from "context/useDeleteIcon";
import {
ConfirmationButton,
Icon,
+ success,
useNotify,
} from "@canonical/react-components";
import classnames from "classnames";
@@ -39,7 +40,7 @@ const DeleteProfileBtn: FC = ({
});
navigate(
`/ui/project/${project}/profiles`,
- notify.queue(notify.success(`Profile ${profile.name} deleted.`)),
+ notify.queue(success(`Profile ${profile.name} deleted.`)),
);
})
.catch((e) => {
diff --git a/src/pages/projects/CreateProject.tsx b/src/pages/projects/CreateProject.tsx
index 0a921be3a6..38ccc46305 100644
--- a/src/pages/projects/CreateProject.tsx
+++ b/src/pages/projects/CreateProject.tsx
@@ -1,5 +1,5 @@
import React, { FC, useEffect, useState } from "react";
-import { Button, useNotify } from "@canonical/react-components";
+import { Button, success, useNotify } from "@canonical/react-components";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useQueryClient } from "@tanstack/react-query";
@@ -99,7 +99,7 @@ const CreateProject: FC = () => {
.then(() => {
navigate(
`/ui/project/${values.name}/instances`,
- notify.queue(notify.success(`Project ${values.name} created.`)),
+ notify.queue(success(`Project ${values.name} created.`)),
);
})
.catch((e: Error) => {
diff --git a/src/pages/projects/ProjectConfigurationHeader.tsx b/src/pages/projects/ProjectConfigurationHeader.tsx
index 8648f427e5..83938960d4 100644
--- a/src/pages/projects/ProjectConfigurationHeader.tsx
+++ b/src/pages/projects/ProjectConfigurationHeader.tsx
@@ -7,7 +7,7 @@ import * as Yup from "yup";
import { useFormik } from "formik";
import { checkDuplicateName } from "util/helpers";
import DeleteProjectBtn from "./actions/DeleteProjectBtn";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
import HelpLink from "components/HelpLink";
import { useEventQueue } from "context/eventQueue";
import { useDocs } from "context/useDocs";
@@ -53,7 +53,7 @@ const ProjectConfigurationHeader: FC = ({ project }) => {
() => {
navigate(
`/ui/project/${values.name}/configuration`,
- notify.queue(notify.success("Project renamed.")),
+ notify.queue(success("Project renamed.")),
);
void formik.setFieldValue("isRenaming", false);
},
diff --git a/src/pages/projects/actions/DeleteProjectBtn.tsx b/src/pages/projects/actions/DeleteProjectBtn.tsx
index 4ccdd1d3c8..f42ba7622a 100644
--- a/src/pages/projects/actions/DeleteProjectBtn.tsx
+++ b/src/pages/projects/actions/DeleteProjectBtn.tsx
@@ -10,6 +10,7 @@ import { useDeleteIcon } from "context/useDeleteIcon";
import {
ConfirmationButton,
Icon,
+ success,
useNotify,
} from "@canonical/react-components";
import classnames from "classnames";
@@ -43,7 +44,7 @@ const DeleteProjectBtn: FC = ({ project }) => {
.then(() => {
navigate(
`/ui/project/default/instances`,
- notify.queue(notify.success(`Project ${project.name} deleted.`)),
+ notify.queue(success(`Project ${project.name} deleted.`)),
);
})
.catch((e) => {
diff --git a/src/pages/storage/StoragePoolHeader.tsx b/src/pages/storage/StoragePoolHeader.tsx
index 8b55fa502e..f5cff1f891 100644
--- a/src/pages/storage/StoragePoolHeader.tsx
+++ b/src/pages/storage/StoragePoolHeader.tsx
@@ -7,7 +7,7 @@ import { LxdStoragePool } from "types/storage";
import { renameStoragePool } from "api/storage-pools";
import DeleteStoragePoolBtn from "pages/storage/actions/DeleteStoragePoolBtn";
import { testDuplicateStoragePoolName } from "util/storagePool";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
interface Props {
name: string;
@@ -42,7 +42,7 @@ const StoragePoolHeader: FC = ({ name, pool, project }) => {
.then(() => {
navigate(
`/ui/project/${project}/storage/detail/${values.name}`,
- notify.queue(notify.success("Storage pool renamed.")),
+ notify.queue(success("Storage pool renamed.")),
);
void formik.setFieldValue("isRenaming", false);
})
diff --git a/src/pages/storage/StorageVolumeHeader.tsx b/src/pages/storage/StorageVolumeHeader.tsx
index b1e790c96c..3ff487e853 100644
--- a/src/pages/storage/StorageVolumeHeader.tsx
+++ b/src/pages/storage/StorageVolumeHeader.tsx
@@ -6,7 +6,7 @@ import * as Yup from "yup";
import { LxdStorageVolume } from "types/storage";
import { renameStorageVolume } from "api/storage-pools";
import { testDuplicateStorageVolumeName } from "util/storageVolume";
-import { useNotify } from "@canonical/react-components";
+import { success, useNotify } from "@canonical/react-components";
import DeleteStorageVolumeBtn from "pages/storage/actions/DeleteStorageVolumeBtn";
interface Props {
@@ -49,7 +49,7 @@ const StorageVolumeHeader: FC = ({ volume, project }) => {
.then(() => {
navigate(
`/ui/project/${project}/storage/detail/${volume.pool}/${volume.type}/${values.name}`,
- notify.queue(notify.success("Storage volume renamed.")),
+ notify.queue(success("Storage volume renamed.")),
);
void formik.setFieldValue("isRenaming", false);
})
diff --git a/src/pages/storage/StorageVolumeSnapshots.tsx b/src/pages/storage/StorageVolumeSnapshots.tsx
index d30d983616..2af0d86c40 100644
--- a/src/pages/storage/StorageVolumeSnapshots.tsx
+++ b/src/pages/storage/StorageVolumeSnapshots.tsx
@@ -1,4 +1,4 @@
-import React, { FC, ReactNode, useEffect, useState } from "react";
+import React, { FC, useEffect, useState } from "react";
import {
EmptyState,
Icon,
@@ -62,14 +62,6 @@ const StorageVolumeSnapshots: FC = ({ volume }) => {
}),
});
- const onSuccess = (message: string) => {
- notify.queue(notify.success(message));
- };
-
- const onFailure = (title: string, error: unknown, message?: ReactNode) => {
- notify.failure(title, error, message);
- };
-
const snapshotsDisabled = isSnapshotsDisabled(project);
useEffect(() => {
@@ -129,12 +121,7 @@ const StorageVolumeSnapshots: FC = ({ volume }) => {
const rows = filteredSnapshots.map((snapshot) => {
const actions = (
-
+
);
return {
@@ -227,8 +214,6 @@ const StorageVolumeSnapshots: FC = ({ volume }) => {
= ({ volume }) => {
snapshotNames={selectedNames}
onStart={() => setProcessingNames(selectedNames)}
onFinish={() => setProcessingNames([])}
- onSuccess={onSuccess}
- onFailure={onFailure}
/>
)}
@@ -323,8 +306,6 @@ const StorageVolumeSnapshots: FC = ({ volume }) => {
= ({
});
navigate(
`/ui/project/${project}/storage`,
- notify.queue(notify.success(`Storage pool ${pool.name} deleted.`)),
+ notify.queue(success(`Storage pool ${pool.name} deleted.`)),
);
})
.catch((e) => {
diff --git a/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotBtn.tsx b/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotBtn.tsx
index 14d05d2b84..cd212fc08f 100644
--- a/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotBtn.tsx
+++ b/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotBtn.tsx
@@ -1,4 +1,4 @@
-import React, { FC, ReactNode } from "react";
+import React, { FC } from "react";
import usePortal from "react-useportal";
import { Button } from "@canonical/react-components";
import VolumeConfigureSnapshotModal from "./VolumeConfigureSnapshotModal";
@@ -6,16 +6,12 @@ import { LxdStorageVolume } from "types/storage";
interface Props {
volume: LxdStorageVolume;
- onSuccess: (message: string) => void;
- onFailure: (title: string, e: unknown, message?: ReactNode) => void;
isDisabled?: boolean;
className?: string;
}
const VolumeConfigureSnapshotBtn: FC = ({
volume,
- onSuccess,
- onFailure,
isDisabled,
className,
}) => {
@@ -26,12 +22,7 @@ const VolumeConfigureSnapshotBtn: FC = ({
{isOpen && (
-
+
)}
diff --git a/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotModal.tsx b/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotModal.tsx
index 892ef84afe..f1c2626664 100644
--- a/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotModal.tsx
+++ b/src/pages/storage/actions/snapshots/VolumeConfigureSnapshotModal.tsx
@@ -1,5 +1,5 @@
import React, { FC, KeyboardEvent } from "react";
-import { Button, Modal } from "@canonical/react-components";
+import { Button, Modal, useNotify } from "@canonical/react-components";
import { useFormik } from "formik";
import { queryKeys } from "util/queryKeys";
import { useQueryClient } from "@tanstack/react-query";
@@ -16,16 +16,10 @@ import StorageVolumeFormSnapshots from "pages/storage/forms/StorageVolumeFormSna
interface Props {
volume: LxdStorageVolume;
close: () => void;
- onSuccess: (message: string) => void;
- onFailure: (title: string, e: unknown) => void;
}
-const VolumeConfigureSnapshotModal: FC = ({
- volume,
- close,
- onSuccess,
- onFailure,
-}) => {
+const VolumeConfigureSnapshotModal: FC = ({ volume, close }) => {
+ const notify = useNotify();
const queryClient = useQueryClient();
const formik = useFormik({
@@ -37,7 +31,7 @@ const VolumeConfigureSnapshotModal: FC = ({
etag: volume.etag,
})
.then(() => {
- onSuccess("Configuration updated.");
+ notify.success("Configuration updated.");
void queryClient.invalidateQueries({
queryKey: [queryKeys.storage],
predicate: (query) =>
@@ -46,7 +40,7 @@ const VolumeConfigureSnapshotModal: FC = ({
});
})
.catch((e: Error) => {
- onFailure("Configuration update failed", e);
+ notify.failure("Configuration update failed", e);
})
.finally(() => {
close();
diff --git a/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx b/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx
index 083b602a40..016a912e8e 100644
--- a/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx
+++ b/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx
@@ -6,7 +6,12 @@ import {
} from "api/volume-snapshots";
import { useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
-import { ConfirmationButton, Icon, List } from "@canonical/react-components";
+import {
+ ConfirmationButton,
+ Icon,
+ List,
+ useNotify,
+} from "@canonical/react-components";
import classnames from "classnames";
import ItemName from "components/ItemName";
import { useEventQueue } from "context/eventQueue";
@@ -15,17 +20,11 @@ import VolumeEditSnapshotBtn from "./VolumeEditSnapshotBtn";
interface Props {
volume: LxdStorageVolume;
snapshot: LxdVolumeSnapshot;
- onSuccess: (message: string) => void;
- onFailure: (title: string, error: Error) => void;
}
-const VolumeSnapshotActions: FC = ({
- volume,
- snapshot,
- onSuccess,
- onFailure,
-}) => {
+const VolumeSnapshotActions: FC = ({ volume, snapshot }) => {
const eventQueue = useEventQueue();
+ const notify = useNotify();
const [isDeleting, setDeleting] = useState(false);
const [isRestoring, setRestoring] = useState(false);
const queryClient = useQueryClient();
@@ -35,8 +34,8 @@ const VolumeSnapshotActions: FC = ({
void deleteVolumeSnapshot(volume, snapshot).then((operation) =>
eventQueue.set(
operation.metadata.id,
- () => onSuccess(`Snapshot ${snapshot.name} deleted`),
- (msg) => onFailure("Snapshot deletion failed", new Error(msg)),
+ () => notify.success(`Snapshot ${snapshot.name} deleted`),
+ (msg) => notify.failure("Snapshot deletion failed", new Error(msg)),
() => {
setDeleting(false);
void queryClient.invalidateQueries({
@@ -53,10 +52,10 @@ const VolumeSnapshotActions: FC = ({
setRestoring(true);
void restoreVolumeSnapshot(volume, snapshot)
.then(() => {
- onSuccess(`Snapshot ${snapshot.name} restored`);
+ notify.success(`Snapshot ${snapshot.name} restored`);
})
.catch((error: Error) => {
- onFailure("Snapshot restore failed", error);
+ notify.failure("Snapshot restore failed", error);
})
.finally(() => {
setRestoring(false);
diff --git a/src/pages/storage/actions/snapshots/VolumeSnapshotBulkDelete.tsx b/src/pages/storage/actions/snapshots/VolumeSnapshotBulkDelete.tsx
index f3e3951c40..5cbc1b3ea2 100644
--- a/src/pages/storage/actions/snapshots/VolumeSnapshotBulkDelete.tsx
+++ b/src/pages/storage/actions/snapshots/VolumeSnapshotBulkDelete.tsx
@@ -1,9 +1,13 @@
-import React, { FC, ReactNode, useState } from "react";
+import React, { FC, useState } from "react";
import { deleteVolumeSnapshotBulk } from "api/volume-snapshots";
import { useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
import { pluralizeSnapshot } from "util/instanceBulkActions";
-import { ConfirmationButton, Icon } from "@canonical/react-components";
+import {
+ ConfirmationButton,
+ Icon,
+ useNotify,
+} from "@canonical/react-components";
import classnames from "classnames";
import { useEventQueue } from "context/eventQueue";
import { getPromiseSettledCounts } from "util/helpers";
@@ -14,8 +18,6 @@ interface Props {
snapshotNames: string[];
onStart: () => void;
onFinish: () => void;
- onSuccess: (message: string) => void;
- onFailure: (title: string, e: unknown, message?: ReactNode) => void;
}
const VolumeSnapshotBulkDelete: FC = ({
@@ -23,10 +25,9 @@ const VolumeSnapshotBulkDelete: FC = ({
snapshotNames,
onStart,
onFinish,
- onSuccess,
- onFailure,
}) => {
const eventQueue = useEventQueue();
+ const notify = useNotify();
const [isLoading, setLoading] = useState(false);
const queryClient = useQueryClient();
@@ -40,13 +41,13 @@ const VolumeSnapshotBulkDelete: FC = ({
const { fulfilledCount, rejectedCount } =
getPromiseSettledCounts(results);
if (fulfilledCount === count) {
- onSuccess(
+ notify.success(
`${snapshotNames.length} ${pluralizeSnapshot(
snapshotNames.length,
)} deleted`,
);
} else if (rejectedCount === count) {
- onFailure(
+ notify.failure(
"Snapshot bulk deletion failed",
undefined,
<>
@@ -54,7 +55,7 @@ const VolumeSnapshotBulkDelete: FC = ({
>,
);
} else {
- onFailure(
+ notify.failure(
"Snapshot bulk deletion partially failed",
undefined,
<>
diff --git a/src/pages/storage/forms/CreateVolumeSnapshotForm.tsx b/src/pages/storage/forms/CreateVolumeSnapshotForm.tsx
index 840b0e15fd..b7c97423b1 100644
--- a/src/pages/storage/forms/CreateVolumeSnapshotForm.tsx
+++ b/src/pages/storage/forms/CreateVolumeSnapshotForm.tsx
@@ -53,7 +53,7 @@ const CreateVolumeSnapshotForm: FC = ({ close, volume }) => {
query.queryKey[0] === queryKeys.volumes ||
query.queryKey[0] === queryKeys.storage,
});
- notify.queue(notify.success(`Snapshot ${values.name} created.`));
+ notify.success(`Snapshot ${values.name} created.`);
close();
resetForm();
},
diff --git a/src/pages/storage/forms/EditVolumeSnapshotForm.tsx b/src/pages/storage/forms/EditVolumeSnapshotForm.tsx
index 0e3b2709e3..043691e4e4 100644
--- a/src/pages/storage/forms/EditVolumeSnapshotForm.tsx
+++ b/src/pages/storage/forms/EditVolumeSnapshotForm.tsx
@@ -33,7 +33,7 @@ const EditVolumeSnapshotForm: FC = ({ volume, snapshot, close }) => {
query.queryKey[0] === queryKeys.volumes ||
query.queryKey[0] === queryKeys.storage,
});
- notify.queue(notify.success(`Snapshot ${name} saved.`));
+ notify.success(`Snapshot ${name} saved.`);
formik.setSubmitting(false);
close();
};
diff --git a/yarn.lock b/yarn.lock
index bc5f3cfbdc..d7d021984a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2086,22 +2086,21 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@canonical/react-components@0.47.1":
- version "0.47.1"
- resolved "https://registry.yarnpkg.com/@canonical/react-components/-/react-components-0.47.1.tgz#4f870b47f688d06f0c9a018dc13c167479b3abd6"
- integrity sha512-Uue9LyUQH5OLB8FcOccDpnlLYqxlXO3WT6ibKIs8oSxn+EUNI6xXKLljawnZGf7dtMiSdrv4ieaeYQmnV5mtlg==
+"@canonical/react-components@0.47.3":
+ version "0.47.3"
+ resolved "https://registry.yarnpkg.com/@canonical/react-components/-/react-components-0.47.3.tgz#9937e14f44583e5662561b5bfe63d96fba5a7fe0"
+ integrity sha512-M58N593Qc+AsOfgmwU205VEvdu9zBIQEhTs2YgTeshfLMx5MICTh2NhKBYCsWjgRTANaagAJJgdTovKawzgWcQ==
dependencies:
"@types/jest" "27.5.2"
- "@types/node" "18.18.5"
- "@types/react" "18.2.28"
- "@types/react-dom" "18.2.13"
- "@types/react-table" "7.7.16"
- classnames "2.3.2"
- nanoid "3.3.6"
+ "@types/node" "18.19.4"
+ "@types/react" "18.2.46"
+ "@types/react-dom" "18.2.18"
+ "@types/react-table" "7.7.19"
+ classnames "2.5.1"
+ nanoid "3.3.7"
prop-types "15.8.1"
- react-router-dom "6.17.0"
react-table "7.8.0"
- react-useportal "1.0.18"
+ react-useportal "1.0.19"
"@csstools/css-parser-algorithms@^2.4.0":
version "2.5.0"
@@ -2811,10 +2810,10 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
-"@remix-run/router@1.10.0":
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.10.0.tgz#e2170dc2049b06e65bbe883adad0e8ddf8291278"
- integrity sha512-Lm+fYpMfZoEucJ7cMxgt4dYt8jLfbpwRCzAjm9UgSLOkmlqo9gupxt6YX3DY0Fk155NT9l17d/ydi+964uS9Lw==
+"@remix-run/router@1.14.2":
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.14.2.tgz#4d58f59908d9197ba3179310077f25c88e49ed17"
+ integrity sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==
"@rollup/plugin-babel@^5.2.0":
version "5.3.1"
@@ -3245,10 +3244,12 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014"
integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==
-"@types/node@18.18.5":
- version "18.18.5"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.5.tgz#afc0fd975df946d6e1add5bbf98264225b212244"
- integrity sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A==
+"@types/node@18.19.4":
+ version "18.19.4"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.4.tgz#89672e84f11a2c19543d694dac00ab8d7bc20ddb"
+ integrity sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==
+ dependencies:
+ undici-types "~5.26.4"
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -3288,13 +3289,6 @@
"@types/cytoscape" "*"
"@types/react" "*"
-"@types/react-dom@18.2.13":
- version "18.2.13"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.13.tgz#89cd7f9ec8b28c8b6f0392b9591671fb4a9e96b7"
- integrity sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw==
- dependencies:
- "@types/react" "*"
-
"@types/react-dom@18.2.18":
version "18.2.18"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
@@ -3319,10 +3313,10 @@
"@types/history" "^4.7.11"
"@types/react" "*"
-"@types/react-table@7.7.16":
- version "7.7.16"
- resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.7.16.tgz#e143e2c0fa2dcac739fcc8055e58f5a7a9c0e5fb"
- integrity sha512-khfVwkNkvFnQV+Dx5Z/4jeMWIi+qytR8/Hl89fMPQ3aGiIgVlnghwdnyrq45UVSU+9wTqQFL0kUmIk4MGaM20Q==
+"@types/react-table@7.7.19":
+ version "7.7.19"
+ resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.7.19.tgz#5175cb52a7df9e0234a67bdbdfe592738c92c862"
+ integrity sha512-47jMa1Pai7ily6BXJCW33IL5ghqmCWs2VM9s+h1D4mCaK5P4uNkZOW3RMMg8MCXBvAJ0v9+sPqKjhid0PaJPQA==
dependencies:
"@types/react" "*"
@@ -3335,10 +3329,10 @@
"@types/scheduler" "*"
csstype "^3.0.2"
-"@types/react@18.2.28":
- version "18.2.28"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.28.tgz#86877465c0fcf751659a36c769ecedfcfacee332"
- integrity sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==
+"@types/react@18.2.46":
+ version "18.2.46"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.46.tgz#f04d6c528f8f136ea66333bc66abcae46e2680df"
+ integrity sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -4779,10 +4773,10 @@ cjs-module-lexer@^1.0.0:
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
-classnames@2.3.2:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
- integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
+classnames@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
+ integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
clean-css@^5.2.2:
version "5.3.2"
@@ -8828,21 +8822,16 @@ multicast-dns@^7.2.5:
dns-packet "^5.2.2"
thunky "^1.0.2"
-nanoid@3.3.6:
- version "3.3.6"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
- integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
+nanoid@3.3.7, nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-nanoid@^3.3.7:
- version "3.3.7"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
- integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
-
natural-compare-lite@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
@@ -10297,20 +10286,20 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
-react-router-dom@6.17.0:
- version "6.17.0"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.17.0.tgz#ea73f89186546c1cf72b10fcb7356d874321b2ad"
- integrity sha512-qWHkkbXQX+6li0COUUPKAUkxjNNqPJuiBd27dVwQGDNsuFBdMbrS6UZ0CLYc4CsbdLYTckn4oB4tGDuPZpPhaQ==
+react-router-dom@6.21.3:
+ version "6.21.3"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.21.3.tgz#ef3a7956a3699c7b82c21fcb3dbc63c313ed8c5d"
+ integrity sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==
dependencies:
- "@remix-run/router" "1.10.0"
- react-router "6.17.0"
+ "@remix-run/router" "1.14.2"
+ react-router "6.21.3"
-react-router@6.17.0:
- version "6.17.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.17.0.tgz#7b680c4cefbc425b57537eb9c73bedecbdc67c1e"
- integrity sha512-YJR3OTJzi3zhqeJYADHANCGPUu9J+6fT5GLv82UWRGSxu6oJYCKVmxUcaBQuGm9udpWmPsvpme/CdHumqgsoaA==
+react-router@6.21.3:
+ version "6.21.3"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.21.3.tgz#8086cea922c2bfebbb49c6594967418f1f167d70"
+ integrity sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==
dependencies:
- "@remix-run/router" "1.10.0"
+ "@remix-run/router" "1.14.2"
react-scripts@5.0.1:
version "5.0.1"
@@ -10372,13 +10361,6 @@ react-table@7.8.0:
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2"
integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==
-react-useportal@1.0.18:
- version "1.0.18"
- resolved "https://registry.yarnpkg.com/react-useportal/-/react-useportal-1.0.18.tgz#b3baf14962f44402b2d0d6152acc2035c5342bd8"
- integrity sha512-dGuT/yyE2T9RtUxRZJYkIX8tLHC7KxAxbMw/Ufjiwo8ixoDYzkk9LFKGnARtCtFz6Yd5AoP7fVymrN3eT04jiA==
- dependencies:
- use-ssr "^1.0.25"
-
react-useportal@1.0.19:
version "1.0.19"
resolved "https://registry.yarnpkg.com/react-useportal/-/react-useportal-1.0.19.tgz#473168f1a1c4009833d49a46b05d974a5850a166"
@@ -11991,6 +11973,11 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"