mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-10 23:08:37 +02:00
Miscellaneous Fixes (#21050)
* Don't add to history when opening search dialog * Update caniuse * Revamp the history handling for dialog components * clarify audio transcription docs * Use titlecase helper * Allow running object clasasification on stationary objects * small spacing tweaks for tablets * require admin role to delete users * explicitly prevent deletion of admin user --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
This commit is contained in:
@@ -13,7 +13,7 @@ import { cn } from "@/lib/utils";
|
||||
import { isPWA } from "@/utils/isPWA";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useHistoryBack } from "@/hooks/use-history-back";
|
||||
|
||||
const MobilePageContext = createContext<{
|
||||
open: boolean;
|
||||
@@ -24,15 +24,16 @@ type MobilePageProps = {
|
||||
children: React.ReactNode;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
enableHistoryBack?: boolean;
|
||||
};
|
||||
|
||||
export function MobilePage({
|
||||
children,
|
||||
open: controlledOpen,
|
||||
onOpenChange,
|
||||
enableHistoryBack = true,
|
||||
}: MobilePageProps) {
|
||||
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
|
||||
const open = controlledOpen ?? uncontrolledOpen;
|
||||
const setOpen = useCallback(
|
||||
@@ -46,33 +47,12 @@ export function MobilePage({
|
||||
[onOpenChange, setUncontrolledOpen],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let isActive = true;
|
||||
|
||||
if (open && isActive) {
|
||||
window.history.pushState({ isMobilePage: true }, "", location.pathname);
|
||||
}
|
||||
|
||||
const handlePopState = (event: PopStateEvent) => {
|
||||
if (open && isActive) {
|
||||
event.preventDefault();
|
||||
setOpen(false);
|
||||
// Delay replaceState to ensure state updates are processed
|
||||
setTimeout(() => {
|
||||
if (isActive) {
|
||||
window.history.replaceState(null, "", location.pathname);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("popstate", handlePopState);
|
||||
|
||||
return () => {
|
||||
isActive = false;
|
||||
window.removeEventListener("popstate", handlePopState);
|
||||
};
|
||||
}, [open, setOpen, location.pathname]);
|
||||
// Handle browser back button to close mobile page
|
||||
useHistoryBack({
|
||||
enabled: enableHistoryBack,
|
||||
open,
|
||||
onClose: () => setOpen(false),
|
||||
});
|
||||
|
||||
return (
|
||||
<MobilePageContext.Provider value={{ open, onOpenChange: setOpen }}>
|
||||
|
||||
@@ -113,7 +113,12 @@ export function PlatformAwareSheet({
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange} modal={false}>
|
||||
<Sheet
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
modal={false}
|
||||
enableHistoryBack
|
||||
>
|
||||
<SheetTrigger asChild className={triggerClassName}>
|
||||
{trigger}
|
||||
</SheetTrigger>
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useHistoryBack } from "@/hooks/use-history-back";
|
||||
|
||||
// Enhanced Dialog with History Support
|
||||
interface HistoryDialogProps extends DialogPrimitive.DialogProps {
|
||||
@@ -15,51 +16,28 @@ const Dialog = ({
|
||||
...props
|
||||
}: HistoryDialogProps) => {
|
||||
const [internalOpen, setInternalOpen] = React.useState(open || false);
|
||||
const historyStateRef = React.useRef<null | {
|
||||
listener: (e: PopStateEvent) => void;
|
||||
}>(null);
|
||||
|
||||
// Sync internal state with controlled open prop
|
||||
React.useEffect(() => {
|
||||
if (open !== undefined) {
|
||||
setInternalOpen(open);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (enableHistoryBack) {
|
||||
if (internalOpen) {
|
||||
window.history.pushState({ dialogOpen: true }, "");
|
||||
const handleOpenChange = React.useCallback(
|
||||
(newOpen: boolean) => {
|
||||
setInternalOpen(newOpen);
|
||||
onOpenChange?.(newOpen);
|
||||
},
|
||||
[onOpenChange],
|
||||
);
|
||||
|
||||
const listener = () => {
|
||||
setInternalOpen(false);
|
||||
if (onOpenChange) onOpenChange(false);
|
||||
};
|
||||
|
||||
historyStateRef.current = { listener };
|
||||
window.addEventListener("popstate", listener);
|
||||
|
||||
return () => {
|
||||
if (internalOpen) {
|
||||
window.removeEventListener("popstate", listener);
|
||||
historyStateRef.current = null;
|
||||
}
|
||||
};
|
||||
} else if (historyStateRef.current) {
|
||||
window.removeEventListener(
|
||||
"popstate",
|
||||
historyStateRef.current.listener,
|
||||
);
|
||||
historyStateRef.current = null;
|
||||
}
|
||||
}
|
||||
}, [enableHistoryBack, internalOpen, onOpenChange]);
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setInternalOpen(open);
|
||||
if (onOpenChange) {
|
||||
onOpenChange(open);
|
||||
}
|
||||
};
|
||||
// Handle browser back button to close dialog
|
||||
useHistoryBack({
|
||||
enabled: enableHistoryBack,
|
||||
open: internalOpen,
|
||||
onClose: () => handleOpenChange(false),
|
||||
});
|
||||
|
||||
return (
|
||||
<DialogPrimitive.Root
|
||||
|
||||
@@ -4,6 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useHistoryBack } from "@/hooks/use-history-back";
|
||||
|
||||
// Enhanced Sheet with History Support
|
||||
interface HistorySheetProps extends SheetPrimitive.DialogProps {
|
||||
@@ -17,51 +18,28 @@ const Sheet = ({
|
||||
...props
|
||||
}: HistorySheetProps) => {
|
||||
const [internalOpen, setInternalOpen] = React.useState(open || false);
|
||||
const historyStateRef = React.useRef<null | {
|
||||
listener: (e: PopStateEvent) => void;
|
||||
}>(null);
|
||||
|
||||
// Sync internal state with controlled open prop
|
||||
React.useEffect(() => {
|
||||
if (open !== undefined) {
|
||||
setInternalOpen(open);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (enableHistoryBack) {
|
||||
if (internalOpen) {
|
||||
window.history.pushState({ sheetOpen: true }, "");
|
||||
const handleOpenChange = React.useCallback(
|
||||
(newOpen: boolean) => {
|
||||
setInternalOpen(newOpen);
|
||||
onOpenChange?.(newOpen);
|
||||
},
|
||||
[onOpenChange],
|
||||
);
|
||||
|
||||
const listener = () => {
|
||||
setInternalOpen(false);
|
||||
if (onOpenChange) onOpenChange(false);
|
||||
};
|
||||
|
||||
historyStateRef.current = { listener };
|
||||
window.addEventListener("popstate", listener);
|
||||
|
||||
return () => {
|
||||
if (internalOpen) {
|
||||
window.removeEventListener("popstate", listener);
|
||||
historyStateRef.current = null;
|
||||
}
|
||||
};
|
||||
} else if (historyStateRef.current) {
|
||||
window.removeEventListener(
|
||||
"popstate",
|
||||
historyStateRef.current.listener,
|
||||
);
|
||||
historyStateRef.current = null;
|
||||
}
|
||||
}
|
||||
}, [enableHistoryBack, internalOpen, onOpenChange]);
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setInternalOpen(open);
|
||||
if (onOpenChange) {
|
||||
onOpenChange(open);
|
||||
}
|
||||
};
|
||||
// Handle browser back button to close sheet
|
||||
useHistoryBack({
|
||||
enabled: enableHistoryBack,
|
||||
open: internalOpen,
|
||||
onClose: () => handleOpenChange(false),
|
||||
});
|
||||
|
||||
return (
|
||||
<SheetPrimitive.Root
|
||||
|
||||
Reference in New Issue
Block a user