Files
deer-flow/web/src/app/_settings/tabs/general-tab.tsx

128 lines
3.6 KiB
TypeScript
Raw Normal View History

2025-04-24 15:41:33 +08:00
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { zodResolver } from "@hookform/resolvers/zod";
import { Settings } from "lucide-react";
import { useEffect, useMemo } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import type { SettingsState } from "~/core/store";
import type { Tab } from "./types";
const generalFormSchema = z.object({
maxPlanIterations: z.number().min(1, {
message: "Max plan iterations must be at least 1.",
}),
maxStepNum: z.number().min(1, {
message: "Max step number must be at least 1.",
}),
});
export const GeneralTab: Tab = ({
settings,
onChange,
}: {
settings: SettingsState;
onChange: (changes: Partial<SettingsState>) => void;
}) => {
const generalSettings = useMemo(() => settings.general, [settings]);
const form = useForm<z.infer<typeof generalFormSchema>>({
resolver: zodResolver(generalFormSchema, undefined, undefined),
values: generalSettings,
});
const currentSettings = form.watch();
useEffect(() => {
let hasChanges = false;
for (const key in currentSettings) {
if (
currentSettings[key as keyof typeof currentSettings] !==
settings.general[key as keyof SettingsState["general"]]
) {
hasChanges = true;
break;
}
}
if (hasChanges) {
onChange({ general: currentSettings });
}
}, [currentSettings, onChange, settings]);
return (
<div className="flex flex-col gap-4">
<header>
<h1 className="text-lg font-medium">General</h1>
</header>
<main>
<Form {...form}>
<form className="space-y-8">
<FormField
control={form.control}
name="maxPlanIterations"
render={({ field }) => (
<FormItem>
<FormLabel>Max plan iterations</FormLabel>
<FormControl>
<Input
className="w-60"
type="number"
{...field}
min={1}
onChange={(event) =>
field.onChange(parseInt(event.target.value))
}
/>
</FormControl>
<FormDescription>
Set to 1 for single-step planning. Set to 2 to enable
re-planning.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="maxStepNum"
render={({ field }) => (
<FormItem>
<FormLabel>Max steps of a research plan</FormLabel>
<FormControl>
<Input
className="w-60"
type="number"
{...field}
min={1}
onChange={(event) =>
field.onChange(parseInt(event.target.value))
}
/>
</FormControl>
<FormDescription>
By default, each research plan has 3 steps.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</main>
</div>
);
};
GeneralTab.displayName = "";
GeneralTab.icon = Settings;