feat(ui): new Layout UI using antd
This commit is contained in:
101
ui/src/pages/settings/Account.tsx
Normal file
101
ui/src/pages/settings/Account.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z.string().email("settings.account.email.errmsg.invalid"),
|
||||
});
|
||||
|
||||
const Account = () => {
|
||||
const { toast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [changed, setChanged] = useState(false);
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
email: getPocketBase().authStore.model?.email,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||
try {
|
||||
await getPocketBase().admins.update(getPocketBase().authStore.model?.id, {
|
||||
email: values.email,
|
||||
});
|
||||
|
||||
getPocketBase().authStore.clear();
|
||||
toast({
|
||||
title: t("settings.account.email.changed.message"),
|
||||
description: t("settings.account.relogin.message"),
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate("/login");
|
||||
}, 500);
|
||||
} catch (e) {
|
||||
const message = getErrMessage(e);
|
||||
toast({
|
||||
title: t("settings.account.email.failed.message"),
|
||||
description: message,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full md:max-w-[35em]">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("settings.account.email.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t("settings.account.email.placeholder")}
|
||||
{...field}
|
||||
type="email"
|
||||
onChange={(e) => {
|
||||
setChanged(true);
|
||||
form.setValue("email", e.target.value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
{changed ? (
|
||||
<Button type="submit">{t("common.update")}</Button>
|
||||
) : (
|
||||
<Button type="submit" disabled variant={"secondary"}>
|
||||
{t("common.update")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Account;
|
||||
88
ui/src/pages/settings/Notify.tsx
Normal file
88
ui/src/pages/settings/Notify.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||
import DingTalk from "@/components/notify/DingTalk";
|
||||
import Lark from "@/components/notify/Lark";
|
||||
import NotifyTemplate from "@/components/notify/NotifyTemplate";
|
||||
import Telegram from "@/components/notify/Telegram";
|
||||
import Webhook from "@/components/notify/Webhook";
|
||||
import ServerChan from "@/components/notify/ServerChan";
|
||||
import Email from "@/components/notify/Email";
|
||||
import Bark from "@/components/notify/Bark";
|
||||
import { NotifyProvider } from "@/providers/notify";
|
||||
|
||||
const Notify = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<NotifyProvider>
|
||||
<div className="border rounded-sm p-5 shadow-lg">
|
||||
<Accordion type={"multiple"} className="dark:text-stone-200">
|
||||
<AccordionItem value="item-1" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("settings.notification.template.label")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<NotifyTemplate />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
|
||||
<div className="border rounded-md p-5 mt-7 shadow-lg">
|
||||
<Accordion type={"single"} collapsible={true} className="dark:text-stone-200">
|
||||
<AccordionItem value="item-email" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.email")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Email />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-webhook" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.webhook")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Webhook />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-dingtalk" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.dingtalk")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<DingTalk />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-lark" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.lark")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Lark />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-telegram" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.telegram")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Telegram />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-serverchan" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.serverchan")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<ServerChan />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="item-bark" className="dark:border-stone-200">
|
||||
<AccordionTrigger>{t("common.provider.bark")}</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Bark />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
</NotifyProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notify;
|
||||
136
ui/src/pages/settings/Password.tsx
Normal file
136
ui/src/pages/settings/Password.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
oldPassword: z.string().min(10, {
|
||||
message: "settings.password.password.errmsg.length",
|
||||
}),
|
||||
newPassword: z.string().min(10, {
|
||||
message: "settings.password.password.errmsg.length",
|
||||
}),
|
||||
confirmPassword: z.string().min(10, {
|
||||
message: "settings.password.password.errmsg.length",
|
||||
}),
|
||||
})
|
||||
.refine((data) => data.newPassword === data.confirmPassword, {
|
||||
message: "settings.password.password.errmsg.not_matched",
|
||||
path: ["confirmPassword"],
|
||||
});
|
||||
|
||||
const Password = () => {
|
||||
const { toast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
oldPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||
try {
|
||||
await getPocketBase().admins.authWithPassword(getPocketBase().authStore.model?.email, values.oldPassword);
|
||||
} catch (e) {
|
||||
const message = getErrMessage(e);
|
||||
form.setError("oldPassword", { message });
|
||||
}
|
||||
|
||||
try {
|
||||
await getPocketBase().admins.update(getPocketBase().authStore.model?.id, {
|
||||
password: values.newPassword,
|
||||
passwordConfirm: values.confirmPassword,
|
||||
});
|
||||
|
||||
getPocketBase().authStore.clear();
|
||||
toast({
|
||||
title: t("settings.password.changed.message"),
|
||||
description: t("settings.account.relogin.message"),
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate("/login");
|
||||
}, 500);
|
||||
} catch (e) {
|
||||
const message = getErrMessage(e);
|
||||
toast({
|
||||
title: t("settings.password.failed.message"),
|
||||
description: message,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full md:max-w-[35em]">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="oldPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("settings.password.current_password.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.password.current_password.placeholder")} {...field} type="password" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="newPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("settings.password.new_password.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.password.new_password.placeholder")} {...field} type="password" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="confirmPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("settings.password.confirm_password.label")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.password.confirm_password.placeholder")} {...field} type="password" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.update")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Password;
|
||||
445
ui/src/pages/settings/SSLProvider.tsx
Normal file
445
ui/src/pages/settings/SSLProvider.tsx
Normal file
@@ -0,0 +1,445 @@
|
||||
import { useContext, useEffect, useState, createContext } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { cn } from "@/components/ui/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { SSLProvider as SSLProviderType, SSLProviderSetting, Setting } from "@/domain/settings";
|
||||
import { getSetting, update } from "@/repository/settings";
|
||||
import { produce } from "immer";
|
||||
|
||||
type SSLProviderContext = {
|
||||
setting: Setting<SSLProviderSetting>;
|
||||
onSubmit: (data: Setting<SSLProviderSetting>) => void;
|
||||
setConfig: (config: Setting<SSLProviderSetting>) => void;
|
||||
};
|
||||
|
||||
const Context = createContext({} as SSLProviderContext);
|
||||
|
||||
export const useSSLProviderContext = () => {
|
||||
return useContext(Context);
|
||||
};
|
||||
|
||||
const SSLProvider = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [config, setConfig] = useState<Setting<SSLProviderSetting>>({
|
||||
id: "",
|
||||
content: {
|
||||
provider: "letsencrypt",
|
||||
config: {},
|
||||
},
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const setting = await getSetting<SSLProviderSetting>("ssl-provider");
|
||||
|
||||
if (setting) {
|
||||
setConfig(setting);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const setProvider = (val: SSLProviderType) => {
|
||||
const newData = produce(config, (draft) => {
|
||||
if (draft.content) {
|
||||
draft.content.provider = val;
|
||||
} else {
|
||||
draft.content = {
|
||||
provider: val,
|
||||
config: {},
|
||||
};
|
||||
}
|
||||
});
|
||||
setConfig(newData);
|
||||
};
|
||||
|
||||
const getOptionCls = (val: string) => {
|
||||
if (config.content?.provider === val) {
|
||||
return "border-primary dark:border-primary";
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
const onSubmit = async (data: Setting<SSLProviderSetting>) => {
|
||||
try {
|
||||
console.log(data);
|
||||
const resp = await update({ ...data });
|
||||
setConfig(resp);
|
||||
toast({
|
||||
title: t("common.update.succeeded.message"),
|
||||
description: t("common.update.succeeded.message"),
|
||||
});
|
||||
} catch (e) {
|
||||
const message = getErrMessage(e);
|
||||
toast({
|
||||
title: t("common.update.failed.message"),
|
||||
description: message,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Context.Provider value={{ onSubmit, setConfig, setting: config }}>
|
||||
<div className="w-full md:max-w-[35em]">
|
||||
<Label className="dark:text-stone-200">{t("common.text.ca")}</Label>
|
||||
<RadioGroup
|
||||
className="flex mt-3 dark:text-stone-200"
|
||||
onValueChange={(val) => {
|
||||
setProvider(val as SSLProviderType);
|
||||
}}
|
||||
value={config.content?.provider}
|
||||
>
|
||||
<div className="flex items-center space-x-2 ">
|
||||
<RadioGroupItem value="letsencrypt" id="letsencrypt" />
|
||||
<Label htmlFor="letsencrypt">
|
||||
<div className={cn("flex items-center space-x-2 border p-2 rounded cursor-pointer dark:border-stone-700", getOptionCls("letsencrypt"))}>
|
||||
<img src={"/imgs/providers/letsencrypt.svg"} className="h-6" />
|
||||
<div>{"Let's Encrypt"}</div>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 ">
|
||||
<RadioGroupItem value="zerossl" id="zerossl" />
|
||||
<Label htmlFor="zerossl">
|
||||
<div className={cn("flex items-center space-x-2 border p-2 rounded cursor-pointer dark:border-stone-700", getOptionCls("zerossl"))}>
|
||||
<img src={"/imgs/providers/zerossl.svg"} className="h-6" />
|
||||
<div>{"ZeroSSL"}</div>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="gts" id="gts" />
|
||||
<Label htmlFor="gts">
|
||||
<div className={cn("flex items-center space-x-2 border p-2 rounded cursor-pointer dark:border-stone-700", getOptionCls("gts"))}>
|
||||
<img src={"/imgs/providers/google.svg"} className="h-6" />
|
||||
<div>{"Google Trust Services"}</div>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
|
||||
<SSLProviderForm kind={config.content?.provider ?? ""} />
|
||||
</div>
|
||||
</Context.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const SSLProviderForm = ({ kind }: { kind: string }) => {
|
||||
const getForm = () => {
|
||||
switch (kind) {
|
||||
case "zerossl":
|
||||
return <SSLProviderZeroSSLForm />;
|
||||
case "gts":
|
||||
return <SSLProviderGtsForm />;
|
||||
default:
|
||||
return <SSLProviderLetsEncryptForm />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-5">{getForm()}</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getConfigStr = (content: SSLProviderSetting, kind: string, key: string) => {
|
||||
if (!content.config) {
|
||||
return "";
|
||||
}
|
||||
if (!content.config[kind]) {
|
||||
return "";
|
||||
}
|
||||
return content.config[kind][key] ?? "";
|
||||
};
|
||||
|
||||
const SSLProviderLetsEncryptForm = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { setting, onSubmit } = useSSLProviderContext();
|
||||
|
||||
const formSchema = z.object({
|
||||
kind: z.literal("letsencrypt"),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
kind: "letsencrypt",
|
||||
},
|
||||
});
|
||||
|
||||
const onLocalSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
const newData = produce(setting, (draft) => {
|
||||
if (!draft.content) {
|
||||
draft.content = {
|
||||
provider: data.kind,
|
||||
config: {
|
||||
letsencrypt: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
onSubmit(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onLocalSubmit)} className="space-y-8 dark:text-stone-200">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="kind"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden>
|
||||
<FormLabel>kind</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.update")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
const SSLProviderZeroSSLForm = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { setting, onSubmit } = useSSLProviderContext();
|
||||
|
||||
const formSchema = z.object({
|
||||
kind: z.literal("zerossl"),
|
||||
eabKid: z.string().min(1, { message: t("settings.ca.eab_kid_hmac_key.errmsg.empty") }),
|
||||
eabHmacKey: z.string().min(1, { message: t("settings.ca.eab_kid_hmac_key.errmsg.empty") }),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
kind: "zerossl",
|
||||
eabKid: "",
|
||||
eabHmacKey: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (setting.content) {
|
||||
const content = setting.content;
|
||||
|
||||
form.reset({
|
||||
eabKid: getConfigStr(content, "zerossl", "eabKid"),
|
||||
eabHmacKey: getConfigStr(content, "zerossl", "eabHmacKey"),
|
||||
});
|
||||
}
|
||||
}, [setting]);
|
||||
|
||||
const onLocalSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
const newData = produce(setting, (draft) => {
|
||||
if (!draft.content) {
|
||||
draft.content = {
|
||||
provider: "zerossl",
|
||||
config: {
|
||||
zerossl: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
draft.content.config.zerossl = {
|
||||
eabKid: data.eabKid,
|
||||
eabHmacKey: data.eabHmacKey,
|
||||
};
|
||||
});
|
||||
onSubmit(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onLocalSubmit)} className="space-y-8 dark:text-stone-200">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="kind"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden>
|
||||
<FormLabel>kind</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="eabKid"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>EAB_KID</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.ca.eab_kid.errmsg.empty")} {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="eabHmacKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>EAB_HMAC_KEY</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.ca.eab_hmac_key.errmsg.empty")} {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.update")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const SSLProviderGtsForm = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { setting, onSubmit } = useSSLProviderContext();
|
||||
|
||||
const formSchema = z.object({
|
||||
kind: z.literal("gts"),
|
||||
eabKid: z.string().min(1, { message: t("settings.ca.eab_kid_hmac_key.errmsg.empty") }),
|
||||
eabHmacKey: z.string().min(1, { message: t("settings.ca.eab_kid_hmac_key.errmsg.empty") }),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
kind: "gts",
|
||||
eabKid: "",
|
||||
eabHmacKey: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (setting.content) {
|
||||
const content = setting.content;
|
||||
|
||||
form.reset({
|
||||
eabKid: getConfigStr(content, "gts", "eabKid"),
|
||||
eabHmacKey: getConfigStr(content, "gts", "eabHmacKey"),
|
||||
});
|
||||
}
|
||||
}, [setting]);
|
||||
|
||||
const onLocalSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
const newData = produce(setting, (draft) => {
|
||||
if (!draft.content) {
|
||||
draft.content = {
|
||||
provider: "gts",
|
||||
config: {
|
||||
zerossl: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
draft.content.config.gts = {
|
||||
eabKid: data.eabKid,
|
||||
eabHmacKey: data.eabHmacKey,
|
||||
};
|
||||
});
|
||||
onSubmit(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onLocalSubmit)} className="space-y-8 dark:text-stone-200">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="kind"
|
||||
render={({ field }) => (
|
||||
<FormItem hidden>
|
||||
<FormLabel>kind</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="eabKid"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>EAB_KID</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.ca.eab_kid.errmsg.empty")} {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="eabHmacKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>EAB_HMAC_KEY</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder={t("settings.ca.eab_hmac_key.errmsg.empty")} {...field} type="text" />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">{t("common.update")}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default SSLProvider;
|
||||
Reference in New Issue
Block a user