mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-23 08:38:22 +03:00
add restart button to toast when restart is required
This commit is contained in:
parent
5d518bfa65
commit
ef55d90379
@ -55,6 +55,8 @@ import { applySchemaDefaults } from "@/lib/config-schema";
|
|||||||
import { isJsonObject } from "@/lib/utils";
|
import { isJsonObject } from "@/lib/utils";
|
||||||
import { ConfigSectionData, JsonObject, JsonValue } from "@/types/configForm";
|
import { ConfigSectionData, JsonObject, JsonValue } from "@/types/configForm";
|
||||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
|
import RestartDialog from "@/components/overlay/dialog/RestartDialog";
|
||||||
|
import { useRestart } from "@/api/ws";
|
||||||
|
|
||||||
export interface SectionConfig {
|
export interface SectionConfig {
|
||||||
/** Field ordering within the section */
|
/** Field ordering within the section */
|
||||||
@ -178,8 +180,10 @@ export function ConfigSection({
|
|||||||
"config/cameras",
|
"config/cameras",
|
||||||
"views/settings",
|
"views/settings",
|
||||||
"common",
|
"common",
|
||||||
|
"components/dialog",
|
||||||
]);
|
]);
|
||||||
const [isOpen, setIsOpen] = useState(!defaultCollapsed);
|
const [isOpen, setIsOpen] = useState(!defaultCollapsed);
|
||||||
|
const { send: sendRestart } = useRestart();
|
||||||
|
|
||||||
// Create a key for this section's pending data
|
// Create a key for this section's pending data
|
||||||
const pendingDataKey = useMemo(
|
const pendingDataKey = useMemo(
|
||||||
@ -212,6 +216,7 @@ export function ConfigSection({
|
|||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [formKey, setFormKey] = useState(0);
|
const [formKey, setFormKey] = useState(0);
|
||||||
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
|
||||||
|
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
||||||
const isResettingRef = useRef(false);
|
const isResettingRef = useRef(false);
|
||||||
const isInitializingRef = useRef(true);
|
const isInitializingRef = useRef(true);
|
||||||
|
|
||||||
@ -562,14 +567,31 @@ export function ConfigSection({
|
|||||||
requires_restart: needsRestart ? 1 : 0,
|
requires_restart: needsRestart ? 1 : 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.success(
|
if (needsRestart) {
|
||||||
t(needsRestart ? "toast.successRestartRequired" : "toast.success", {
|
toast.success(
|
||||||
ns: "views/settings",
|
t("toast.successRestartRequired", {
|
||||||
defaultValue: needsRestart
|
ns: "views/settings",
|
||||||
? "Settings saved successfully. Restart Frigate to apply your changes."
|
defaultValue:
|
||||||
: "Settings saved successfully",
|
"Settings saved successfully. Restart Frigate to apply your changes.",
|
||||||
}),
|
}),
|
||||||
);
|
{
|
||||||
|
action: (
|
||||||
|
<a onClick={() => setRestartDialogOpen(true)}>
|
||||||
|
<Button>
|
||||||
|
{t("restart.button", { ns: "components/dialog" })}
|
||||||
|
</Button>
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
toast.success(
|
||||||
|
t("toast.success", {
|
||||||
|
ns: "views/settings",
|
||||||
|
defaultValue: "Settings saved successfully",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
setPendingData(null);
|
setPendingData(null);
|
||||||
refreshConfig();
|
refreshConfig();
|
||||||
@ -933,16 +955,61 @@ export function ConfigSection({
|
|||||||
|
|
||||||
if (collapsible) {
|
if (collapsible) {
|
||||||
return (
|
return (
|
||||||
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
|
<>
|
||||||
<div className="space-y-3">
|
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<CollapsibleTrigger asChild>
|
<div className="space-y-3">
|
||||||
<div className="flex cursor-pointer items-center justify-between">
|
<CollapsibleTrigger asChild>
|
||||||
|
<div className="flex cursor-pointer items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{isOpen ? (
|
||||||
|
<LuChevronDown className="h-4 w-4 text-muted-foreground" />
|
||||||
|
) : (
|
||||||
|
<LuChevronRight className="h-4 w-4 text-muted-foreground" />
|
||||||
|
)}
|
||||||
|
<Heading as="h4">{title}</Heading>
|
||||||
|
{showOverrideIndicator &&
|
||||||
|
level === "camera" &&
|
||||||
|
isOverridden && (
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{t("button.overridden", {
|
||||||
|
ns: "common",
|
||||||
|
defaultValue: "Overridden",
|
||||||
|
})}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{hasChanges && (
|
||||||
|
<Badge variant="outline" className="text-xs">
|
||||||
|
{t("modified", {
|
||||||
|
ns: "common",
|
||||||
|
defaultValue: "Modified",
|
||||||
|
})}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
|
||||||
|
<CollapsibleContent>
|
||||||
|
<div className="pl-7">{sectionContent}</div>
|
||||||
|
</CollapsibleContent>
|
||||||
|
</div>
|
||||||
|
</Collapsible>
|
||||||
|
<RestartDialog
|
||||||
|
isOpen={restartDialogOpen}
|
||||||
|
onClose={() => setRestartDialogOpen(false)}
|
||||||
|
onRestart={() => sendRestart("restart")}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{shouldShowTitle && (
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{isOpen ? (
|
|
||||||
<LuChevronDown className="h-4 w-4 text-muted-foreground" />
|
|
||||||
) : (
|
|
||||||
<LuChevronRight className="h-4 w-4 text-muted-foreground" />
|
|
||||||
)}
|
|
||||||
<Heading as="h4">{title}</Heading>
|
<Heading as="h4">{title}</Heading>
|
||||||
{showOverrideIndicator &&
|
{showOverrideIndicator &&
|
||||||
level === "camera" &&
|
level === "camera" &&
|
||||||
@ -956,55 +1023,26 @@ export function ConfigSection({
|
|||||||
)}
|
)}
|
||||||
{hasChanges && (
|
{hasChanges && (
|
||||||
<Badge variant="outline" className="text-xs">
|
<Badge variant="outline" className="text-xs">
|
||||||
{t("modified", {
|
{t("modified", { ns: "common", defaultValue: "Modified" })}
|
||||||
ns: "common",
|
|
||||||
defaultValue: "Modified",
|
|
||||||
})}
|
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{sectionDescription && (
|
||||||
</CollapsibleTrigger>
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{sectionDescription}
|
||||||
<CollapsibleContent>
|
</p>
|
||||||
<div className="pl-7">{sectionContent}</div>
|
|
||||||
</CollapsibleContent>
|
|
||||||
</div>
|
|
||||||
</Collapsible>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-3">
|
|
||||||
{shouldShowTitle && (
|
|
||||||
<div className="flex items-start justify-between">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<Heading as="h4">{title}</Heading>
|
|
||||||
{showOverrideIndicator && level === "camera" && isOverridden && (
|
|
||||||
<Badge variant="secondary" className="text-xs">
|
|
||||||
{t("button.overridden", {
|
|
||||||
ns: "common",
|
|
||||||
defaultValue: "Overridden",
|
|
||||||
})}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
{hasChanges && (
|
|
||||||
<Badge variant="outline" className="text-xs">
|
|
||||||
{t("modified", { ns: "common", defaultValue: "Modified" })}
|
|
||||||
</Badge>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{sectionDescription && (
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
{sectionDescription}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{sectionContent}
|
{sectionContent}
|
||||||
</div>
|
</div>
|
||||||
|
<RestartDialog
|
||||||
|
isOpen={restartDialogOpen}
|
||||||
|
onClose={() => setRestartDialogOpen(false)}
|
||||||
|
onRestart={() => sendRestart("restart")}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user