feat(ui): new SettingsNotification using antd

This commit is contained in:
Fu Diwei
2024-12-20 13:56:29 +08:00
parent cae33cfc4f
commit 7c1a2d5f91
60 changed files with 1105 additions and 2450 deletions

View File

@@ -1,88 +0,0 @@
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 Notification = () => {
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.notifier.email")}</AccordionTrigger>
<AccordionContent>
<Email />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-webhook" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.webhook")}</AccordionTrigger>
<AccordionContent>
<Webhook />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-dingtalk" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.dingtalk")}</AccordionTrigger>
<AccordionContent>
<DingTalk />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-lark" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.lark")}</AccordionTrigger>
<AccordionContent>
<Lark />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-telegram" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.telegram")}</AccordionTrigger>
<AccordionContent>
<Telegram />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-serverchan" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.serverchan")}</AccordionTrigger>
<AccordionContent>
<ServerChan />
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-bark" className="dark:border-stone-200">
<AccordionTrigger>{t("common.notifier.bark")}</AccordionTrigger>
<AccordionContent>
<Bark />
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</NotifyProvider>
</>
);
};
export default Notification;

View File

@@ -3,6 +3,7 @@ import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { produce } from "immer";
import { cn } from "@/components/ui/utils";
import { Button } from "@/components/ui/button";
@@ -11,10 +12,9 @@ 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 { getErrMsg } from "@/utils/error";
import { SSLProvider as SSLProviderType, SSLProviderSetting, SettingsModel } from "@/domain/settings";
import { SETTINGS_NAMES, SSLProvider as SSLProviderType, SSLProviderSetting, SettingsModel } from "@/domain/settings";
import { get, save } from "@/repository/settings";
import { produce } from "immer";
import { getErrMsg } from "@/utils/error";
type SSLProviderContext = {
setting: SettingsModel<SSLProviderSetting>;
@@ -28,6 +28,16 @@ export const useSSLProviderContext = () => {
return useContext(Context);
};
const getConfigStr = (content: SSLProviderSetting, kind: string, key: string) => {
if (!content.config) {
return "";
}
if (!content.config[kind]) {
return "";
}
return content.config[kind][key] ?? "";
};
const SSLProvider = () => {
const { t } = useTranslation();
@@ -42,7 +52,7 @@ const SSLProvider = () => {
useEffect(() => {
const fetchData = async () => {
const setting = await get<SSLProviderSetting>("ssl-provider");
const setting = await get<SSLProviderSetting>(SETTINGS_NAMES.SSL_PROVIDER);
if (setting) {
setConfig(setting);
@@ -95,7 +105,7 @@ const SSLProvider = () => {
return (
<>
<Context.Provider value={{ onSubmit, setConfig, setting: config }}>
<div className="w-full md:max-w-[35em]">
<div className="md:max-w-[40rem]">
<Label className="dark:text-stone-200">{t("common.text.ca")}</Label>
<RadioGroup
className="flex mt-3 dark:text-stone-200"
@@ -147,7 +157,7 @@ const SSLProviderForm = ({ kind }: { kind: string }) => {
case "zerossl":
return <SSLProviderZeroSSLForm />;
case "gts":
return <SSLProviderGtsForm />;
return <SSLProviderGoogleTrustServicesForm />;
default:
return <SSLProviderLetsEncryptForm />;
}
@@ -160,16 +170,6 @@ const SSLProviderForm = ({ kind }: { kind: string }) => {
);
};
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();
@@ -227,6 +227,7 @@ const SSLProviderLetsEncryptForm = () => {
</Form>
);
};
const SSLProviderZeroSSLForm = () => {
const { t } = useTranslation();
@@ -334,7 +335,7 @@ const SSLProviderZeroSSLForm = () => {
);
};
const SSLProviderGtsForm = () => {
const SSLProviderGoogleTrustServicesForm = () => {
const { t } = useTranslation();
const { setting, onSubmit } = useSSLProviderContext();

View File

@@ -5,8 +5,6 @@ import { Card, Space } from "antd";
import { PageHeader } from "@ant-design/pro-components";
import { KeyRound as KeyRoundIcon, Megaphone as MegaphoneIcon, ShieldCheck as ShieldCheckIcon, UserRound as UserRoundIcon } from "lucide-react";
import { Toaster } from "@/components/ui/toaster";
const Settings = () => {
const location = useLocation();
const navigate = useNavigate();
@@ -73,7 +71,6 @@ const Settings = () => {
navigate(`/settings/${key}`);
}}
>
<Toaster />
<Outlet />
</Card>
</>

View File

@@ -47,7 +47,7 @@ const SettingsAccount = () => {
navigate("/login");
}, 500);
} catch (err) {
notificationApi.error({ message: t("common.text.request_error"), description: <>{getErrMsg(err)}</> });
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
} finally {
setFormPending(false);
}
@@ -58,7 +58,7 @@ const SettingsAccount = () => {
{MessageContextHolder}
{NotificationContextHolder}
<div className="w-full md:max-w-[35em]">
<div className="md:max-w-[40rem]">
<Form form={form} disabled={formPending} initialValues={initialValues} layout="vertical" onFinish={handleFormFinish}>
<Form.Item name="username" label={t("settings.account.form.email.label")} rules={[formRule]}>
<Input placeholder={t("settings.account.form.email.placeholder")} onChange={handleInputChange} />

View File

@@ -0,0 +1,30 @@
import { useTranslation } from "react-i18next";
import { Card, Divider } from "antd";
import NotifyChannels from "@/components/notification/NotifyChannels";
import NotifyTemplate from "@/components/notification/NotifyTemplate";
import { useNotifyChannelStore } from "@/stores/notify";
const SettingsNotification = () => {
const { t } = useTranslation();
const { initialized } = useNotifyChannelStore();
return (
<div>
<Card className="shadow" title={t("settings.notification.template.card.title")}>
<div className="md:max-w-[40rem]">
<NotifyTemplate />
</div>
</Card>
<Divider />
<Card className="shadow" styles={{ body: initialized ? { padding: 0 } : {} }} title={t("settings.notification.channels.card.title")}>
<NotifyChannels classNames={{ form: "md:max-w-[40rem]" }} />
</Card>
</div>
);
};
export default SettingsNotification;

View File

@@ -60,7 +60,7 @@ const SettingsPassword = () => {
navigate("/login");
}, 500);
} catch (err) {
notificationApi.error({ message: t("common.text.request_error"), description: <>{getErrMsg(err)}</> });
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
} finally {
setFormPending(false);
}
@@ -71,7 +71,7 @@ const SettingsPassword = () => {
{MessageContextHolder}
{NotificationContextHolder}
<div className="w-full md:max-w-[35em]">
<div className="md:max-w-[40rem]">
<Form form={form} disabled={formPending} layout="vertical" onFinish={handleFormFinish}>
<Form.Item name="oldPassword" label={t("settings.password.form.old_password.label")} rules={[formRule]}>
<Input.Password placeholder={t("settings.password.form.old_password.placeholder")} onChange={handleInputChange} />