- )}
- {showReplayInitSkeleton && (
+ {status.live_ready ? (
+ <>
+
+ )}
+ >
+ ) : (
@@ -595,32 +653,38 @@ export default function Replay() {
{t("page.configurationDesc")}
-
-
-
-
+ {configSchema == null ? (
+
+ ) : (
+
+
+
+
+ )}
diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx
index c74191957e..42511e7a9c 100644
--- a/web/src/pages/Settings.tsx
+++ b/web/src/pages/Settings.tsx
@@ -28,11 +28,7 @@ import useOptimisticState from "@/hooks/use-optimistic-state";
import { isMobile } from "react-device-detect";
import { FaVideo } from "react-icons/fa";
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
-import type {
- ConfigSectionData,
- JsonObject,
- JsonValue,
-} from "@/types/configForm";
+import type { ConfigSectionData, JsonObject } from "@/types/configForm";
import useSWR from "swr";
import FilterSwitch from "@/components/filter/FilterSwitch";
import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter";
@@ -93,6 +89,7 @@ import { mutate } from "swr";
import { RJSFSchema } from "@rjsf/utils";
import {
buildConfigDataForPath,
+ flattenOverrides,
parseProfileFromSectionPath,
prepareSectionSavePayload,
PROFILE_ELIGIBLE_SECTIONS,
@@ -190,25 +187,6 @@ const parsePendingDataKey = (pendingDataKey: string) => {
};
};
-const flattenOverrides = (
- value: JsonValue | undefined,
- path: string[] = [],
-): Array<{ path: string; value: JsonValue }> => {
- if (value === undefined) return [];
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
- return [{ path: path.join("."), value }];
- }
-
- const entries = Object.entries(value);
- if (entries.length === 0) {
- return [{ path: path.join("."), value: {} }];
- }
-
- return entries.flatMap(([key, entryValue]) =>
- flattenOverrides(entryValue, [...path, key]),
- );
-};
-
const createSectionPage = (
sectionKey: string,
level: "global" | "camera",
@@ -907,6 +885,7 @@ export default function Settings() {
// Refresh config from server once
await mutate("config");
+ mutate("config/raw_paths");
// Clear hasChanges in sidebar for all successfully saved sections
if (savedKeys.length > 0) {
@@ -1435,7 +1414,7 @@ export default function Settings() {
/>
)}
{showUnsavedDot && (
-
+
)}
)}
@@ -1516,7 +1495,7 @@ export default function Settings() {
-
+
{t("unsavedChanges", {
ns: "views/settings",
defaultValue: "You have unsaved changes",
@@ -2018,7 +1997,6 @@ function CameraSelectButton({
return (
{
if (!open) {
diff --git a/web/src/types/chat.ts b/web/src/types/chat.ts
index 8a1ea5443a..d9d3948b53 100644
--- a/web/src/types/chat.ts
+++ b/web/src/types/chat.ts
@@ -8,9 +8,19 @@ export type ChatMessage = {
role: "user" | "assistant";
content: string;
toolCalls?: ToolCall[];
+ stats?: ChatStats;
};
export type StartingRequest = {
label: string;
prompt: string;
};
+
+export type ChatStats = {
+ promptTokens?: number;
+ completionTokens?: number;
+ completionDurationMs?: number;
+ tokensPerSecond?: number;
+};
+
+export type ShowStatsMode = "while_generating" | "always";
diff --git a/web/src/types/configForm.ts b/web/src/types/configForm.ts
index f228de4306..03ecd3e4d9 100644
--- a/web/src/types/configForm.ts
+++ b/web/src/types/configForm.ts
@@ -13,6 +13,8 @@ export type JsonArray = JsonValue[];
export type ConfigSectionData = JsonObject;
+export type HiddenFieldEntry = string | ((config: FrigateConfig) => string[]);
+
export type ConfigFormContext = {
level?: "global" | "camera";
cameraName?: string;
@@ -42,4 +44,5 @@ export type ConfigFormContext = {
requiresRestart?: boolean;
t?: (key: string, options?: Record) => string;
renderers?: Record;
+ isProfile?: boolean;
};
diff --git a/web/src/types/frigateConfig.ts b/web/src/types/frigateConfig.ts
index 9a745b76c9..2b9a05a1a3 100644
--- a/web/src/types/frigateConfig.ts
+++ b/web/src/types/frigateConfig.ts
@@ -382,6 +382,18 @@ export type AllGroupsStreamingSettings = {
[groupName: string]: GroupStreamingSettings;
};
+export type GenAIRole = "chat" | "descriptions" | "embeddings";
+
+export type GenAIAgentConfig = {
+ api_key?: string;
+ base_url?: string;
+ model: string;
+ provider?: string;
+ roles: GenAIRole[];
+ provider_options?: Record;
+ runtime_options?: Record