mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-21 15:48:22 +03:00
clean up camera inputs fields
This commit is contained in:
parent
afeb03a32f
commit
ef665a8c3d
@ -1252,7 +1252,7 @@
|
|||||||
"manualPlaceholder": "Enter FFmpeg arguments"
|
"manualPlaceholder": "Enter FFmpeg arguments"
|
||||||
},
|
},
|
||||||
"cameraInputs": {
|
"cameraInputs": {
|
||||||
"itemTitle": "Stream {{index}}: {{path}}"
|
"itemTitle": "Stream {{index}}"
|
||||||
},
|
},
|
||||||
"restartRequiredField": "Restart required",
|
"restartRequiredField": "Restart required",
|
||||||
"restartRequiredFooter": "Configuration changed - Restart required",
|
"restartRequiredFooter": "Configuration changed - Restart required",
|
||||||
|
|||||||
@ -30,6 +30,7 @@ const ffmpeg: SectionConfigOverrides = {
|
|||||||
output_args: "/configuration/ffmpeg_presets#output-args-presets",
|
output_args: "/configuration/ffmpeg_presets#output-args-presets",
|
||||||
"inputs.output_args": "/configuration/ffmpeg_presets#output-args-presets",
|
"inputs.output_args": "/configuration/ffmpeg_presets#output-args-presets",
|
||||||
"output_args.record": "/configuration/ffmpeg_presets#output-args-presets",
|
"output_args.record": "/configuration/ffmpeg_presets#output-args-presets",
|
||||||
|
"inputs.roles": "/configuration/cameras/#setting-up-camera-inputs",
|
||||||
},
|
},
|
||||||
restartRequired: [],
|
restartRequired: [],
|
||||||
fieldOrder: [
|
fieldOrder: [
|
||||||
@ -85,6 +86,9 @@ const ffmpeg: SectionConfigOverrides = {
|
|||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
"ui:widget": "inputRoles",
|
"ui:widget": "inputRoles",
|
||||||
|
"ui:options": {
|
||||||
|
showArrayItemDescription: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
global_args: {
|
global_args: {
|
||||||
"ui:widget": "hidden",
|
"ui:widget": "hidden",
|
||||||
@ -92,10 +96,13 @@ const ffmpeg: SectionConfigOverrides = {
|
|||||||
hwaccel_args: ffmpegArgsWidget("hwaccel_args", {
|
hwaccel_args: ffmpegArgsWidget("hwaccel_args", {
|
||||||
allowInherit: true,
|
allowInherit: true,
|
||||||
hideDescription: true,
|
hideDescription: true,
|
||||||
|
forceSplitLayout: true,
|
||||||
showArrayItemDescription: true,
|
showArrayItemDescription: true,
|
||||||
}),
|
}),
|
||||||
input_args: ffmpegArgsWidget("input_args", {
|
input_args: ffmpegArgsWidget("input_args", {
|
||||||
|
allowInherit: true,
|
||||||
hideDescription: true,
|
hideDescription: true,
|
||||||
|
forceSplitLayout: true,
|
||||||
showArrayItemDescription: true,
|
showArrayItemDescription: true,
|
||||||
}),
|
}),
|
||||||
output_args: {
|
output_args: {
|
||||||
|
|||||||
@ -87,7 +87,7 @@ const normalizeNonDetectHwaccel = (inputs: FfmpegInput[]): FfmpegInput[] =>
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...input,
|
...input,
|
||||||
hwaccel_args: null,
|
hwaccel_args: undefined,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -311,8 +311,9 @@ export function CameraInputsField(props: FieldProps) {
|
|||||||
const itemTitle = t("configForm.cameraInputs.itemTitle", {
|
const itemTitle = t("configForm.cameraInputs.itemTitle", {
|
||||||
ns: "views/settings",
|
ns: "views/settings",
|
||||||
index: index + 1,
|
index: index + 1,
|
||||||
path: typeof input.path === "string" ? input.path.trim() : "",
|
|
||||||
});
|
});
|
||||||
|
const itemPath =
|
||||||
|
typeof input.path === "string" ? input.path.trim() : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card key={`${baseId}-${index}`} className="w-full">
|
<Card key={`${baseId}-${index}`} className="w-full">
|
||||||
@ -328,7 +329,14 @@ export function CameraInputsField(props: FieldProps) {
|
|||||||
<CollapsibleTrigger asChild>
|
<CollapsibleTrigger asChild>
|
||||||
<CardHeader className="cursor-pointer p-4 transition-colors hover:bg-muted/50">
|
<CardHeader className="cursor-pointer p-4 transition-colors hover:bg-muted/50">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<CardTitle className="text-sm">{itemTitle}</CardTitle>
|
<CardTitle className="text-sm">
|
||||||
|
<span>{itemTitle}</span>
|
||||||
|
{itemPath ? (
|
||||||
|
<span className="mt-1 block text-xs font-normal text-muted-foreground">
|
||||||
|
{itemPath}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</CardTitle>
|
||||||
{open ? (
|
{open ? (
|
||||||
<LuChevronDown className="h-4 w-4" />
|
<LuChevronDown className="h-4 w-4" />
|
||||||
) : (
|
) : (
|
||||||
@ -352,11 +360,7 @@ export function CameraInputsField(props: FieldProps) {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">{renderField(index, "roles")}</div>
|
||||||
{renderField(index, "roles", {
|
|
||||||
showSchemaDescription: true,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{renderField(index, "input_args")}
|
{renderField(index, "input_args")}
|
||||||
|
|
||||||
|
|||||||
@ -135,9 +135,10 @@ export function FieldTemplate(props: FieldTemplateProps) {
|
|||||||
!isMultiSchemaWrapper &&
|
!isMultiSchemaWrapper &&
|
||||||
!isObjectField &&
|
!isObjectField &&
|
||||||
!isAdditionalProperty;
|
!isAdditionalProperty;
|
||||||
|
const forceSplitLayout = uiOptionsFromSchema.forceSplitLayout === true;
|
||||||
const useSplitLayout =
|
const useSplitLayout =
|
||||||
uiOptionsFromSchema.splitLayout !== false &&
|
uiOptionsFromSchema.splitLayout !== false &&
|
||||||
isScalarValueField &&
|
(isScalarValueField || forceSplitLayout) &&
|
||||||
!isBoolean &&
|
!isBoolean &&
|
||||||
!isMultiSchemaWrapper &&
|
!isMultiSchemaWrapper &&
|
||||||
!isObjectField &&
|
!isObjectField &&
|
||||||
|
|||||||
@ -64,6 +64,10 @@ const resolveMode = (
|
|||||||
return "inherit";
|
return "inherit";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allowInherit && Array.isArray(value) && value.length === 0) {
|
||||||
|
return "inherit";
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return "manual";
|
return "manual";
|
||||||
}
|
}
|
||||||
@ -116,6 +120,7 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
const presetField = options?.ffmpegPresetField as PresetField | undefined;
|
const presetField = options?.ffmpegPresetField as PresetField | undefined;
|
||||||
const allowInherit = options?.allowInherit === true;
|
const allowInherit = options?.allowInherit === true;
|
||||||
const hideDescription = options?.hideDescription === true;
|
const hideDescription = options?.hideDescription === true;
|
||||||
|
const useSplitLayout = options?.splitLayout !== false;
|
||||||
|
|
||||||
const { data } = useSWR<FfmpegPresetResponse>("ffmpeg/presets");
|
const { data } = useSWR<FfmpegPresetResponse>("ffmpeg/presets");
|
||||||
|
|
||||||
@ -148,7 +153,7 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
setMode(nextMode);
|
setMode(nextMode);
|
||||||
|
|
||||||
if (nextMode === "inherit") {
|
if (nextMode === "inherit") {
|
||||||
onChange(null);
|
onChange(undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,10 +169,15 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode === "preset") {
|
||||||
|
onChange("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const manualText = normalizeManualText(value);
|
const manualText = normalizeManualText(value);
|
||||||
onChange(manualText);
|
onChange(manualText);
|
||||||
},
|
},
|
||||||
[onChange, presetOptions, value],
|
[mode, onChange, presetOptions, value],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlePresetChange = useCallback(
|
const handlePresetChange = useCallback(
|
||||||
@ -237,6 +247,23 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
onValueChange={(next) => handleModeChange(next as FfmpegArgsMode)}
|
onValueChange={(next) => handleModeChange(next as FfmpegArgsMode)}
|
||||||
className="gap-3"
|
className="gap-3"
|
||||||
>
|
>
|
||||||
|
{allowInherit ? (
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem
|
||||||
|
value="inherit"
|
||||||
|
id={`${id}-inherit`}
|
||||||
|
disabled={disabled || readonly}
|
||||||
|
className={
|
||||||
|
mode === "inherit"
|
||||||
|
? "bg-selected from-selected/50 to-selected/90 text-selected"
|
||||||
|
: "bg-secondary from-secondary/50 to-secondary/90 text-secondary"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<label htmlFor={`${id}-inherit`} className="cursor-pointer text-sm">
|
||||||
|
{t("configForm.ffmpegArgs.inherit", { ns: "views/settings" })}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem
|
<RadioGroupItem
|
||||||
value="preset"
|
value="preset"
|
||||||
@ -267,23 +294,6 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
{t("configForm.ffmpegArgs.manual", { ns: "views/settings" })}
|
{t("configForm.ffmpegArgs.manual", { ns: "views/settings" })}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{allowInherit ? (
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem
|
|
||||||
value="inherit"
|
|
||||||
id={`${id}-inherit`}
|
|
||||||
disabled={disabled || readonly}
|
|
||||||
className={
|
|
||||||
mode === "inherit"
|
|
||||||
? "bg-selected from-selected/50 to-selected/90 text-selected"
|
|
||||||
: "bg-secondary from-secondary/50 to-secondary/90 text-secondary"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<label htmlFor={`${id}-inherit`} className="cursor-pointer text-sm">
|
|
||||||
{t("configForm.ffmpegArgs.inherit", { ns: "views/settings" })}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
{mode === "inherit" ? null : mode === "preset" && canUsePresets ? (
|
{mode === "inherit" ? null : mode === "preset" && canUsePresets ? (
|
||||||
@ -292,7 +302,7 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
onValueChange={handlePresetChange}
|
onValueChange={handlePresetChange}
|
||||||
disabled={disabled || readonly}
|
disabled={disabled || readonly}
|
||||||
>
|
>
|
||||||
<SelectTrigger id={id} className="w-full">
|
<SelectTrigger id={id} className="w-full md:max-w-md">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={
|
||||||
placeholder ||
|
placeholder ||
|
||||||
@ -326,7 +336,7 @@ export function FfmpegArgsWidget(props: WidgetProps) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!hideDescription && fieldDescription ? (
|
{!hideDescription && !useSplitLayout && fieldDescription ? (
|
||||||
<p className="text-xs text-muted-foreground">{fieldDescription}</p>
|
<p className="text-xs text-muted-foreground">{fieldDescription}</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -35,31 +35,33 @@ export function InputRolesWidget(props: WidgetProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2 rounded-lg bg-secondary p-2 pr-0 md:max-w-md">
|
<div className="rounded-lg border border-secondary-highlight bg-background_alt p-2 pr-0 md:max-w-md">
|
||||||
{INPUT_ROLES.map((role) => {
|
<div className="grid gap-2">
|
||||||
const checked = selectedRoles.includes(role);
|
{INPUT_ROLES.map((role) => {
|
||||||
const label = t(`configForm.inputRoles.options.${role}`, {
|
const checked = selectedRoles.includes(role);
|
||||||
ns: "views/settings",
|
const label = t(`configForm.inputRoles.options.${role}`, {
|
||||||
defaultValue: role,
|
ns: "views/settings",
|
||||||
});
|
defaultValue: role,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={role}
|
key={role}
|
||||||
className="flex items-center justify-between rounded-md px-3 py-0"
|
className="flex items-center justify-between rounded-md px-3 py-0"
|
||||||
>
|
>
|
||||||
<label htmlFor={`${id}-${role}`} className="text-sm">
|
<label htmlFor={`${id}-${role}`} className="text-sm">
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
<Switch
|
<Switch
|
||||||
id={`${id}-${role}`}
|
id={`${id}-${role}`}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
disabled={disabled || readonly}
|
disabled={disabled || readonly}
|
||||||
onCheckedChange={(enabled) => toggleRole(role, !!enabled)}
|
onCheckedChange={(enabled) => toggleRole(role, !!enabled)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user