Miscellaneous fixes (#23186)

* improve scroll handling for non-modal DropdownMenu in classification and face selection dialogs

* clean up

* fix incorrect key capitalization

* fix profile array overrides not replacing base arrays

don't use lodash merge(), it does positional merging and an empty source array doesn't override the destination, and shorter arrays leak destination elements through.

backend is unaffected, so the saved config and actual backend functionality was right

* only show audio debug tab when audio is enabled in config

* move apple_compatibility out of advanced

* remove retry_interval from UI

99% of users should never be changing this

* hide switch in optionalfieldwidget if editing a profile

* add override badges for cameras and profiles

collect shared functions into the config util and separate hooks

* Use new models endpoint info to determine modalities

* clarify language

* fix linter

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
Josh Hawkins
2026-05-13 11:04:11 -05:00
committed by GitHub
co-authored by Nicolas Mowen
parent bd1fc1cc72
commit ca75f06456
19 changed files with 783 additions and 379 deletions
@@ -33,6 +33,7 @@ import { getTranslatedLabel } from "@/utils/i18n";
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
import { AudioLevelGraph } from "@/components/audio/AudioLevelGraph";
import { useWs } from "@/api/ws";
import { cn } from "@/lib/utils";
type ObjectSettingsViewProps = {
selectedCamera?: string;
@@ -200,15 +201,18 @@ export default function ObjectSettingsView({
<Tabs defaultValue="debug" className="w-full">
<TabsList
className={`grid w-full ${cameraConfig.ffmpeg.inputs.some((input) => input.roles.includes("audio")) ? "grid-cols-3" : "grid-cols-2"}`}
className={cn(
"grid w-full",
cameraConfig.audio.enabled_in_config
? "grid-cols-3"
: "grid-cols-2",
)}
>
<TabsTrigger value="debug">{t("debug.debugging")}</TabsTrigger>
<TabsTrigger value="objectlist">
{t("debug.objectList")}
</TabsTrigger>
{cameraConfig.ffmpeg.inputs.some((input) =>
input.roles.includes("audio"),
) && (
{cameraConfig.audio.enabled_in_config && (
<TabsTrigger value="audio">{t("debug.audio.title")}</TabsTrigger>
)}
</TabsList>
@@ -325,9 +329,7 @@ export default function ObjectSettingsView({
<TabsContent value="objectlist">
<ObjectList cameraConfig={cameraConfig} objects={memoizedObjects} />
</TabsContent>
{cameraConfig.ffmpeg.inputs.some((input) =>
input.roles.includes("audio"),
) && (
{cameraConfig.audio.enabled_in_config && (
<TabsContent value="audio">
<AudioList
cameraConfig={cameraConfig}
+39 -66
View File
@@ -3,18 +3,14 @@ import { useTranslation } from "react-i18next";
import type { SectionConfig } from "@/components/config-form/sections";
import { ConfigSectionTemplate } from "@/components/config-form/sections";
import { CameraOverridesBadge } from "@/components/config-form/sections/CameraOverridesBadge";
import { GlobalOverridesBadge } from "@/components/config-form/sections/GlobalOverridesBadge";
import { ProfileOverridesBadge } from "@/components/config-form/sections/ProfileOverridesBadge";
import type { PolygonType } from "@/types/canvas";
import { Badge } from "@/components/ui/badge";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { ConfigSectionData } from "@/types/configForm";
import type { ProfileState } from "@/types/profile";
import { getSectionConfig } from "@/utils/configUtil";
import { getProfileColor } from "@/utils/profileColors";
import { cn } from "@/lib/utils";
import { useDocDomain } from "@/hooks/use-doc-domain";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
@@ -173,46 +169,25 @@ export function SingleSectionPage({
)}
{level === "camera" &&
showOverrideIndicator &&
sectionStatus.isOverridden && (
<Tooltip>
<TooltipTrigger asChild>
<Badge
variant="secondary"
className={cn(
"cursor-default border-2 text-center text-xs text-primary-variant",
sectionStatus.overrideSource === "profile" &&
profileColor
? profileColor.border
: "border-selected",
)}
>
{sectionStatus.overrideSource === "profile"
? t("button.overriddenBaseConfig", {
ns: "views/settings",
defaultValue: "Overridden (Base Config)",
})
: t("button.overriddenGlobal", {
ns: "views/settings",
defaultValue: "Overridden (Global)",
})}
</Badge>
</TooltipTrigger>
<TooltipContent>
{sectionStatus.overrideSource === "profile"
? t("button.overriddenBaseConfigTooltip", {
ns: "views/settings",
profile: currentEditingProfile
? (profileState?.profileFriendlyNames.get(
currentEditingProfile,
) ?? currentEditingProfile)
: "",
})
: t("button.overriddenGlobalTooltip", {
ns: "views/settings",
})}
</TooltipContent>
</Tooltip>
)}
sectionStatus.isOverridden &&
selectedCamera &&
(sectionStatus.overrideSource === "profile" &&
currentEditingProfile ? (
<ProfileOverridesBadge
sectionPath={sectionKey}
cameraName={selectedCamera}
profileName={currentEditingProfile}
profileFriendlyName={profileState?.profileFriendlyNames.get(
currentEditingProfile,
)}
profileBorderColor={profileColor?.border}
/>
) : (
<GlobalOverridesBadge
sectionPath={sectionKey}
cameraName={selectedCamera}
/>
))}
{sectionStatus.hasChanges && (
<Badge
variant="secondary"
@@ -233,27 +208,25 @@ export function SingleSectionPage({
)}
{level === "camera" &&
showOverrideIndicator &&
sectionStatus.isOverridden && (
<Badge
variant="secondary"
className={cn(
"cursor-default border-2 text-center text-xs text-primary-variant",
sectionStatus.overrideSource === "profile" && profileColor
? profileColor.border
: "border-selected",
sectionStatus.isOverridden &&
selectedCamera &&
(sectionStatus.overrideSource === "profile" &&
currentEditingProfile ? (
<ProfileOverridesBadge
sectionPath={sectionKey}
cameraName={selectedCamera}
profileName={currentEditingProfile}
profileFriendlyName={profileState?.profileFriendlyNames.get(
currentEditingProfile,
)}
>
{sectionStatus.overrideSource === "profile"
? t("button.overriddenBaseConfig", {
ns: "views/settings",
defaultValue: "Overridden (Base Config)",
})
: t("button.overriddenGlobal", {
ns: "views/settings",
defaultValue: "Overridden (Global)",
})}
</Badge>
)}
profileBorderColor={profileColor?.border}
/>
) : (
<GlobalOverridesBadge
sectionPath={sectionKey}
cameraName={selectedCamera}
/>
))}
{sectionStatus.hasChanges && (
<Badge
variant="secondary"