mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Show dialog when restarting from config editor (#14815)
* Show restart dialog when restarting from config editor * don't save until confirmed restart
This commit is contained in:
parent
404807c697
commit
fc0fb158d5
@ -24,7 +24,7 @@ import {
|
|||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "../ui/dropdown-menu";
|
} from "../ui/dropdown-menu";
|
||||||
import { Button } from "../ui/button";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { CgDarkMode } from "react-icons/cg";
|
import { CgDarkMode } from "react-icons/cg";
|
||||||
import {
|
import {
|
||||||
@ -33,30 +33,15 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from "@/context/theme-provider";
|
} from "@/context/theme-provider";
|
||||||
import { IoColorPalette } from "react-icons/io5";
|
import { IoColorPalette } from "react-icons/io5";
|
||||||
import {
|
|
||||||
AlertDialog,
|
import { useState } from "react";
|
||||||
AlertDialogAction,
|
|
||||||
AlertDialogCancel,
|
|
||||||
AlertDialogContent,
|
|
||||||
AlertDialogFooter,
|
|
||||||
AlertDialogHeader,
|
|
||||||
AlertDialogTitle,
|
|
||||||
} from "../ui/alert-dialog";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useRestart } from "@/api/ws";
|
import { useRestart } from "@/api/ws";
|
||||||
import {
|
|
||||||
Sheet,
|
|
||||||
SheetContent,
|
|
||||||
SheetDescription,
|
|
||||||
SheetHeader,
|
|
||||||
SheetTitle,
|
|
||||||
} from "../ui/sheet";
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import ActivityIndicator from "../indicators/activity-indicator";
|
|
||||||
import { isDesktop, isMobile } from "react-device-detect";
|
import { isDesktop, isMobile } from "react-device-detect";
|
||||||
import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer";
|
import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer";
|
||||||
import {
|
import {
|
||||||
@ -68,8 +53,8 @@ import {
|
|||||||
} from "../ui/dialog";
|
} from "../ui/dialog";
|
||||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { baseUrl } from "@/api/baseUrl";
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import RestartDialog from "../overlay/dialog/RestartDialog";
|
||||||
|
|
||||||
type GeneralSettingsProps = {
|
type GeneralSettingsProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -83,35 +68,8 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
|||||||
|
|
||||||
const { theme, colorScheme, setTheme, setColorScheme } = useTheme();
|
const { theme, colorScheme, setTheme, setColorScheme } = useTheme();
|
||||||
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
||||||
const [restartingSheetOpen, setRestartingSheetOpen] = useState(false);
|
|
||||||
const [countdown, setCountdown] = useState(60);
|
|
||||||
|
|
||||||
const { send: sendRestart } = useRestart();
|
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 Container = isDesktop ? DropdownMenu : Drawer;
|
||||||
const Trigger = isDesktop ? DropdownMenuTrigger : DrawerTrigger;
|
const Trigger = isDesktop ? DropdownMenuTrigger : DrawerTrigger;
|
||||||
const Content = isDesktop ? DropdownMenuContent : DrawerContent;
|
const Content = isDesktop ? DropdownMenuContent : DrawerContent;
|
||||||
@ -413,64 +371,11 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
|||||||
</div>
|
</div>
|
||||||
</Content>
|
</Content>
|
||||||
</Container>
|
</Container>
|
||||||
{restartDialogOpen && (
|
<RestartDialog
|
||||||
<AlertDialog
|
isOpen={restartDialogOpen}
|
||||||
open={restartDialogOpen}
|
onClose={() => setRestartDialogOpen(false)}
|
||||||
onOpenChange={() => setRestartDialogOpen(false)}
|
onRestart={() => sendRestart("restart")}
|
||||||
>
|
/>
|
||||||
<AlertDialogContent>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>
|
|
||||||
Are you sure you want to restart Frigate?
|
|
||||||
</AlertDialogTitle>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={() => {
|
|
||||||
setRestartingSheetOpen(true);
|
|
||||||
sendRestart("restart");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Restart
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
)}
|
|
||||||
{restartingSheetOpen && (
|
|
||||||
<>
|
|
||||||
<Sheet
|
|
||||||
open={restartingSheetOpen}
|
|
||||||
onOpenChange={() => setRestartingSheetOpen(false)}
|
|
||||||
>
|
|
||||||
<SheetContent
|
|
||||||
side="top"
|
|
||||||
onInteractOutside={(e) => e.preventDefault()}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<ActivityIndicator />
|
|
||||||
<SheetHeader className="mt-5 text-center">
|
|
||||||
<SheetTitle className="text-center">
|
|
||||||
Frigate is Restarting
|
|
||||||
</SheetTitle>
|
|
||||||
<SheetDescription className="text-center">
|
|
||||||
<p>This page will reload in {countdown} seconds.</p>
|
|
||||||
</SheetDescription>
|
|
||||||
</SheetHeader>
|
|
||||||
<Button
|
|
||||||
size="lg"
|
|
||||||
className="mt-5"
|
|
||||||
aria-label="Force reload now"
|
|
||||||
onClick={handleForceReload}
|
|
||||||
>
|
|
||||||
Force Reload Now
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
122
web/src/components/overlay/dialog/RestartDialog.tsx
Normal file
122
web/src/components/overlay/dialog/RestartDialog.tsx
Normal file
@ -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 (
|
||||||
|
<>
|
||||||
|
<AlertDialog
|
||||||
|
open={restartDialogOpen}
|
||||||
|
onOpenChange={() => {
|
||||||
|
setRestartDialogOpen(false);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>
|
||||||
|
Are you sure you want to restart Frigate?
|
||||||
|
</AlertDialogTitle>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction onClick={handleRestart}>
|
||||||
|
Restart
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
|
<Sheet
|
||||||
|
open={restartingSheetOpen}
|
||||||
|
onOpenChange={() => setRestartingSheetOpen(false)}
|
||||||
|
>
|
||||||
|
<SheetContent side="top" onInteractOutside={(e) => e.preventDefault()}>
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<ActivityIndicator />
|
||||||
|
<SheetHeader className="mt-5 text-center">
|
||||||
|
<SheetTitle className="text-center">
|
||||||
|
Frigate is Restarting
|
||||||
|
</SheetTitle>
|
||||||
|
<SheetDescription className="text-center">
|
||||||
|
<div>This page will reload in {countdown} seconds.</div>
|
||||||
|
</SheetDescription>
|
||||||
|
</SheetHeader>
|
||||||
|
<Button
|
||||||
|
size="lg"
|
||||||
|
className="mt-5"
|
||||||
|
aria-label="Force reload now"
|
||||||
|
onClick={handleForceReload}
|
||||||
|
>
|
||||||
|
Force Reload Now
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -13,6 +13,7 @@ import { Toaster } from "@/components/ui/sonner";
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { LuCopy, LuSave } from "react-icons/lu";
|
import { LuCopy, LuSave } from "react-icons/lu";
|
||||||
import { MdOutlineRestartAlt } from "react-icons/md";
|
import { MdOutlineRestartAlt } from "react-icons/md";
|
||||||
|
import RestartDialog from "@/components/overlay/dialog/RestartDialog";
|
||||||
|
|
||||||
type SaveOptions = "saveonly" | "restart";
|
type SaveOptions = "saveonly" | "restart";
|
||||||
|
|
||||||
@ -33,6 +34,8 @@ function ConfigEditor() {
|
|||||||
const configRef = useRef<HTMLDivElement | null>(null);
|
const configRef = useRef<HTMLDivElement | null>(null);
|
||||||
const schemaConfiguredRef = useRef(false);
|
const schemaConfiguredRef = useRef(false);
|
||||||
|
|
||||||
|
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
||||||
|
|
||||||
const onHandleSaveConfig = useCallback(
|
const onHandleSaveConfig = useCallback(
|
||||||
async (save_option: SaveOptions) => {
|
async (save_option: SaveOptions) => {
|
||||||
if (!editorRef.current) {
|
if (!editorRef.current) {
|
||||||
@ -202,7 +205,7 @@ function ConfigEditor() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
aria-label="Save and restart"
|
aria-label="Save and restart"
|
||||||
onClick={() => onHandleSaveConfig("restart")}
|
onClick={() => setRestartDialogOpen(true)}
|
||||||
>
|
>
|
||||||
<div className="relative size-5">
|
<div className="relative size-5">
|
||||||
<LuSave className="absolute left-0 top-0 size-3 text-secondary-foreground" />
|
<LuSave className="absolute left-0 top-0 size-3 text-secondary-foreground" />
|
||||||
@ -231,6 +234,11 @@ function ConfigEditor() {
|
|||||||
<div ref={configRef} className="mt-2 h-[calc(100%-2.75rem)]" />
|
<div ref={configRef} className="mt-2 h-[calc(100%-2.75rem)]" />
|
||||||
</div>
|
</div>
|
||||||
<Toaster closeButton={true} />
|
<Toaster closeButton={true} />
|
||||||
|
<RestartDialog
|
||||||
|
isOpen={restartDialogOpen}
|
||||||
|
onClose={() => setRestartDialogOpen(false)}
|
||||||
|
onRestart={() => onHandleSaveConfig("restart")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user