message push config
This commit is contained in:
@@ -25,6 +25,7 @@ import { update } from "@/repository/settings";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
import { PbErrorData } from "@/domain/base";
|
||||
import { useState } from "react";
|
||||
import { EmailsSetting } from "@/domain/settings";
|
||||
|
||||
type EmailsEditProps = {
|
||||
className?: string;
|
||||
@@ -51,7 +52,7 @@ const EmailsEdit = ({ className, trigger }: EmailsEditProps) => {
|
||||
});
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
if (emails.content.emails.includes(data.email)) {
|
||||
if ((emails.content as EmailsSetting).emails.includes(data.email)) {
|
||||
form.setError("email", {
|
||||
message: "邮箱已存在",
|
||||
});
|
||||
@@ -59,7 +60,7 @@ const EmailsEdit = ({ className, trigger }: EmailsEditProps) => {
|
||||
}
|
||||
|
||||
// 保存到 config
|
||||
const newEmails = [...emails.content.emails, data.email];
|
||||
const newEmails = [...(emails.content as EmailsSetting).emails, data.email];
|
||||
|
||||
try {
|
||||
const resp = await update({
|
||||
|
||||
146
ui/src/components/notify/DingTalk.tsx
Normal file
146
ui/src/components/notify/DingTalk.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
import { Switch } from "../ui/switch";
|
||||
import { Label } from "../ui/label";
|
||||
import { useNotify } from "@/providers/notify";
|
||||
import { NotifyChannelDingTalk, NotifyChannels } from "@/domain/settings";
|
||||
import { useEffect, useState } from "react";
|
||||
import { update } from "@/repository/settings";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { useToast } from "../ui/use-toast";
|
||||
|
||||
type DingTalkSetting = {
|
||||
id: string;
|
||||
name: string;
|
||||
data: NotifyChannelDingTalk;
|
||||
};
|
||||
|
||||
const DingTalk = () => {
|
||||
const { config, setChannels } = useNotify();
|
||||
|
||||
const [dingtalk, setDingtalk] = useState<DingTalkSetting>({
|
||||
id: config.id ?? "",
|
||||
name: "notifyChannels",
|
||||
data: {
|
||||
accessToken: "",
|
||||
secret: "",
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const getDetailDingTalk = () => {
|
||||
const df: NotifyChannelDingTalk = {
|
||||
accessToken: "",
|
||||
secret: "",
|
||||
enabled: false,
|
||||
};
|
||||
if (!config.content) {
|
||||
return df;
|
||||
}
|
||||
const chanels = config.content as NotifyChannels;
|
||||
if (!chanels.dingtalk) {
|
||||
return df;
|
||||
}
|
||||
|
||||
return chanels.dingtalk as NotifyChannelDingTalk;
|
||||
};
|
||||
const data = getDetailDingTalk();
|
||||
setDingtalk({
|
||||
id: config.id ?? "",
|
||||
name: "dingtalk",
|
||||
data,
|
||||
});
|
||||
}, [config]);
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
try {
|
||||
const resp = await update({
|
||||
...config,
|
||||
name: "notifyChannels",
|
||||
content: {
|
||||
...config.content,
|
||||
dingtalk: {
|
||||
...dingtalk.data,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setChannels(resp);
|
||||
toast({
|
||||
title: "保存成功",
|
||||
description: "配置保存成功",
|
||||
});
|
||||
} catch (e) {
|
||||
const msg = getErrMessage(e);
|
||||
|
||||
toast({
|
||||
title: "保存失败",
|
||||
description: "配置保存失败:" + msg,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
placeholder="AccessToken"
|
||||
value={dingtalk.data.accessToken}
|
||||
onChange={(e) => {
|
||||
setDingtalk({
|
||||
...dingtalk,
|
||||
data: {
|
||||
...dingtalk.data,
|
||||
accessToken: e.target.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
placeholder="加签的签名"
|
||||
className="mt-2"
|
||||
value={dingtalk.data.secret}
|
||||
onChange={(e) => {
|
||||
setDingtalk({
|
||||
...dingtalk,
|
||||
data: {
|
||||
...dingtalk.data,
|
||||
secret: e.target.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-center space-x-1 mt-2">
|
||||
<Switch
|
||||
id="airplane-mode"
|
||||
checked={dingtalk.data.enabled}
|
||||
onCheckedChange={() => {
|
||||
setDingtalk({
|
||||
...dingtalk,
|
||||
data: {
|
||||
...dingtalk.data,
|
||||
enabled: !dingtalk.data.enabled,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="airplane-mode">是否启用</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end mt-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleSaveClick();
|
||||
}}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DingTalk;
|
||||
104
ui/src/components/notify/NotifyTemplate.tsx
Normal file
104
ui/src/components/notify/NotifyTemplate.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Input } from "../ui/input";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
defaultNotifyTemplate,
|
||||
NotifyTemplates,
|
||||
NotifyTemplate as NotifyTemplateT,
|
||||
} from "@/domain/settings";
|
||||
import { getSetting, update } from "@/repository/settings";
|
||||
import { useToast } from "../ui/use-toast";
|
||||
|
||||
const NotifyTemplate = () => {
|
||||
const [id, setId] = useState("");
|
||||
const [templates, setTemplates] = useState<NotifyTemplateT[]>([
|
||||
defaultNotifyTemplate,
|
||||
]);
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
const featchData = async () => {
|
||||
const resp = await getSetting("templates");
|
||||
|
||||
if (resp.content) {
|
||||
setTemplates((resp.content as NotifyTemplates).notifyTemplates);
|
||||
setId(resp.id ? resp.id : "");
|
||||
}
|
||||
};
|
||||
featchData();
|
||||
}, []);
|
||||
|
||||
const handleTitleChange = (val: string) => {
|
||||
const template = templates[0];
|
||||
|
||||
setTemplates([
|
||||
{
|
||||
...template,
|
||||
title: val,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const handleContentChange = (val: string) => {
|
||||
const template = templates[0];
|
||||
|
||||
setTemplates([
|
||||
{
|
||||
...template,
|
||||
content: val,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
const resp = await update({
|
||||
id: id,
|
||||
content: {
|
||||
notifyTemplates: templates,
|
||||
},
|
||||
name: "templates",
|
||||
});
|
||||
|
||||
if (resp.id) {
|
||||
setId(resp.id);
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "保存成功",
|
||||
description: "通知模板保存成功",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
value={templates[0].title}
|
||||
onChange={(e) => {
|
||||
handleTitleChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="text-muted-foreground text-sm mt-1">
|
||||
可选的变量, COUNT:即将过期张数
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
className="mt-2"
|
||||
value={templates[0].content}
|
||||
onChange={(e) => {
|
||||
handleContentChange(e.target.value);
|
||||
}}
|
||||
></Textarea>
|
||||
<div className="text-muted-foreground text-sm mt-1">
|
||||
可选的变量, COUNT:即将过期张数,DOMAINS:域名列表
|
||||
</div>
|
||||
<div className="flex justify-end mt-2">
|
||||
<Button onClick={handleSaveClick}>保存</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotifyTemplate;
|
||||
131
ui/src/components/notify/Telegram.tsx
Normal file
131
ui/src/components/notify/Telegram.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
import { Switch } from "../ui/switch";
|
||||
import { Label } from "../ui/label";
|
||||
import { useNotify } from "@/providers/notify";
|
||||
import { NotifyChannels, NotifyChannelTelegram } from "@/domain/settings";
|
||||
import { useEffect, useState } from "react";
|
||||
import { update } from "@/repository/settings";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { useToast } from "../ui/use-toast";
|
||||
|
||||
type TelegramSetting = {
|
||||
id: string;
|
||||
name: string;
|
||||
data: NotifyChannelTelegram;
|
||||
};
|
||||
|
||||
const Telegram = () => {
|
||||
const { config, setChannels } = useNotify();
|
||||
|
||||
const [telegram, setTelegram] = useState<TelegramSetting>({
|
||||
id: config.id ?? "",
|
||||
name: "notifyChannels",
|
||||
data: {
|
||||
apiToken: "",
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const getDetailTelegram = () => {
|
||||
const df: NotifyChannelTelegram = {
|
||||
apiToken: "",
|
||||
enabled: false,
|
||||
};
|
||||
if (!config.content) {
|
||||
return df;
|
||||
}
|
||||
const chanels = config.content as NotifyChannels;
|
||||
if (!chanels.telegram) {
|
||||
return df;
|
||||
}
|
||||
|
||||
return chanels.telegram as NotifyChannelTelegram;
|
||||
};
|
||||
const data = getDetailTelegram();
|
||||
setTelegram({
|
||||
id: config.id ?? "",
|
||||
name: "telegram",
|
||||
data,
|
||||
});
|
||||
}, [config]);
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
try {
|
||||
const resp = await update({
|
||||
...config,
|
||||
name: "notifyChannels",
|
||||
content: {
|
||||
...config.content,
|
||||
telegram: {
|
||||
...telegram.data,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setChannels(resp);
|
||||
toast({
|
||||
title: "保存成功",
|
||||
description: "配置保存成功",
|
||||
});
|
||||
} catch (e) {
|
||||
const msg = getErrMessage(e);
|
||||
|
||||
toast({
|
||||
title: "保存失败",
|
||||
description: "配置保存失败:" + msg,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
placeholder="ApiToken"
|
||||
value={telegram.data.apiToken}
|
||||
onChange={(e) => {
|
||||
setTelegram({
|
||||
...telegram,
|
||||
data: {
|
||||
...telegram.data,
|
||||
apiToken: e.target.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex items-center space-x-1 mt-2">
|
||||
<Switch
|
||||
id="airplane-mode"
|
||||
checked={telegram.data.enabled}
|
||||
onCheckedChange={() => {
|
||||
setTelegram({
|
||||
...telegram,
|
||||
data: {
|
||||
...telegram.data,
|
||||
enabled: !telegram.data.enabled,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="airplane-mode">是否启用</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end mt-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleSaveClick();
|
||||
}}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Telegram;
|
||||
131
ui/src/components/notify/Webhook.tsx
Normal file
131
ui/src/components/notify/Webhook.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
import { Switch } from "../ui/switch";
|
||||
import { Label } from "../ui/label";
|
||||
import { useNotify } from "@/providers/notify";
|
||||
import { NotifyChannels, NotifyChannelWebhook } from "@/domain/settings";
|
||||
import { useEffect, useState } from "react";
|
||||
import { update } from "@/repository/settings";
|
||||
import { getErrMessage } from "@/lib/error";
|
||||
import { useToast } from "../ui/use-toast";
|
||||
|
||||
type WebhookSetting = {
|
||||
id: string;
|
||||
name: string;
|
||||
data: NotifyChannelWebhook;
|
||||
};
|
||||
|
||||
const Webhook = () => {
|
||||
const { config, setChannels } = useNotify();
|
||||
|
||||
const [webhook, setWebhook] = useState<WebhookSetting>({
|
||||
id: config.id ?? "",
|
||||
name: "notifyChannels",
|
||||
data: {
|
||||
url: "",
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const getDetailWebhook = () => {
|
||||
const df: NotifyChannelWebhook = {
|
||||
url: "",
|
||||
enabled: false,
|
||||
};
|
||||
if (!config.content) {
|
||||
return df;
|
||||
}
|
||||
const chanels = config.content as NotifyChannels;
|
||||
if (!chanels.webhook) {
|
||||
return df;
|
||||
}
|
||||
|
||||
return chanels.webhook as NotifyChannelWebhook;
|
||||
};
|
||||
const data = getDetailWebhook();
|
||||
setWebhook({
|
||||
id: config.id ?? "",
|
||||
name: "webhook",
|
||||
data,
|
||||
});
|
||||
}, [config]);
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleSaveClick = async () => {
|
||||
try {
|
||||
const resp = await update({
|
||||
...config,
|
||||
name: "notifyChannels",
|
||||
content: {
|
||||
...config.content,
|
||||
webhook: {
|
||||
...webhook.data,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setChannels(resp);
|
||||
toast({
|
||||
title: "保存成功",
|
||||
description: "配置保存成功",
|
||||
});
|
||||
} catch (e) {
|
||||
const msg = getErrMessage(e);
|
||||
|
||||
toast({
|
||||
title: "保存失败",
|
||||
description: "配置保存失败:" + msg,
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
placeholder="Url"
|
||||
value={webhook.data.url}
|
||||
onChange={(e) => {
|
||||
setWebhook({
|
||||
...webhook,
|
||||
data: {
|
||||
...webhook.data,
|
||||
url: e.target.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex items-center space-x-1 mt-2">
|
||||
<Switch
|
||||
id="airplane-mode"
|
||||
checked={webhook.data.enabled}
|
||||
onCheckedChange={() => {
|
||||
setWebhook({
|
||||
...webhook,
|
||||
data: {
|
||||
...webhook.data,
|
||||
enabled: !webhook.data.enabled,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="airplane-mode">是否启用</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end mt-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleSaveClick();
|
||||
}}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Webhook;
|
||||
Reference in New Issue
Block a user