mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
refactor: migrate radix-ui to base-ui
This commit is contained in:
@@ -10,8 +10,8 @@ import {
|
||||
WaypointsIcon,
|
||||
ZapIcon,
|
||||
} from "lucide-react";
|
||||
import { type JSX, useCallback, useEffect, useState } from "react";
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { type JSX, useCallback, useRef, useState } from "react";
|
||||
import { Controller, type UseFormReturn, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AntSwordTabContent } from "@/components/memshell/tabs/antsword-tab";
|
||||
import { BehinderTabContent } from "@/components/memshell/tabs/behinder-tab";
|
||||
@@ -22,15 +22,12 @@ import { NeoRegTabContent } from "@/components/memshell/tabs/neoreg-tab";
|
||||
import { Suo5TabContent } from "@/components/memshell/tabs/suo5-tab";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/components/ui/field";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
@@ -52,6 +49,7 @@ import {
|
||||
ShellToolType,
|
||||
} from "@/types/memshell";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { Spinner } from "../ui/spinner";
|
||||
|
||||
const shellToolIcons: Record<ShellToolType, JSX.Element> = {
|
||||
[ShellToolType.Behinder]: <ShieldOffIcon className="h-4 w-4" />,
|
||||
@@ -67,7 +65,7 @@ const shellToolIcons: Record<ShellToolType, JSX.Element> = {
|
||||
const defaultServerVersionOptions = [
|
||||
{
|
||||
name: "Unknown",
|
||||
value: "unknown",
|
||||
value: "Unknown",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -80,32 +78,21 @@ export default function MainConfigCard({
|
||||
form: UseFormReturn<MemShellFormSchema>;
|
||||
servers?: ServerConfig;
|
||||
}>) {
|
||||
const { t } = useTranslation(["common", "memshell"]);
|
||||
|
||||
const [shellToolMap, setShellToolMap] = useState<{
|
||||
[toolName: string]: string[];
|
||||
}>();
|
||||
const [shellTools, setShellTools] = useState<ShellToolType[]>([
|
||||
ShellToolType.Godzilla,
|
||||
ShellToolType.Behinder,
|
||||
ShellToolType.AntSword,
|
||||
ShellToolType.Command,
|
||||
ShellToolType.Suo5,
|
||||
ShellToolType.NeoreGeorg,
|
||||
ShellToolType.Custom,
|
||||
]);
|
||||
const [shellTools, setShellTools] = useState<ShellToolType[]>([]);
|
||||
const [shellTypes, setShellTypes] = useState<string[]>([]);
|
||||
const shellTool = form.watch("shellTool");
|
||||
const { t } = useTranslation(["common", "memshell"]);
|
||||
|
||||
const [serverVersionOptions, setServerVersionOptions] = useState(
|
||||
defaultServerVersionOptions,
|
||||
);
|
||||
|
||||
// 处理一下 shellTypes 由于 server 或 shellTool 变更时无法正常为 form.shellType 赋值的问题
|
||||
useEffect(() => {
|
||||
if (shellTypes.length > 0) {
|
||||
form.setValue("shellType", shellTypes[0]);
|
||||
}
|
||||
}, [shellTypes, form]);
|
||||
const shellTool = useWatch({
|
||||
control: form.control,
|
||||
name: "shellTool",
|
||||
});
|
||||
|
||||
const handleServerChange = useCallback(
|
||||
(value: string) => {
|
||||
@@ -132,7 +119,10 @@ export default function MainConfigCard({
|
||||
}
|
||||
setShellTypes(currentShellTypes);
|
||||
|
||||
// 特殊环境的 JDK 版本
|
||||
if (currentShellTypes && currentShellTypes.length > 0) {
|
||||
form.setValue("shellType", currentShellTypes[0]);
|
||||
}
|
||||
|
||||
if (
|
||||
(value === "SpringWebFlux" || value === "XXLJOB") &&
|
||||
Number.parseInt(form.getValues("targetJdkVersion") as string, 10) < 52
|
||||
@@ -142,7 +132,6 @@ export default function MainConfigCard({
|
||||
form.setValue("targetJdkVersion", "50");
|
||||
}
|
||||
|
||||
// 特殊的服务需要指定版本
|
||||
if (value === "TongWeb") {
|
||||
setServerVersionOptions([
|
||||
...defaultServerVersionOptions,
|
||||
@@ -169,16 +158,6 @@ export default function MainConfigCard({
|
||||
[form, mainConfig],
|
||||
);
|
||||
|
||||
// 处理一下默认值 server 不刷新 shellType 的问题
|
||||
useEffect(() => {
|
||||
if (mainConfig) {
|
||||
const initialServer = form.getValues("server");
|
||||
if (initialServer && mainConfig[initialServer]) {
|
||||
handleServerChange(initialServer);
|
||||
}
|
||||
}
|
||||
}, [mainConfig, form, handleServerChange]);
|
||||
|
||||
const handleShellToolChange = useCallback(
|
||||
(value: string) => {
|
||||
const resetCommand = () => {
|
||||
@@ -229,6 +208,11 @@ export default function MainConfigCard({
|
||||
}
|
||||
setShellTypes(currentShellTypes);
|
||||
|
||||
// 直接设置 shellType 而不是依赖 useEffect
|
||||
if (currentShellTypes && currentShellTypes.length > 0) {
|
||||
form.setValue("shellType", currentShellTypes[0]);
|
||||
}
|
||||
|
||||
form.resetField("urlPattern");
|
||||
form.resetField("shellClassName");
|
||||
form.resetField("injectorClassName");
|
||||
@@ -253,8 +237,17 @@ export default function MainConfigCard({
|
||||
[form, servers, shellToolMap],
|
||||
);
|
||||
|
||||
const initializedRef = useRef(false);
|
||||
if (!initializedRef.current && mainConfig) {
|
||||
const initialServer = form.getValues("server");
|
||||
if (initialServer && mainConfig[initialServer]) {
|
||||
handleServerChange(initialServer);
|
||||
initializedRef.current = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<>
|
||||
<Card>
|
||||
<CardHeader className="pb-1">
|
||||
<CardTitle className="text-md flex items-center gap-2">
|
||||
@@ -263,284 +256,300 @@ export default function MainConfigCard({
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="server"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:server")}</FormFieldLabel>
|
||||
<Select
|
||||
onValueChange={(v) => {
|
||||
field.onChange(v);
|
||||
handleServerChange(v);
|
||||
}}
|
||||
value={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{Object.keys(servers ?? {}).map((server: string) => (
|
||||
<SelectItem key={server} value={server}>
|
||||
{server}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription className="flex items-center">
|
||||
{t("memshell:tips.targetServerNotFound")}
|
||||
<a
|
||||
href="https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex items-center underline"
|
||||
{!mainConfig ? (
|
||||
<div className="flex items-center justify-center p-4 gap-4 h-100">
|
||||
<Spinner />
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("loading")}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="server"
|
||||
render={({ field }) => (
|
||||
<Field>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="server">
|
||||
{t("common:server")}
|
||||
</FieldLabel>
|
||||
<Select
|
||||
onValueChange={(v) => {
|
||||
field.onChange(v);
|
||||
handleServerChange(v as string);
|
||||
}}
|
||||
value={field.value}
|
||||
>
|
||||
<SelectTrigger id="server">
|
||||
<SelectValue
|
||||
data-placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.keys(servers ?? {}).map(
|
||||
(server: string) => (
|
||||
<SelectItem key={server} value={server}>
|
||||
{server}
|
||||
</SelectItem>
|
||||
),
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription className="flex items-center">
|
||||
{t("memshell:tips.targetServerNotFound")}
|
||||
<a
|
||||
href="https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex items-center underline"
|
||||
>
|
||||
{t("memshell:tips.targetServerRequest")}
|
||||
<ArrowUpRightIcon className="h-4" />
|
||||
</a>
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="serverVersion"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field
|
||||
orientation="vertical"
|
||||
data-invalid={fieldState.invalid}
|
||||
>
|
||||
{t("memshell:tips.targetServerRequest")}
|
||||
<ArrowUpRightIcon className="h-4" />
|
||||
</a>
|
||||
</FormDescription>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="serverVersion"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:serverVersion")}</FormFieldLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{serverVersionOptions.map((v) => (
|
||||
<SelectItem key={v.value} value={v.value}>
|
||||
{v.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shellTool"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:shellTool")}</FormFieldLabel>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={(v) => handleShellToolChange(v)}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{shellTools.map((tool) => (
|
||||
<SelectItem key={tool} value={tool}>
|
||||
<span className="flex items-center gap-2">
|
||||
{shellToolIcons[tool]}
|
||||
{tool}
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 mt-4 flex-col lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="debug"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="debug"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<FormLabel htmlFor="debug">{t("common:debug")}</FormLabel>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:debug.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="probe"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="probe"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<Label htmlFor="probe">{t("common:probe")}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:probe.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="byPassJavaModule"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="bypass"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<Label htmlFor="bypass">
|
||||
{t("common:byPassJavaModule")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:byPassJavaModule.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lambdaSuffix"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="lambdaSuffix"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<Label htmlFor="lambdaSuffix">
|
||||
{t("common:lambdaSuffix")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:lambdaSuffix.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shrink"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="shrink"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<Label htmlFor="shrink">{t("common:shrink")}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:shrink.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="staticInitialize"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="staticInitialize"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex items-center gap-1">
|
||||
<Label htmlFor="staticInitialize">
|
||||
{t("common:staticInitialize")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:staticInitialize.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="serverVersion">
|
||||
{t("common:serverVersion")}
|
||||
</FieldLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
>
|
||||
<SelectTrigger
|
||||
id="serverVersion"
|
||||
aria-invalid={fieldState.invalid}
|
||||
>
|
||||
<SelectValue
|
||||
data-placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{serverVersionOptions.map((v) => (
|
||||
<SelectItem key={v.value} value={v.value}>
|
||||
{v.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{fieldState.error && (
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
)}
|
||||
</FieldContent>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shellTool"
|
||||
render={({ field }) => (
|
||||
<Field>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="shellTool">
|
||||
{t("common:shellTool")}
|
||||
</FieldLabel>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={(v) =>
|
||||
handleShellToolChange(v as string)
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="shellTool">
|
||||
<SelectValue
|
||||
data-placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{shellTools.map((tool) => (
|
||||
<SelectItem key={tool} value={tool}>
|
||||
<span className="flex items-center gap-2">
|
||||
{shellToolIcons[tool]}
|
||||
{tool}
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 mt-4 flex-col lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="debug"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="debug"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="debug">{t("common:debug")}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:debug.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="probe"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="probe"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="probe">{t("common:probe")}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:probe.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="byPassJavaModule"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="bypass"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="bypass">
|
||||
{t("common:byPassJavaModule")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:byPassJavaModule.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="lambdaSuffix"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="lambdaSuffix"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="lambdaSuffix">
|
||||
{t("common:lambdaSuffix")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:lambdaSuffix.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shrink"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="shrink"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="shrink">{t("common:shrink")}</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:shrink.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="staticInitialize"
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
id="staticInitialize"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<Label htmlFor="staticInitialize">
|
||||
{t("common:staticInitialize")}
|
||||
</Label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:staticInitialize.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Tabs value={shellTool} className="w-full">
|
||||
<GodzillaTabContent form={form} shellTypes={shellTypes} />
|
||||
<CommandTabContent form={form} shellTypes={shellTypes} />
|
||||
<BehinderTabContent form={form} shellTypes={shellTypes} />
|
||||
<AntSwordTabContent form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent tabValue="Suo5" form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent tabValue="Suo5v2" form={form} shellTypes={shellTypes} />
|
||||
<NeoRegTabContent form={form} shellTypes={shellTypes} />
|
||||
<CustomTabContent form={form} shellTypes={shellTypes} />
|
||||
</Tabs>
|
||||
</FormProvider>
|
||||
{mainConfig && (
|
||||
<Tabs value={shellTool} className="w-full">
|
||||
<GodzillaTabContent form={form} shellTypes={shellTypes} />
|
||||
<CommandTabContent form={form} shellTypes={shellTypes} />
|
||||
<BehinderTabContent form={form} shellTypes={shellTypes} />
|
||||
<AntSwordTabContent form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent tabValue="Suo5" form={form} shellTypes={shellTypes} />
|
||||
<Suo5TabContent
|
||||
tabValue="Suo5v2"
|
||||
form={form}
|
||||
shellTypes={shellTypes}
|
||||
/>
|
||||
<NeoRegTabContent form={form} shellTypes={shellTypes} />
|
||||
<CustomTabContent form={form} shellTypes={shellTypes} />
|
||||
</Tabs>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import { PackageIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { useMemo } from "react";
|
||||
import { Controller, type UseFormReturn, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from "@/components/ui/form";
|
||||
import { FieldLabel, FieldSet } from "@/components/ui/field";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { PackerConfig } from "@/types/memshell";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
|
||||
type Option = {
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export default function PackageConfigCard({
|
||||
packerConfig,
|
||||
form,
|
||||
@@ -25,13 +16,19 @@ export default function PackageConfigCard({
|
||||
packerConfig: PackerConfig | undefined;
|
||||
form: UseFormReturn<MemShellFormSchema>;
|
||||
}>) {
|
||||
const [options, setOptions] = useState<Array<Option>>([]);
|
||||
|
||||
const shellType = form.watch("shellType");
|
||||
const server = form.watch("server");
|
||||
const { t } = useTranslation("common");
|
||||
|
||||
useEffect(() => {
|
||||
const shellType = useWatch({
|
||||
control: form.control,
|
||||
name: "shellType",
|
||||
});
|
||||
|
||||
const server = useWatch({
|
||||
control: form.control,
|
||||
name: "server",
|
||||
});
|
||||
|
||||
const options = useMemo(() => {
|
||||
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
||||
if (!shellType || shellType === " ") {
|
||||
return true;
|
||||
@@ -44,23 +41,12 @@ export default function PackageConfigCard({
|
||||
}
|
||||
return !name.startsWith("Agent") && !name.toLowerCase().startsWith("xxl");
|
||||
});
|
||||
|
||||
const mappedOptions = filteredOptions.map((name) => {
|
||||
return {
|
||||
name: t(name),
|
||||
value: name,
|
||||
};
|
||||
});
|
||||
|
||||
setOptions(mappedOptions);
|
||||
const currentValue = form.getValues("packingMethod");
|
||||
if (
|
||||
filteredOptions.length > 0 &&
|
||||
(!currentValue || !filteredOptions.includes(currentValue))
|
||||
) {
|
||||
form.setValue("packingMethod", filteredOptions[0]);
|
||||
}
|
||||
}, [form, packerConfig, server, shellType, t]);
|
||||
form.setValue("packingMethod", filteredOptions[0]);
|
||||
return filteredOptions.map((name) => ({
|
||||
name: t(name),
|
||||
value: name,
|
||||
}));
|
||||
}, [packerConfig, shellType, server, t, form]);
|
||||
|
||||
return (
|
||||
<Card className="w-full">
|
||||
@@ -72,41 +58,34 @@ export default function PackageConfigCard({
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{options.length > 0 ? (
|
||||
<FormProvider {...form}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="packingMethod"
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-3">
|
||||
<FormLabel>{t("packerMethod")}</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
className="grid grid-cols-2 md:grid-cols-3"
|
||||
>
|
||||
{options.map(({ name, value }) => (
|
||||
<FormItem
|
||||
key={value}
|
||||
className="flex items-center space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<RadioGroupItem value={value} id={value} />
|
||||
</FormControl>
|
||||
<FormLabel className="text-xs" htmlFor={value}>
|
||||
{name}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormProvider>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="packingMethod"
|
||||
render={({ field }) => (
|
||||
<FieldSet>
|
||||
<FieldLabel>{t("packerMethod")}</FieldLabel>
|
||||
<RadioGroup
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
defaultValue={options[0].value}
|
||||
onValueChange={field.onChange}
|
||||
className="grid grid-cols-2 md:grid-cols-3"
|
||||
>
|
||||
{options.map(({ name, value }) => (
|
||||
<div key={value} className="flex items-center space-x-3">
|
||||
<RadioGroupItem value={value} id={value} />
|
||||
<FieldLabel className="text-xs" htmlFor={value}>
|
||||
{name}
|
||||
</FieldLabel>
|
||||
</div>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center p-4 space-x-2">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
<div className="flex items-center justify-center p-4 gap-4 h-50">
|
||||
<Spinner />
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("loading")}
|
||||
</span>
|
||||
|
||||
@@ -7,13 +7,13 @@ export function QuickUsage() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-md flex items-center gap-2">
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<ScrollTextIcon className="h-5" />
|
||||
<span>{t("common:quickUsage.title")}</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ol className="list-decimal list-inside space-y-4 text-sm">
|
||||
<ol className="flex flex-col gap-4 list-decimal list-inside text-sm">
|
||||
<li>{t("memshell:quickUsage.step1")}</li>
|
||||
<li>{t("memshell:quickUsage.step2")}</li>
|
||||
<li>{t("memshell:quickUsage.step3")}</li>
|
||||
|
||||
@@ -79,7 +79,7 @@ export function MultiPackResult({
|
||||
<div className="flex items-center justify-between text-xs gap-2">
|
||||
<Select
|
||||
onValueChange={(value) => {
|
||||
setSelectedMethod(value);
|
||||
setSelectedMethod(value as string);
|
||||
setPackResult(
|
||||
allPackResults?.[value as keyof typeof allPackResults] ?? "",
|
||||
);
|
||||
@@ -90,7 +90,7 @@ export function MultiPackResult({
|
||||
<span className="text-muted-foreground">
|
||||
{t("common:packerMethod")}:
|
||||
</span>
|
||||
<SelectValue />
|
||||
<SelectValue data-placeholder={t("common:placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{packMethods.map((method) => (
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
} from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -23,65 +18,61 @@ export function AntSwordTabContent({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="AntSword">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<FormField
|
||||
<TabsContent value="AntSword">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="antSwordPass"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("shellToolConfig.antSword.pass")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="antSwordPass"
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("shellToolConfig.antSword.pass")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:headerName")}</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -18,63 +18,61 @@ export function BehinderTabContent({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Behinder">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<FormField
|
||||
<TabsContent value="Behinder">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="behinderPass"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("shellToolConfig.behinder.pass")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="behinderPass"
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("shellToolConfig.behinder.pass")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:headerName")}</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Shuffle } from "lucide-react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -72,44 +72,43 @@ export function OptionalClassFormField({
|
||||
onCheckedChange={handleToggleRandomClass}
|
||||
/>
|
||||
</div>
|
||||
<FormProvider {...form}>
|
||||
{!useRandomClassName && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shellClassName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel htmlFor="shellClassName">
|
||||
{t("mainConfig.shellClassName")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
id="shellClassName"
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!useRandomClassName && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="injectorClassName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel htmlFor="injectClassName">
|
||||
{t("mainConfig.injectorClassName")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
id="injectClassName"
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</FormProvider>
|
||||
|
||||
{!useRandomClassName && (
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shellClassName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel htmlFor="shellClassName">
|
||||
{t("mainConfig.shellClassName")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
id="shellClassName"
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!useRandomClassName && (
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="injectorClassName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel htmlFor="injectClassName">
|
||||
{t("mainConfig.injectorClassName")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
id="injectClassName"
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ChevronDown, ChevronRight, InfoIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
@@ -9,12 +9,7 @@ import {
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
} from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
@@ -56,141 +51,129 @@ export function CommandTabContent({
|
||||
});
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Command">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="commandParamName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<div className="flex items-center gap-1">
|
||||
<FormFieldLabel>
|
||||
{t("common:paramName")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:paramName.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Collapsible open={isAdvancedOpen} onOpenChange={setIsAdvancedOpen}>
|
||||
<CollapsibleTrigger className="flex items-center gap-2 w-full py-2 text-sm font-medium hover:underline">
|
||||
{isAdvancedOpen ? (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
)}
|
||||
{t("common:advancedConfig")}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="space-y-2 pt-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="encryptor"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:encryptor")}</FormFieldLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
defaultValue="RAW"
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{data?.encryptors?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="implementationClass"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:implementationClass")}
|
||||
</FormFieldLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
defaultValue="RuntimeExec"
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{data?.implementationClasses?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<TabsContent value="Command">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="commandParamName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:paramName")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common:paramName.description")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<FormField
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Collapsible open={isAdvancedOpen} onOpenChange={setIsAdvancedOpen}>
|
||||
<CollapsibleTrigger className="flex items-center gap-2 w-full py-2 text-sm font-medium hover:underline">
|
||||
{isAdvancedOpen ? (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
)}
|
||||
{t("common:advancedConfig")}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="space-y-2 pt-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="commandTemplate"
|
||||
name="encryptor"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:commandTemplate")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:commandTemplate.placeholder")}
|
||||
/>
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{t("common:commandTemplate.description")}
|
||||
</p>
|
||||
</FormFieldItem>
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:encryptor")}</FieldLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
defaultValue="RAW"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
data-placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{data?.encryptors?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="implementationClass"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:implementationClass")}</FieldLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
defaultValue="RuntimeExec"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
data-placeholder={t("common:placeholders.select")}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{data?.implementationClasses?.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="commandTemplate"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:commandTemplate")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:commandTemplate.placeholder")}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
{t("common:commandTemplate.description")}
|
||||
</p>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
@@ -90,74 +84,71 @@ export default function CustomTabContent({
|
||||
}, [classNameEndpoint, form, shellClassBase64, t]);
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Custom">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shellClassBase64"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("shellClass")}</FormFieldLabel>
|
||||
<RadioGroup
|
||||
value={isFile ? "file" : "base64"}
|
||||
onValueChange={(value) => {
|
||||
field.onChange("");
|
||||
setIsFile(value === "file");
|
||||
}}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="base64" id="optionOne" />
|
||||
<Label htmlFor="optionOne">Base64</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="file" id="optionTwo" />
|
||||
<Label htmlFor="optionTwo">File</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
<FormControl className="mt-2">
|
||||
{isFile ? (
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const base64String =
|
||||
(event.target?.result as string)?.split(
|
||||
",",
|
||||
)[1] || "";
|
||||
field.onChange(base64String);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}}
|
||||
accept=".class"
|
||||
placeholder={t("common:placeholders.input")}
|
||||
type="file"
|
||||
/>
|
||||
) : (
|
||||
<Textarea
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
className="h-24"
|
||||
/>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<TabsContent value="Custom">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shellClassBase64"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("shellClass")}</FieldLabel>
|
||||
<RadioGroup
|
||||
value={isFile ? "file" : "base64"}
|
||||
onValueChange={(value) => {
|
||||
field.onChange("");
|
||||
setIsFile(value === "file");
|
||||
}}
|
||||
className="flex items-center"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<RadioGroupItem value="base64" id="optionOne" />
|
||||
<Label htmlFor="optionOne">Base64</Label>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<RadioGroupItem value="file" id="optionTwo" />
|
||||
<Label htmlFor="optionTwo">File</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
<div className="mt-2">
|
||||
{isFile ? (
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const base64String =
|
||||
(event.target?.result as string)?.split(",")[1] ||
|
||||
"";
|
||||
field.onChange(base64String);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}}
|
||||
accept=".class"
|
||||
placeholder={t("common:placeholders.input")}
|
||||
type="file"
|
||||
/>
|
||||
) : (
|
||||
<Textarea
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
className="h-24"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{fieldState.error && <FieldError errors={[fieldState.error]} />}
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -18,79 +18,76 @@ export function GodzillaTabContent({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="Godzilla">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="godzillaPass"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("shellToolConfig.godzilla.pass")}{" "}
|
||||
{t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="godzillaKey"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("shellToolConfig.godzilla.key")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<TabsContent value="Godzilla">
|
||||
<Card>
|
||||
<CardContent className="flex flex-col gap-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="godzillaPass"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("shellToolConfig.godzilla.pass")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="godzillaKey"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("shellToolConfig.godzilla.key")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:headerName")}</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -18,48 +18,46 @@ export function NeoRegTabContent({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value="NeoreGeorg">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<TabsContent value="NeoreGeorg">
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:headerName")}</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
} from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -24,42 +19,38 @@ export function ShellTypeFormField({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="shellType"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("mainConfig.shellMountType")}</FormFieldLabel>
|
||||
<Select
|
||||
onValueChange={(e) => {
|
||||
form.resetField("urlPattern");
|
||||
field.onChange(e);
|
||||
}}
|
||||
value={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("common:placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent key={shellTypes?.join(",")}>
|
||||
{shellTypes?.length ? (
|
||||
shellTypes.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value=" ">
|
||||
{t("tips.shellToolNotSelected")}
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shellType"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("mainConfig.shellMountType")}</FieldLabel>
|
||||
<Select
|
||||
onValueChange={(e) => {
|
||||
form.resetField("urlPattern");
|
||||
field.onChange(e);
|
||||
}}
|
||||
value={field.value}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue data-placeholder={t("common:placeholders.select")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent key={shellTypes?.join(",")}>
|
||||
{shellTypes?.length ? (
|
||||
shellTypes.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{v}
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</FormProvider>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value=" ">
|
||||
{t("tips.shellToolNotSelected")}
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { FormField, FormFieldItem, FormFieldLabel } from "@/components/ui/form";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
@@ -20,48 +20,46 @@ export function Suo5TabContent({
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<TabsContent value={tabValue}>
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem>
|
||||
<FormFieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FormFieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</FormProvider>
|
||||
<TabsContent value={tabValue}>
|
||||
<Card>
|
||||
<CardContent className="space-y-2 mt-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<UrlPatternFormField form={form} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerName"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>{t("common:headerName")}</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="headerValue"
|
||||
render={({ field }) => (
|
||||
<Field className="gap-1">
|
||||
<FieldLabel>
|
||||
{t("common:headerValue")} {t("common:optional")}
|
||||
</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("common:placeholders.input")}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<OptionalClassFormField form={form} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormField,
|
||||
FormFieldItem,
|
||||
FormFieldLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { shouldHidden } from "@/lib/utils";
|
||||
import { cn, shouldHidden } from "@/lib/utils";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
|
||||
export function UrlPatternFormField({
|
||||
@@ -16,20 +11,19 @@ export function UrlPatternFormField({
|
||||
const { t } = useTranslation("common");
|
||||
const shellType = form.watch("shellType");
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="urlPattern"
|
||||
render={({ field }) => (
|
||||
<FormFieldItem
|
||||
className={shouldHidden(shellType) ? "hidden" : "grid"}
|
||||
>
|
||||
<FormFieldLabel>{t("urlPattern")}</FormFieldLabel>
|
||||
<Input {...field} placeholder={t("placeholders.input")} />
|
||||
<FormMessage />
|
||||
</FormFieldItem>
|
||||
)}
|
||||
/>
|
||||
</FormProvider>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="urlPattern"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field
|
||||
className={cn("gap-1", shouldHidden(shellType) ? "hidden" : "grid")}
|
||||
data-invalid={fieldState.invalid}
|
||||
>
|
||||
<FieldLabel>{t("urlPattern")}</FieldLabel>
|
||||
<Input {...field} placeholder={t("placeholders.input")} />
|
||||
{fieldState.error && <FieldError errors={[fieldState.error]} />}
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user