mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
refactor(ui): change serverVersion field localtion
This commit is contained in:
@@ -2,7 +2,7 @@ import { FileTextIcon } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { shouldHidden } from "@/lib/utils";
|
||||
import { notNeedUrlPattern } from "@/lib/utils";
|
||||
import {
|
||||
type AntSwordShellToolConfig,
|
||||
type BehinderShellToolConfig,
|
||||
@@ -45,7 +45,7 @@ export function BasicInfo({
|
||||
label={t("mainConfig.shellMountType")}
|
||||
text={generateResult?.shellConfig.shellType}
|
||||
/>
|
||||
{!shouldHidden(generateResult?.shellConfig?.shellType) && (
|
||||
{!notNeedUrlPattern(generateResult?.shellConfig?.shellType) && (
|
||||
<CopyableField
|
||||
label={t("mainConfig.urlPattern")}
|
||||
text={generateResult?.injectorConfig.urlPattern}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function AntSwordTabContent({
|
||||
form,
|
||||
@@ -21,10 +20,7 @@ export function AntSwordTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="antSwordPass"
|
||||
|
||||
@@ -7,7 +7,6 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function BehinderTabContent({
|
||||
form,
|
||||
@@ -21,10 +20,7 @@ export function BehinderTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="behinderPass"
|
||||
|
||||
@@ -28,7 +28,6 @@ import { env } from "@/config";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function CommandTabContent({
|
||||
form,
|
||||
@@ -54,10 +53,7 @@ export function CommandTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="commandParamName"
|
||||
|
||||
@@ -13,7 +13,6 @@ import { env } from "@/config";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export default function CustomTabContent({
|
||||
form,
|
||||
@@ -87,15 +86,12 @@ export default function CustomTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="shellClassBase64"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field className="gap-1">
|
||||
<Field className="gap-2">
|
||||
<FieldLabel>{t("shellClass")}</FieldLabel>
|
||||
<RadioGroup
|
||||
value={isFile ? "file" : "base64"}
|
||||
@@ -105,35 +101,38 @@ export default function CustomTabContent({
|
||||
}}
|
||||
className="flex items-center"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-1">
|
||||
<RadioGroupItem value="base64" id="optionOne" />
|
||||
<Label htmlFor="optionOne">Base64</Label>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-1">
|
||||
<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"
|
||||
/>
|
||||
<div className="grid w-full max-w-sm items-center gap-3">
|
||||
<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"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Textarea
|
||||
{...field}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function GodzillaTabContent({
|
||||
form,
|
||||
@@ -21,10 +20,7 @@ export function GodzillaTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function NeoRegTabContent({
|
||||
form,
|
||||
@@ -21,10 +20,7 @@ export function NeoRegTabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { Controller, type UseFormReturn, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Field, FieldLabel } from "@/components/ui/field";
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -8,6 +14,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { cn, notNeedUrlPattern } from "@/lib/utils";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
|
||||
export function ShellTypeFormField({
|
||||
@@ -18,39 +25,118 @@ export function ShellTypeFormField({
|
||||
shellTypes: Array<string>;
|
||||
}>) {
|
||||
const { t } = useTranslation(["memshell", "common"]);
|
||||
const shellType = useWatch({ control: form.control, name: "shellType" });
|
||||
const server = useWatch({ control: form.control, name: "server" });
|
||||
const needSelectServerVersion =
|
||||
(server === "TongWeb" && shellType.endsWith("Valve")) ||
|
||||
(server === "Jetty" &&
|
||||
(shellType === "Handler" || shellType === "JakartaHandler"));
|
||||
const needUrlPattern = !notNeedUrlPattern(shellType);
|
||||
const serverVersionOptions = getServerVersionOptions(server);
|
||||
return (
|
||||
<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}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<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>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value=" ">
|
||||
{t("tips.shellToolNotSelected")}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value=" ">
|
||||
{t("tips.shellToolNotSelected")}
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="urlPattern"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field
|
||||
className={cn("gap-1", needUrlPattern ? "grid" : "hidden")}
|
||||
data-invalid={fieldState.invalid}
|
||||
>
|
||||
<FieldLabel>{t("common:urlPattern")}</FieldLabel>
|
||||
<Input {...field} placeholder={t("common:placeholders.input")} />
|
||||
{fieldState.error && <FieldError errors={[fieldState.error]} />}
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="serverVersion"
|
||||
render={({ field, fieldState }) => (
|
||||
<Field
|
||||
className={cn("gap-1", needSelectServerVersion ? "grid" : "hidden")}
|
||||
orientation="vertical"
|
||||
data-invalid={fieldState.invalid}
|
||||
>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
function getServerVersionOptions(server: string) {
|
||||
let serverVersionOptions = [] as { name: string; value: string }[];
|
||||
if (server === "TongWeb") {
|
||||
serverVersionOptions = [
|
||||
{ name: "6", value: "6" },
|
||||
{ name: "7", value: "7" },
|
||||
{ name: "8", value: "8" },
|
||||
];
|
||||
} else if (server === "Jetty") {
|
||||
serverVersionOptions = [
|
||||
{ name: "6", value: "6" },
|
||||
{ name: "7+", value: "7+" },
|
||||
{ name: "12", value: "12" },
|
||||
];
|
||||
}
|
||||
return serverVersionOptions;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
import { OptionalClassFormField } from "./classname-field";
|
||||
import { ShellTypeFormField } from "./shelltype-field";
|
||||
import { UrlPatternFormField } from "./urlpattern-field";
|
||||
|
||||
export function Suo5TabContent({
|
||||
form,
|
||||
@@ -23,10 +22,7 @@ export function Suo5TabContent({
|
||||
<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>
|
||||
<ShellTypeFormField form={form} shellTypes={shellTypes} />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<Controller
|
||||
control={form.control}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { cn, shouldHidden } from "@/lib/utils";
|
||||
import type { MemShellFormSchema } from "@/types/schema";
|
||||
|
||||
export function UrlPatternFormField({
|
||||
form,
|
||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
||||
const { t } = useTranslation("common");
|
||||
const shellType = form.watch("shellType");
|
||||
return (
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -69,7 +69,7 @@ export function formatBytes(bytes: number) {
|
||||
return `${kbValue} ${sizes[1]}`;
|
||||
}
|
||||
|
||||
export function shouldHidden(shellType: string | undefined) {
|
||||
export function notNeedUrlPattern(shellType: string | undefined) {
|
||||
if (shellType === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user