diff --git a/src/api/images.tsx b/src/api/images.tsx index 390223b596..dba20b2db7 100644 --- a/src/api/images.tsx +++ b/src/api/images.tsx @@ -54,14 +54,19 @@ export const deleteImageBulk = ( void Promise.allSettled( fingerprints.map((name) => { const image = { fingerprint: name } as LxdImage; - return deleteImage(image, project).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => pushSuccess(results), - (msg) => pushFailure(results, msg), - () => continueOrFinish(results, fingerprints.length, resolve), - ); - }); + return deleteImage(image, project) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => pushSuccess(results), + (msg) => pushFailure(results, msg), + () => continueOrFinish(results, fingerprints.length, resolve), + ); + }) + .catch((e) => { + pushFailure(results, e instanceof Error ? e.message : ""); + continueOrFinish(results, fingerprints.length, resolve); + }); }), ); }); diff --git a/src/api/instance-snapshots.tsx b/src/api/instance-snapshots.tsx index 66b91a944a..b4fdda3b86 100644 --- a/src/api/instance-snapshots.tsx +++ b/src/api/instance-snapshots.tsx @@ -58,16 +58,19 @@ export const deleteInstanceSnapshotBulk = ( return new Promise((resolve) => { void Promise.allSettled( snapshotNames.map(async (name) => { - return await deleteInstanceSnapshot(instance, { name }).then( - (operation) => { + return await deleteInstanceSnapshot(instance, { name }) + .then((operation) => { eventQueue.set( operation.metadata.id, () => pushSuccess(results), (msg) => pushFailure(results, msg), () => continueOrFinish(results, snapshotNames.length, resolve), ); - }, - ); + }) + .catch((e) => { + pushFailure(results, e instanceof Error ? e.message : ""); + continueOrFinish(results, snapshotNames.length, resolve); + }); }), ); }); diff --git a/src/api/instances.tsx b/src/api/instances.tsx index d4997666fd..13cc0e43b8 100644 --- a/src/api/instances.tsx +++ b/src/api/instances.tsx @@ -171,16 +171,19 @@ export const updateInstanceBulkAction = ( return new Promise((resolve) => { void Promise.allSettled( actions.map(async ({ name, project, action }) => { - return await putInstanceAction(name, project, action, isForce).then( - (operation) => { + return await putInstanceAction(name, project, action, isForce) + .then((operation) => { eventQueue.set( operation.metadata.id, () => pushSuccess(results), (msg) => pushFailure(results, msg), () => continueOrFinish(results, actions.length, resolve), ); - }, - ); + }) + .catch((e) => { + pushFailure(results, e instanceof Error ? e.message : ""); + continueOrFinish(results, actions.length, resolve); + }); }), ); }); @@ -207,14 +210,19 @@ export const deleteInstanceBulk = ( return new Promise((resolve) => { void Promise.allSettled( instances.map(async (instance) => { - return await deleteInstance(instance).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => pushSuccess(results), - (msg) => pushFailure(results, msg), - () => continueOrFinish(results, instances.length, resolve), - ); - }); + return await deleteInstance(instance) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => pushSuccess(results), + (msg) => pushFailure(results, msg), + () => continueOrFinish(results, instances.length, resolve), + ); + }) + .catch((e) => { + pushFailure(results, e instanceof Error ? e.message : ""); + continueOrFinish(results, instances.length, resolve); + }); }), ); }); diff --git a/src/api/volume-snapshots.tsx b/src/api/volume-snapshots.tsx index e8051d6717..34dabdffae 100644 --- a/src/api/volume-snapshots.tsx +++ b/src/api/volume-snapshots.tsx @@ -59,16 +59,19 @@ export const deleteVolumeSnapshotBulk = ( return new Promise((resolve) => { void Promise.allSettled( snapshotNames.map(async (name) => { - return await deleteVolumeSnapshot(volume, { name }).then( - (operation) => { + return await deleteVolumeSnapshot(volume, { name }) + .then((operation) => { eventQueue.set( operation.metadata.id, () => pushSuccess(results), (msg) => pushFailure(results, msg), () => continueOrFinish(results, snapshotNames.length, resolve), ); - }, - ); + }) + .catch((e) => { + pushFailure(results, e instanceof Error ? e.message : ""); + continueOrFinish(results, snapshotNames.length, resolve); + }); }), ); }); diff --git a/src/pages/images/actions/DeleteImageBtn.tsx b/src/pages/images/actions/DeleteImageBtn.tsx index 5a62d5fdc2..2f12b76af5 100644 --- a/src/pages/images/actions/DeleteImageBtn.tsx +++ b/src/pages/images/actions/DeleteImageBtn.tsx @@ -20,26 +20,36 @@ const DeleteImageBtn: FC = ({ image, project }) => { const handleDelete = () => { setLoading(true); - void deleteImage(image, project).then((operation) => - eventQueue.set( - operation.metadata.id, - () => { - void queryClient.invalidateQueries({ - queryKey: [queryKeys.images], - }); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.projects, project], - }); - toastNotify.success(`Image ${image.properties.description} deleted.`); - }, - (msg) => - toastNotify.failure( - `Image ${image.properties.description} deletion failed`, - new Error(msg), - ), - () => setLoading(false), - ), - ); + void deleteImage(image, project) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => { + void queryClient.invalidateQueries({ + queryKey: [queryKeys.images], + }); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.projects, project], + }); + toastNotify.success( + `Image ${image.properties.description} deleted.`, + ); + }, + (msg) => + toastNotify.failure( + `Image ${image.properties.description} deletion failed`, + new Error(msg), + ), + () => setLoading(false), + ), + ) + .catch((e) => { + toastNotify.failure( + `Image ${image.properties.description} deletion failed`, + e, + ); + setLoading(false); + }); }; return ( diff --git a/src/pages/instances/CreateInstance.tsx b/src/pages/instances/CreateInstance.tsx index 9743ec1ded..ebce9c5ad3 100644 --- a/src/pages/instances/CreateInstance.tsx +++ b/src/pages/instances/CreateInstance.tsx @@ -210,13 +210,17 @@ const CreateInstance: FC = () => { void startInstance({ name: instanceName, project: project, - } as LxdInstance).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => notifyCreatedAndStarted(instanceLink), - (msg) => notifyCreatedButStartFailed(instanceLink, new Error(msg)), - ); - }); + } as LxdInstance) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => notifyCreatedAndStarted(instanceLink), + (msg) => notifyCreatedButStartFailed(instanceLink, new Error(msg)), + ); + }) + .catch((e: Error) => { + notifyCreatedButStartFailed(instanceLink, e); + }); } else { const consoleUrl = `/ui/project/${project}/instance/${instanceName}/console`; const message = isIsoImage && ( diff --git a/src/pages/instances/EditInstance.tsx b/src/pages/instances/EditInstance.tsx index 2d78f85eb5..581f80e922 100644 --- a/src/pages/instances/EditInstance.tsx +++ b/src/pages/instances/EditInstance.tsx @@ -54,7 +54,7 @@ import { useEventQueue } from "context/eventQueue"; import { hasDiskError, hasNetworkError } from "util/instanceValidation"; import FormFooterLayout from "components/forms/FormFooterLayout"; import { useToastNotification } from "context/toastNotificationProvider"; -import { instanceLinkFromName } from "util/instances"; +import InstanceLink from "pages/instances/InstanceLink"; export interface InstanceEditDetailsFormValues { name: string; @@ -111,33 +111,34 @@ const EditInstance: FC = ({ instance }) => { // ensure the etag is set (it is missing on the yaml) instancePayload.etag = instance.etag; + const instanceLink = ; - void updateInstance(instancePayload, project).then((operation) => { - const instanceName = values.name; - const instanceLink = instanceLinkFromName({ - instanceName, - project, + void updateInstance(instancePayload, project) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => { + toastNotify.success(<>Instance {instanceLink} updated.); + void formik.setValues(getInstanceEditValues(instancePayload)); + }, + (msg) => + toastNotify.failure( + "Instance update failed.", + new Error(msg), + instanceLink, + ), + () => { + formik.setSubmitting(false); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => { + formik.setSubmitting(false); + toastNotify.failure("Instance update failed.", e, instanceLink); }); - eventQueue.set( - operation.metadata.id, - () => { - toastNotify.success(<>Instance {instanceLink} updated.); - void formik.setValues(getInstanceEditValues(instancePayload)); - }, - (msg) => - toastNotify.failure( - "Instance update failed.", - new Error(msg), - instanceLink, - ), - () => { - formik.setSubmitting(false); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); }, }); diff --git a/src/pages/instances/InstanceDetailHeader.tsx b/src/pages/instances/InstanceDetailHeader.tsx index 10a0f9faa3..ab597f6000 100644 --- a/src/pages/instances/InstanceDetailHeader.tsx +++ b/src/pages/instances/InstanceDetailHeader.tsx @@ -15,6 +15,7 @@ import { instanceLinkFromOperation, } from "util/instances"; import { getInstanceName } from "util/operations"; +import InstanceLink from "pages/instances/InstanceLink"; interface Props { name: string; @@ -58,32 +59,42 @@ const InstanceDetailHeader: FC = ({ name, instance, project }) => { formik.setSubmitting(false); return; } - void renameInstance(name, values.name, project).then((operation) => { - const instanceLink = instanceLinkFromName({ - instanceName: values.name, - project, + void renameInstance(name, values.name, project) + .then((operation) => { + const instanceLink = instanceLinkFromName({ + instanceName: values.name, + project, + }); + eventQueue.set( + operation.metadata.id, + () => { + navigate(`/ui/project/${project}/instance/${values.name}`); + toastNotify.success( + <> + Instance{" "} + {getInstanceName(operation.metadata)} renamed + to {instanceLink}. + , + ); + void formik.setFieldValue("isRenaming", false); + }, + (msg) => + toastNotify.failure( + "Renaming instance failed.", + new Error(msg), + instanceLinkFromOperation({ operation, project }), + ), + () => formik.setSubmitting(false), + ); + }) + .catch((e) => { + formik.setSubmitting(false); + toastNotify.failure( + `Renaming instance failed.`, + e, + instance ? : undefined, + ); }); - eventQueue.set( - operation.metadata.id, - () => { - navigate(`/ui/project/${project}/instance/${values.name}`); - toastNotify.success( - <> - Instance {getInstanceName(operation.metadata)}{" "} - renamed to {instanceLink}. - , - ); - void formik.setFieldValue("isRenaming", false); - }, - (msg) => - toastNotify.failure( - "Renaming instance failed.", - new Error(msg), - instanceLinkFromOperation({ operation, project }), - ), - () => formik.setSubmitting(false), - ); - }); }, }); diff --git a/src/pages/instances/actions/AttachIsoBtn.tsx b/src/pages/instances/actions/AttachIsoBtn.tsx index 71e7030223..f9076aaa64 100644 --- a/src/pages/instances/actions/AttachIsoBtn.tsx +++ b/src/pages/instances/actions/AttachIsoBtn.tsx @@ -41,34 +41,39 @@ const AttachIsoBtn: FC = ({ instance }) => { instance, values, ) as LxdInstance; - void updateInstance(instanceMinusIso, project ?? "").then((operation) => { - const instanceLink = instanceLinkFromOperation({ - operation, - project, + void updateInstance(instanceMinusIso, project ?? "") + .then((operation) => { + const instanceLink = instanceLinkFromOperation({ + operation, + project, + }); + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + ISO {attachedIso?.source ?? ""} detached from{" "} + {instanceLink} + , + ), + (msg) => + toastNotify.failure( + "Detaching ISO failed.", + new Error(msg), + instanceLink, + ), + () => { + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances, instance.name, project], + }); + setLoading(false); + }, + ); + }) + .catch((e) => { + setLoading(false); + toastNotify.failure("Detaching ISO failed.", e); }); - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - ISO {attachedIso?.source ?? ""} detached from{" "} - {instanceLink} - , - ), - (msg) => - toastNotify.failure( - "Detaching ISO failed.", - new Error(msg), - instanceLink, - ), - () => { - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances, instance.name, project], - }); - setLoading(false); - }, - ); - }); }; const handleSelect = (image: RemoteImage) => { @@ -78,33 +83,38 @@ const AttachIsoBtn: FC = ({ instance }) => { const isoDevice = remoteImageToIsoDevice(image); values.devices.push(isoDevice); const instancePlusIso = getInstancePayload(instance, values) as LxdInstance; - void updateInstance(instancePlusIso, project ?? "").then((operation) => { - const instanceLink = instanceLinkFromOperation({ - operation, - project, + void updateInstance(instancePlusIso, project ?? "") + .then((operation) => { + const instanceLink = instanceLinkFromOperation({ + operation, + project, + }); + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + ISO {image.aliases} attached to {instanceLink} + , + ), + (msg) => + toastNotify.failure( + "Attaching ISO failed.", + new Error(msg), + instanceLink, + ), + () => { + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances, instance.name, project], + }); + setLoading(false); + }, + ); + }) + .catch((e) => { + setLoading(false); + toastNotify.failure("Attaching ISO failed.", e); }); - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - ISO {image.aliases} attached to {instanceLink} - , - ), - (msg) => - toastNotify.failure( - "Attaching ISO failed.", - new Error(msg), - instanceLink, - ), - () => { - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances, instance.name, project], - }); - setLoading(false); - }, - ); - }); }; return attachedIso ? ( diff --git a/src/pages/instances/actions/DeleteInstanceBtn.tsx b/src/pages/instances/actions/DeleteInstanceBtn.tsx index 5a05f9bc1c..5a229a10ea 100644 --- a/src/pages/instances/actions/DeleteInstanceBtn.tsx +++ b/src/pages/instances/actions/DeleteInstanceBtn.tsx @@ -11,6 +11,7 @@ import { useEventQueue } from "context/eventQueue"; import { queryKeys } from "util/queryKeys"; import { useQueryClient } from "@tanstack/react-query"; import { useToastNotification } from "context/toastNotificationProvider"; +import InstanceLink from "pages/instances/InstanceLink"; interface Props { instance: LxdInstance; @@ -26,27 +27,34 @@ const DeleteInstanceBtn: FC = ({ instance }) => { const handleDelete = () => { setLoading(true); - void deleteInstance(instance).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => { - void queryClient.invalidateQueries({ - queryKey: [queryKeys.projects, instance.project], - }); - navigate(`/ui/project/${instance.project}/instances`); - toastNotify.success(`Instance ${instance.name} deleted.`); - }, - (msg) => - toastNotify.failure( - "Instance deletion failed", - new Error(msg), - <> - Instance : - , - ), - () => setLoading(false), - ); - }); + void deleteInstance(instance) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => { + void queryClient.invalidateQueries({ + queryKey: [queryKeys.projects, instance.project], + }); + navigate(`/ui/project/${instance.project}/instances`); + toastNotify.success(`Instance ${instance.name} deleted.`); + }, + (msg) => + toastNotify.failure( + "Instance deletion failed", + new Error(msg), + , + ), + () => setLoading(false), + ); + }) + .catch((e) => { + toastNotify.failure( + "Instance deletion failed", + e, + , + ); + setLoading(false); + }); }; const isDeletableStatus = deletableStatuses.includes(instance.status); diff --git a/src/pages/instances/actions/FreezeInstanceBtn.tsx b/src/pages/instances/actions/FreezeInstanceBtn.tsx index f28867aefc..6cdaf0d8df 100644 --- a/src/pages/instances/actions/FreezeInstanceBtn.tsx +++ b/src/pages/instances/actions/FreezeInstanceBtn.tsx @@ -25,31 +25,38 @@ const FreezeInstanceBtn: FC = ({ instance }) => { const handleFreeze = () => { instanceLoading.setLoading(instance, "Freezing"); - void freezeInstance(instance).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - Instance frozen. - , - ), - (msg) => - toastNotify.failure( - "Instance freeze failed", - new Error(msg), - <> - Instance : - , - ), - () => { - instanceLoading.setFinish(instance); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); + void freezeInstance(instance) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + Instance frozen. + , + ), + (msg) => + toastNotify.failure( + "Instance freeze failed", + new Error(msg), + , + ), + () => { + instanceLoading.setFinish(instance); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => { + toastNotify.failure( + "Instance freeze failed", + e, + , + ); + instanceLoading.setFinish(instance); + }); }; const isDisabled = isLoading || instance.status !== "Running"; diff --git a/src/pages/instances/actions/RestartInstanceBtn.tsx b/src/pages/instances/actions/RestartInstanceBtn.tsx index 7cc15aa32a..d7230cb5cb 100644 --- a/src/pages/instances/actions/RestartInstanceBtn.tsx +++ b/src/pages/instances/actions/RestartInstanceBtn.tsx @@ -27,31 +27,38 @@ const RestartInstanceBtn: FC = ({ instance }) => { const handleRestart = () => { instanceLoading.setLoading(instance, "Restarting"); - void restartInstance(instance, isForce).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - Instance restarted. - , - ), - (msg) => - toastNotify.failure( - "Instance restart failed", - new Error(msg), - <> - Instance : - , - ), - () => { - instanceLoading.setFinish(instance); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); + void restartInstance(instance, isForce) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + Instance restarted. + , + ), + (msg) => + toastNotify.failure( + "Instance restart failed", + new Error(msg), + , + ), + () => { + instanceLoading.setFinish(instance); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => { + toastNotify.failure( + "Instance restart failed", + e, + , + ); + instanceLoading.setFinish(instance); + }); }; const disabledStatuses = ["Stopped", "Frozen", "Error"]; diff --git a/src/pages/instances/actions/StopInstanceBtn.tsx b/src/pages/instances/actions/StopInstanceBtn.tsx index 08a40a0a91..93ba82ee06 100644 --- a/src/pages/instances/actions/StopInstanceBtn.tsx +++ b/src/pages/instances/actions/StopInstanceBtn.tsx @@ -27,31 +27,38 @@ const StopInstanceBtn: FC = ({ instance }) => { const handleStop = () => { instanceLoading.setLoading(instance, "Stopping"); - void stopInstance(instance, isForce).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - Instance stopped. - , - ), - (msg) => - toastNotify.failure( - "Instance stop failed", - new Error(msg), - <> - Instance : - , - ), - () => { - instanceLoading.setFinish(instance); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); + void stopInstance(instance, isForce) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + Instance stopped. + , + ), + (msg) => + toastNotify.failure( + "Instance stop failed", + new Error(msg), + , + ), + () => { + instanceLoading.setFinish(instance); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => { + toastNotify.failure( + "Instance stop failed", + e, + , + ); + instanceLoading.setFinish(instance); + }); }; return ( diff --git a/src/pages/instances/actions/snapshots/InstanceConfigureSnapshotModal.tsx b/src/pages/instances/actions/snapshots/InstanceConfigureSnapshotModal.tsx index 126690d947..6a92f0952f 100644 --- a/src/pages/instances/actions/snapshots/InstanceConfigureSnapshotModal.tsx +++ b/src/pages/instances/actions/snapshots/InstanceConfigureSnapshotModal.tsx @@ -41,19 +41,21 @@ const InstanceConfigureSnapshotModal: FC = ({ values, ) as LxdInstance; - void updateInstance(instancePayload, project ?? "").then((operation) => { - eventQueue.set( - operation.metadata.id, - () => onSuccess("Configuration updated."), - (msg) => onFailure("Configuration update failed", new Error(msg)), - () => { - close(); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); + void updateInstance(instancePayload, project ?? "") + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => onSuccess("Configuration updated."), + (msg) => onFailure("Configuration update failed", new Error(msg)), + () => { + close(); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => onFailure("Configuration update failed", e)); }, }); diff --git a/src/pages/instances/actions/snapshots/InstanceSnapshotActions.tsx b/src/pages/instances/actions/snapshots/InstanceSnapshotActions.tsx index acf82ee52e..f8dd24c5c6 100644 --- a/src/pages/instances/actions/snapshots/InstanceSnapshotActions.tsx +++ b/src/pages/instances/actions/snapshots/InstanceSnapshotActions.tsx @@ -34,30 +34,35 @@ const InstanceSnapshotActions: FC = ({ const handleDelete = () => { setDeleting(true); - void deleteInstanceSnapshot(instance, snapshot).then((operation) => - eventQueue.set( - operation.metadata.id, - () => - onSuccess( - <> - Snapshot deleted. - , - ), - (msg) => onFailure("Snapshot deletion failed", new Error(msg)), - () => { - setDeleting(false); - void queryClient.invalidateQueries({ - predicate: (query) => query.queryKey[0] === queryKeys.instances, - }); - }, - ), - ); + void deleteInstanceSnapshot(instance, snapshot) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => + onSuccess( + <> + Snapshot deleted. + , + ), + (msg) => onFailure("Snapshot deletion failed", new Error(msg)), + () => { + setDeleting(false); + void queryClient.invalidateQueries({ + predicate: (query) => query.queryKey[0] === queryKeys.instances, + }); + }, + ), + ) + .catch((e) => { + onFailure("Snapshot deletion failed", e); + setDeleting(false); + }); }; const handleRestore = () => { setRestoring(true); - void restoreInstanceSnapshot(instance, snapshot, restoreState).then( - (operation) => + void restoreInstanceSnapshot(instance, snapshot, restoreState) + .then((operation) => eventQueue.set( operation.metadata.id, () => @@ -74,7 +79,11 @@ const InstanceSnapshotActions: FC = ({ }); }, ), - ); + ) + .catch((e) => { + onFailure("Snapshot restore failed", e); + setRestoring(false); + }); }; return ( diff --git a/src/pages/instances/forms/EditInstanceSnapshotForm.tsx b/src/pages/instances/forms/EditInstanceSnapshotForm.tsx index a65f82dde9..8149f6725f 100644 --- a/src/pages/instances/forms/EditInstanceSnapshotForm.tsx +++ b/src/pages/instances/forms/EditInstanceSnapshotForm.tsx @@ -56,8 +56,8 @@ const EditInstanceSnapshotForm: FC = ({ name: newName, } as LxdInstanceSnapshot) : snapshot; - void updateInstanceSnapshot(instance, targetSnapshot, expiresAt).then( - (operation) => + void updateInstanceSnapshot(instance, targetSnapshot, expiresAt) + .then((operation) => eventQueue.set( operation.metadata.id, () => notifyUpdateSuccess(newName ?? snapshot.name), @@ -69,29 +69,38 @@ const EditInstanceSnapshotForm: FC = ({ formik.setSubmitting(false); }, ), - ); + ) + .catch((e) => { + toastNotify.failure("Snapshot update failed", e); + formik.setSubmitting(false); + }); }; const rename = (newName: string, expiresAt?: string) => { - void renameInstanceSnapshot(instance, snapshot, newName).then((operation) => - eventQueue.set( - operation.metadata.id, - () => { - if (expiresAt) { - update(expiresAt, newName); - } else { - notifyUpdateSuccess(newName); - } - }, - (msg) => { - toastNotify.failure( - `Snapshot rename failed for instance ${instance.name}`, - new Error(msg), - ); - formik.setSubmitting(false); - }, - ), - ); + void renameInstanceSnapshot(instance, snapshot, newName) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => { + if (expiresAt) { + update(expiresAt, newName); + } else { + notifyUpdateSuccess(newName); + } + }, + (msg) => { + toastNotify.failure( + `Snapshot rename failed for instance ${instance.name}`, + new Error(msg), + ); + formik.setSubmitting(false); + }, + ), + ) + .catch((e) => { + toastNotify.failure("Snapshot rename failed", e); + formik.setSubmitting(false); + }); }; const [expiryDate, expiryTime] = diff --git a/src/pages/projects/ProjectConfigurationHeader.tsx b/src/pages/projects/ProjectConfigurationHeader.tsx index d67f78c75e..8e68fcb431 100644 --- a/src/pages/projects/ProjectConfigurationHeader.tsx +++ b/src/pages/projects/ProjectConfigurationHeader.tsx @@ -47,24 +47,29 @@ const ProjectConfigurationHeader: FC = ({ project }) => { formik.setSubmitting(false); return; } - void renameProject(project.name, values.name).then((operation) => - eventQueue.set( - operation.metadata.id, - () => { - navigate(`/ui/project/${values.name}/configuration`); - toastNotify.success( - `Project ${project.name} renamed to ${values.name}.`, - ); - void formik.setFieldValue("isRenaming", false); - }, - (msg) => - toastNotify.failure( - `Renaming project ${project.name} failed`, - new Error(msg), - ), - () => formik.setSubmitting(false), - ), - ); + void renameProject(project.name, values.name) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => { + navigate(`/ui/project/${values.name}/configuration`); + toastNotify.success( + `Project ${project.name} renamed to ${values.name}.`, + ); + void formik.setFieldValue("isRenaming", false); + }, + (msg) => + toastNotify.failure( + `Renaming project ${project.name} failed`, + new Error(msg), + ), + () => formik.setSubmitting(false), + ), + ) + .catch((e) => { + formik.setSubmitting(false); + toastNotify.failure(`Renaming project ${project.name} failed`, e); + }); }, }); diff --git a/src/pages/storage/UploadCustomIso.tsx b/src/pages/storage/UploadCustomIso.tsx index cf10773603..de6b5df27b 100644 --- a/src/pages/storage/UploadCustomIso.tsx +++ b/src/pages/storage/UploadCustomIso.tsx @@ -85,20 +85,31 @@ const UploadCustomIso: FC = ({ onCancel, onFinish }) => { projectName, setUploadState, uploadController, - ).then((operation) => - eventQueue.set( - operation.metadata.id, - () => onFinish(name, pool), - (msg) => toastNotify.failure("Image import failed", new Error(msg)), - () => { - setLoading(false); - setUploadState(null); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.storage, pool, queryKeys.volumes, projectName], - }); - }, - ), - ); + ) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => onFinish(name, pool), + (msg) => toastNotify.failure("Image import failed", new Error(msg)), + () => { + setLoading(false); + setUploadState(null); + void queryClient.invalidateQueries({ + queryKey: [ + queryKeys.storage, + pool, + queryKeys.volumes, + projectName, + ], + }); + }, + ), + ) + .catch((e) => { + toastNotify.failure("Image import failed", e); + setLoading(false); + setUploadState(null); + }); }; const changeFile = (e: ChangeEvent) => { diff --git a/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx b/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx index d91ab1f871..96d9f6718a 100644 --- a/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx +++ b/src/pages/storage/actions/snapshots/VolumeSnapshotActions.tsx @@ -33,25 +33,30 @@ const VolumeSnapshotActions: FC = ({ volume, snapshot }) => { const handleDelete = () => { setDeleting(true); - void deleteVolumeSnapshot(volume, snapshot).then((operation) => - eventQueue.set( - operation.metadata.id, - () => toastNotify.success(`Snapshot ${snapshot.name} deleted`), - (msg) => - toastNotify.failure( - `Snapshot ${snapshot.name} deletion failed`, - new Error(msg), - ), - () => { - setDeleting(false); - void queryClient.invalidateQueries({ - predicate: (query) => - query.queryKey[0] === queryKeys.volumes || - query.queryKey[0] === queryKeys.storage, - }); - }, - ), - ); + void deleteVolumeSnapshot(volume, snapshot) + .then((operation) => + eventQueue.set( + operation.metadata.id, + () => toastNotify.success(`Snapshot ${snapshot.name} deleted`), + (msg) => + toastNotify.failure( + `Snapshot ${snapshot.name} deletion failed`, + new Error(msg), + ), + () => { + setDeleting(false); + void queryClient.invalidateQueries({ + predicate: (query) => + query.queryKey[0] === queryKeys.volumes || + query.queryKey[0] === queryKeys.storage, + }); + }, + ), + ) + .catch((e) => { + notify.failure("Snapshot deletion failed", e); + setDeleting(false); + }); }; const handleRestore = () => { diff --git a/src/pages/storage/forms/EditVolumeSnapshotForm.tsx b/src/pages/storage/forms/EditVolumeSnapshotForm.tsx index 18527d294c..800b55e982 100644 --- a/src/pages/storage/forms/EditVolumeSnapshotForm.tsx +++ b/src/pages/storage/forms/EditVolumeSnapshotForm.tsx @@ -57,15 +57,20 @@ const EditVolumeSnapshotForm: FC = ({ volume, snapshot, close }) => { volume, snapshot, newName, - }).then((operation) => - eventQueue.set(operation.metadata.id, resolve, (msg) => { - toastNotify.failure( - `Snapshot ${snapshot.name} rename failed`, - new Error(msg), - ); + }) + .then((operation) => + eventQueue.set(operation.metadata.id, resolve, (msg) => { + toastNotify.failure( + `Snapshot ${snapshot.name} rename failed`, + new Error(msg), + ); + formik.setSubmitting(false); + }), + ) + .catch((e) => { + notify.failure("Snapshot rename failed", e); formik.setSubmitting(false); - }), - ); + }); }); }; diff --git a/src/util/instanceStart.tsx b/src/util/instanceStart.tsx index b6f1445655..df28a59089 100644 --- a/src/util/instanceStart.tsx +++ b/src/util/instanceStart.tsx @@ -25,31 +25,36 @@ export const useInstanceStart = (instance: LxdInstance) => { instanceLoading.setLoading(instance, "Starting"); const mutation = instance.status === "Frozen" ? unfreezeInstance : startInstance; - void mutation(instance).then((operation) => { - eventQueue.set( - operation.metadata.id, - () => - toastNotify.success( - <> - Instance started. - , - ), - (msg) => - toastNotify.failure( - "Instance start failed", - new Error(msg), - <> - Instance : - , - ), - () => { - instanceLoading.setFinish(instance); - void queryClient.invalidateQueries({ - queryKey: [queryKeys.instances], - }); - }, - ); - }); + void mutation(instance) + .then((operation) => { + eventQueue.set( + operation.metadata.id, + () => + toastNotify.success( + <> + Instance started. + , + ), + (msg) => + toastNotify.failure( + "Instance start failed", + new Error(msg), + <> + Instance : + , + ), + () => { + instanceLoading.setFinish(instance); + void queryClient.invalidateQueries({ + queryKey: [queryKeys.instances], + }); + }, + ); + }) + .catch((e) => { + toastNotify.failure("Instance start failed", e); + instanceLoading.setFinish(instance); + }); }; return { handleStart, isLoading, isDisabled }; };