From fc0fb158d570b09fb0a97ff25f22faccf39a4658 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:33:41 -0600 Subject: [PATCH] Show dialog when restarting from config editor (#14815) * Show restart dialog when restarting from config editor * don't save until confirmed restart --- web/src/components/menu/GeneralSettings.tsx | 115 ++--------------- .../overlay/dialog/RestartDialog.tsx | 122 ++++++++++++++++++ web/src/pages/ConfigEditor.tsx | 10 +- 3 files changed, 141 insertions(+), 106 deletions(-) create mode 100644 web/src/components/overlay/dialog/RestartDialog.tsx diff --git a/web/src/components/menu/GeneralSettings.tsx b/web/src/components/menu/GeneralSettings.tsx index 0341f2500..7473d26d7 100644 --- a/web/src/components/menu/GeneralSettings.tsx +++ b/web/src/components/menu/GeneralSettings.tsx @@ -24,7 +24,7 @@ import { DropdownMenuSubTrigger, DropdownMenuTrigger, } from "../ui/dropdown-menu"; -import { Button } from "../ui/button"; + import { Link } from "react-router-dom"; import { CgDarkMode } from "react-icons/cg"; import { @@ -33,30 +33,15 @@ import { useTheme, } from "@/context/theme-provider"; import { IoColorPalette } from "react-icons/io5"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "../ui/alert-dialog"; -import { useEffect, useState } from "react"; + +import { useState } from "react"; import { useRestart } from "@/api/ws"; -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "../ui/sheet"; + import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; -import ActivityIndicator from "../indicators/activity-indicator"; import { isDesktop, isMobile } from "react-device-detect"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { @@ -68,8 +53,8 @@ import { } from "../ui/dialog"; import { TooltipPortal } from "@radix-ui/react-tooltip"; import { cn } from "@/lib/utils"; -import { baseUrl } from "@/api/baseUrl"; import useSWR from "swr"; +import RestartDialog from "../overlay/dialog/RestartDialog"; type GeneralSettingsProps = { className?: string; @@ -83,35 +68,8 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) { const { theme, colorScheme, setTheme, setColorScheme } = useTheme(); const [restartDialogOpen, setRestartDialogOpen] = useState(false); - const [restartingSheetOpen, setRestartingSheetOpen] = useState(false); - const [countdown, setCountdown] = useState(60); - const { send: sendRestart } = useRestart(); - useEffect(() => { - let countdownInterval: NodeJS.Timeout; - - if (restartingSheetOpen) { - countdownInterval = setInterval(() => { - setCountdown((prevCountdown) => prevCountdown - 1); - }, 1000); - } - - return () => { - clearInterval(countdownInterval); - }; - }, [restartingSheetOpen]); - - useEffect(() => { - if (countdown === 0) { - window.location.href = baseUrl; - } - }, [countdown]); - - const handleForceReload = () => { - window.location.href = baseUrl; - }; - const Container = isDesktop ? DropdownMenu : Drawer; const Trigger = isDesktop ? DropdownMenuTrigger : DrawerTrigger; const Content = isDesktop ? DropdownMenuContent : DrawerContent; @@ -413,64 +371,11 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) { - {restartDialogOpen && ( - setRestartDialogOpen(false)} - > - - - - Are you sure you want to restart Frigate? - - - - Cancel - { - setRestartingSheetOpen(true); - sendRestart("restart"); - }} - > - Restart - - - - - )} - {restartingSheetOpen && ( - <> - setRestartingSheetOpen(false)} - > - e.preventDefault()} - > - - - - - Frigate is Restarting - - - This page will reload in {countdown} seconds. - - - - Force Reload Now - - - - - > - )} + setRestartDialogOpen(false)} + onRestart={() => sendRestart("restart")} + /> > ); } diff --git a/web/src/components/overlay/dialog/RestartDialog.tsx b/web/src/components/overlay/dialog/RestartDialog.tsx new file mode 100644 index 000000000..8e1a5c129 --- /dev/null +++ b/web/src/components/overlay/dialog/RestartDialog.tsx @@ -0,0 +1,122 @@ +import { useState, useEffect } from "react"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetDescription, +} from "@/components/ui/sheet"; +import { Button } from "@/components/ui/button"; +import ActivityIndicator from "@/components/indicators/activity-indicator"; +import { baseUrl } from "@/api/baseUrl"; + +type RestartDialogProps = { + isOpen: boolean; + onClose: () => void; + onRestart: () => void; +}; + +export default function RestartDialog({ + isOpen, + onClose, + onRestart, +}: RestartDialogProps) { + const [restartDialogOpen, setRestartDialogOpen] = useState(isOpen); + const [restartingSheetOpen, setRestartingSheetOpen] = useState(false); + const [countdown, setCountdown] = useState(60); + + useEffect(() => { + setRestartDialogOpen(isOpen); + }, [isOpen]); + + useEffect(() => { + let countdownInterval: NodeJS.Timeout; + + if (restartingSheetOpen) { + countdownInterval = setInterval(() => { + setCountdown((prevCountdown) => prevCountdown - 1); + }, 1000); + } + + return () => { + clearInterval(countdownInterval); + }; + }, [restartingSheetOpen]); + + useEffect(() => { + if (countdown === 0) { + window.location.href = baseUrl; + } + }, [countdown]); + + const handleRestart = () => { + setRestartingSheetOpen(true); + onRestart(); + }; + + const handleForceReload = () => { + window.location.href = baseUrl; + }; + + return ( + <> + { + setRestartDialogOpen(false); + onClose(); + }} + > + + + + Are you sure you want to restart Frigate? + + + + Cancel + + Restart + + + + + + setRestartingSheetOpen(false)} + > + e.preventDefault()}> + + + + + Frigate is Restarting + + + This page will reload in {countdown} seconds. + + + + Force Reload Now + + + + + > + ); +} diff --git a/web/src/pages/ConfigEditor.tsx b/web/src/pages/ConfigEditor.tsx index 52cb05473..bcb0c4c65 100644 --- a/web/src/pages/ConfigEditor.tsx +++ b/web/src/pages/ConfigEditor.tsx @@ -13,6 +13,7 @@ import { Toaster } from "@/components/ui/sonner"; import { toast } from "sonner"; import { LuCopy, LuSave } from "react-icons/lu"; import { MdOutlineRestartAlt } from "react-icons/md"; +import RestartDialog from "@/components/overlay/dialog/RestartDialog"; type SaveOptions = "saveonly" | "restart"; @@ -33,6 +34,8 @@ function ConfigEditor() { const configRef = useRef(null); const schemaConfiguredRef = useRef(false); + const [restartDialogOpen, setRestartDialogOpen] = useState(false); + const onHandleSaveConfig = useCallback( async (save_option: SaveOptions) => { if (!editorRef.current) { @@ -202,7 +205,7 @@ function ConfigEditor() { size="sm" className="flex items-center gap-2" aria-label="Save and restart" - onClick={() => onHandleSaveConfig("restart")} + onClick={() => setRestartDialogOpen(true)} > @@ -231,6 +234,11 @@ function ConfigEditor() { + setRestartDialogOpen(false)} + onRestart={() => onHandleSaveConfig("restart")} + /> ); }
This page will reload in {countdown} seconds.