From feb2ab11f9366bdd4b3af179bc3ce1f1f5336ad1 Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Sat, 16 Nov 2024 14:11:32 +0200 Subject: [PATCH] Implement useGuardedMutation hook for enhanced error handling in MachineContainer and update related components --- .../machines/components/MachineContainer.tsx | 8 ++-- .../features/machines/hooks/usePingTrigger.ts | 3 +- .../system/CacheSettingsContainer.tsx | 7 +--- frontend/src/units/swr/hooks/index.ts | 3 ++ .../src/units/swr/hooks/useGuardedMutation.ts | 39 +++++++++++++++++++ frontend/src/units/swr/index.ts | 1 + 6 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 frontend/src/units/swr/hooks/index.ts create mode 100644 frontend/src/units/swr/hooks/useGuardedMutation.ts diff --git a/frontend/src/features/machines/components/MachineContainer.tsx b/frontend/src/features/machines/components/MachineContainer.tsx index ba598d3..31d02af 100644 --- a/frontend/src/features/machines/components/MachineContainer.tsx +++ b/frontend/src/features/machines/components/MachineContainer.tsx @@ -14,7 +14,7 @@ import { RestartMachine, ShutdownMachine } from "types"; -import { Key, NetworkError, mutationFetcher, useSWRMutation } from "units/swr"; +import { Key, NetworkError, mutationFetcher, useGuardedMutation } from "units/swr"; import { usePingTrigger } from "../hooks"; type Props = { @@ -48,20 +48,18 @@ const MachineContainer: React.FC = ({ machine, viewMode }) => { onSuccess: manageActionResponse }); - const { trigger: shutdownMachineTrigger } = useSWRMutation( + const { trigger: shutdownMachineTrigger } = useGuardedMutation( endpoints.network.machine.shutdown, mutationFetcher, { - onError: err => blip.error(err.message), onSuccess: manageActionResponse } ); - const { trigger: restartMachineTrigger } = useSWRMutation( + const { trigger: restartMachineTrigger } = useGuardedMutation( endpoints.network.machine.restart, mutationFetcher, { - onError: err => blip.error(err.serverError.message || err.message), onSuccess: manageActionResponse } ); diff --git a/frontend/src/features/machines/hooks/usePingTrigger.ts b/frontend/src/features/machines/hooks/usePingTrigger.ts index c9264ea..f725132 100644 --- a/frontend/src/features/machines/hooks/usePingTrigger.ts +++ b/frontend/src/features/machines/hooks/usePingTrigger.ts @@ -17,7 +17,8 @@ const usePingTrigger = (options: PingTriggerOptions) => { mutationFetcher, { onError, - onSuccess + onSuccess, + throwOnError: false } ); return { pingMachineTrigger }; diff --git a/frontend/src/features/settings/system/CacheSettingsContainer.tsx b/frontend/src/features/settings/system/CacheSettingsContainer.tsx index 2ee1ee1..39cec63 100644 --- a/frontend/src/features/settings/system/CacheSettingsContainer.tsx +++ b/frontend/src/features/settings/system/CacheSettingsContainer.tsx @@ -3,18 +3,15 @@ import CacheSettingsComponent from "./CacheSettingsComponent"; import { useTranslation } from "react-i18next"; import { endpoints } from "utils/api"; import { blip } from "utils"; -import { useSWRMutation, mutationFetcher, Key, NetworkError } from "units/swr"; +import { useGuardedMutation, mutationFetcher, Key, NetworkError } from "units/swr"; const CacheSettingsContainer: React.FC = () => { const { t } = useTranslation(); - const { trigger } = useSWRMutation( + const { trigger } = useGuardedMutation( endpoints.system.resetCache, mutationFetcher, { - onError: err => { - blip.error(err.message); - }, onSuccess: () => blip.info(t("Settings.Cache.ResetInfo")) } ); diff --git a/frontend/src/units/swr/hooks/index.ts b/frontend/src/units/swr/hooks/index.ts new file mode 100644 index 0000000..d49e535 --- /dev/null +++ b/frontend/src/units/swr/hooks/index.ts @@ -0,0 +1,3 @@ +import useGuardedMutation from "./useGuardedMutation"; + +export { useGuardedMutation }; diff --git a/frontend/src/units/swr/hooks/useGuardedMutation.ts b/frontend/src/units/swr/hooks/useGuardedMutation.ts new file mode 100644 index 0000000..c2f0897 --- /dev/null +++ b/frontend/src/units/swr/hooks/useGuardedMutation.ts @@ -0,0 +1,39 @@ +import useSWRMutation, { MutationFetcher, SWRMutationConfiguration, SWRMutationResponse } from "swr/mutation"; +import { Key, NetworkError } from "../../swr"; +import { blip } from "utils"; +import { useMemo } from "react"; + +const defaultErrorHandler = (error: Error) => { + const isNetworkError = error instanceof NetworkError; + if (isNetworkError) { + blip.error(error.serverError.message || error.message); + return; + } + blip.error(error.message); +}; + +function useGuardedMutation< + Data = any, + Error = any, + SWRMutationKey extends Key = Key, + ExtraArg = never, + SWRData = Data +>( + key: SWRMutationKey, + fetcher: MutationFetcher, + options?: SWRMutationConfiguration & { throwOnError?: boolean } +): SWRMutationResponse { + const opts = useMemo( + () => + ({ + ...options, + onError: options?.onError ?? defaultErrorHandler, + throwOnError: options?.throwOnError ?? false + } as SWRMutationConfiguration), + [options] + ); + + return useSWRMutation(key, fetcher, opts); +} + +export default useGuardedMutation; diff --git a/frontend/src/units/swr/index.ts b/frontend/src/units/swr/index.ts index f5d3e5c..0480844 100644 --- a/frontend/src/units/swr/index.ts +++ b/frontend/src/units/swr/index.ts @@ -4,6 +4,7 @@ import useSWRMutation from "swr/mutation"; export * from "./fetchers"; export * from "./errors"; +export * from "./hooks"; export { useSWR, useSWRMutation }; export type { Key };