diff --git a/web/src/components/config-form/sections/BaseSection.tsx b/web/src/components/config-form/sections/BaseSection.tsx index 7cfa78ab9..81d9b16f9 100644 --- a/web/src/components/config-form/sections/BaseSection.tsx +++ b/web/src/components/config-form/sections/BaseSection.tsx @@ -55,6 +55,8 @@ import { applySchemaDefaults } from "@/lib/config-schema"; import { isJsonObject } from "@/lib/utils"; import { ConfigSectionData, JsonObject, JsonValue } from "@/types/configForm"; import ActivityIndicator from "@/components/indicators/activity-indicator"; +import RestartDialog from "@/components/overlay/dialog/RestartDialog"; +import { useRestart } from "@/api/ws"; export interface SectionConfig { /** Field ordering within the section */ @@ -178,8 +180,10 @@ export function ConfigSection({ "config/cameras", "views/settings", "common", + "components/dialog", ]); const [isOpen, setIsOpen] = useState(!defaultCollapsed); + const { send: sendRestart } = useRestart(); // Create a key for this section's pending data const pendingDataKey = useMemo( @@ -212,6 +216,7 @@ export function ConfigSection({ const [isSaving, setIsSaving] = useState(false); const [formKey, setFormKey] = useState(0); const [isResetDialogOpen, setIsResetDialogOpen] = useState(false); + const [restartDialogOpen, setRestartDialogOpen] = useState(false); const isResettingRef = useRef(false); const isInitializingRef = useRef(true); @@ -562,14 +567,31 @@ export function ConfigSection({ requires_restart: needsRestart ? 1 : 0, }); - toast.success( - t(needsRestart ? "toast.successRestartRequired" : "toast.success", { - ns: "views/settings", - defaultValue: needsRestart - ? "Settings saved successfully. Restart Frigate to apply your changes." - : "Settings saved successfully", - }), - ); + if (needsRestart) { + toast.success( + t("toast.successRestartRequired", { + ns: "views/settings", + defaultValue: + "Settings saved successfully. Restart Frigate to apply your changes.", + }), + { + action: ( + setRestartDialogOpen(true)}> + + + ), + }, + ); + } else { + toast.success( + t("toast.success", { + ns: "views/settings", + defaultValue: "Settings saved successfully", + }), + ); + } setPendingData(null); refreshConfig(); @@ -933,16 +955,61 @@ export function ConfigSection({ if (collapsible) { return ( - -
- -
+ <> + +
+ +
+
+ {isOpen ? ( + + ) : ( + + )} + {title} + {showOverrideIndicator && + level === "camera" && + isOverridden && ( + + {t("button.overridden", { + ns: "common", + defaultValue: "Overridden", + })} + + )} + {hasChanges && ( + + {t("modified", { + ns: "common", + defaultValue: "Modified", + })} + + )} +
+
+
+ + +
{sectionContent}
+
+
+
+ setRestartDialogOpen(false)} + onRestart={() => sendRestart("restart")} + /> + + ); + } + + return ( + <> +
+ {shouldShowTitle && ( +
+
- {isOpen ? ( - - ) : ( - - )} {title} {showOverrideIndicator && level === "camera" && @@ -956,55 +1023,26 @@ export function ConfigSection({ )} {hasChanges && ( - {t("modified", { - ns: "common", - defaultValue: "Modified", - })} + {t("modified", { ns: "common", defaultValue: "Modified" })} )}
-
- - - -
{sectionContent}
-
-
- - ); - } - - return ( -
- {shouldShowTitle && ( -
-
-
- {title} - {showOverrideIndicator && level === "camera" && isOverridden && ( - - {t("button.overridden", { - ns: "common", - defaultValue: "Overridden", - })} - - )} - {hasChanges && ( - - {t("modified", { ns: "common", defaultValue: "Modified" })} - + {sectionDescription && ( +

+ {sectionDescription} +

)}
- {sectionDescription && ( -

- {sectionDescription} -

- )}
-
- )} + )} - {sectionContent} -
+ {sectionContent} +
+ setRestartDialogOpen(false)} + onRestart={() => sendRestart("restart")} + /> + ); }