diff --git a/ui/src/components/notify/Mail.tsx b/ui/src/components/notify/Mail.tsx
index 7b6195fb..ca75125c 100644
--- a/ui/src/components/notify/Mail.tsx
+++ b/ui/src/components/notify/Mail.tsx
@@ -43,13 +43,13 @@ const Mail = () => {
id: config.id ?? "",
name: "notifyChannels",
data: {
- senderAddress: "",
- receiverAddresses: "",
- smtpHostAddr: "",
- smtpHostPort: "25",
- username: "",
- password: "",
- enabled: false,
+ senderAddress: "",
+ receiverAddresses: "",
+ smtpHostAddr: "",
+ smtpHostPort: "25",
+ username: "",
+ password: "",
+ enabled: false,
},
});
@@ -79,13 +79,13 @@ const Mail = () => {
const getDetailMail = () => {
const df: NotifyChannelMail = {
- senderAddress: "",
- receiverAddresses: "",
- smtpHostAddr: "",
- smtpHostPort: "25",
- username: "",
- password: "",
- enabled: false,
+ senderAddress: "",
+ receiverAddresses: "",
+ smtpHostAddr: "",
+ smtpHostPort: "25",
+ username: "",
+ password: "",
+ enabled: false,
};
if (!config.content) {
return df;
@@ -99,7 +99,14 @@ const Mail = () => {
};
const checkChanged = (data: NotifyChannelMail) => {
- if (data.senderAddress !== originMail.data.senderAddress || data.receiverAddresses !== originMail.data.receiverAddresses || data.smtpHostAddr !== originMail.data.smtpHostAddr || data.smtpHostPort !== originMail.data.smtpHostPort || data.username !== originMail.data.username || data.password !== originMail.data.password) {
+ if (
+ data.senderAddress !== originMail.data.senderAddress ||
+ data.receiverAddresses !== originMail.data.receiverAddresses ||
+ data.smtpHostAddr !== originMail.data.smtpHostAddr ||
+ data.smtpHostPort !== originMail.data.smtpHostPort ||
+ data.username !== originMail.data.username ||
+ data.password !== originMail.data.password
+ ) {
setChanged(true);
} else {
setChanged(false);
@@ -236,55 +243,55 @@ const Mail = () => {
checkChanged(newData.data);
setmail(newData);
}}
- />
-
+ {
- const newData = {
+ const newData = {
...mail,
data: {
- ...mail.data,
- smtpHostPort: e.target.value,
+ ...mail.data,
+ smtpHostPort: e.target.value,
},
- };
- checkChanged(newData.data);
- setmail(newData);
+ };
+ checkChanged(newData.data);
+ setmail(newData);
}}
- />
-
+ {
- const newData = {
+ const newData = {
...mail,
data: {
- ...mail.data,
- username: e.target.value,
+ ...mail.data,
+ username: e.target.value,
},
- };
- checkChanged(newData.data);
- setmail(newData);
+ };
+ checkChanged(newData.data);
+ setmail(newData);
}}
- />
-
+ {
- const newData = {
+ const newData = {
...mail,
data: {
- ...mail.data,
- password: e.target.value,
+ ...mail.data,
+ password: e.target.value,
},
- };
- checkChanged(newData.data);
- setmail(newData);
+ };
+ checkChanged(newData.data);
+ setmail(newData);
}}
- />
+ />
diff --git a/ui/src/components/workflow/DeployForm.tsx b/ui/src/components/workflow/DeployForm.tsx
index 3e0b7883..d9fce0ef 100644
--- a/ui/src/components/workflow/DeployForm.tsx
+++ b/ui/src/components/workflow/DeployForm.tsx
@@ -4,15 +4,17 @@ import DeployToAliyunOSS from "./DeployToAliyunOss";
export type DeployFormProps = {
data: WorkflowNode;
+ defaultProivder?: string;
};
-const DeployForm = ({ data }: DeployFormProps) => {
- return getForm(data);
+const DeployForm = ({ data, defaultProivder }: DeployFormProps) => {
+ return getForm(data, defaultProivder);
};
export default memo(DeployForm);
-const getForm = (data: WorkflowNode) => {
- switch (data.config?.providerType) {
+const getForm = (data: WorkflowNode, defaultProivder?: string) => {
+ const provider = defaultProivder || data.config?.providerType;
+ switch (provider) {
case "aliyun-oss":
return
;
case "tencent":
diff --git a/ui/src/components/workflow/DeployPanelBody.tsx b/ui/src/components/workflow/DeployPanelBody.tsx
index 8fcdb589..cd5a9c24 100644
--- a/ui/src/components/workflow/DeployPanelBody.tsx
+++ b/ui/src/components/workflow/DeployPanelBody.tsx
@@ -22,7 +22,7 @@ const DeployPanelBody = ({ data }: DeployPanelBodyProps) => {
return (
<>
{/* 默认展示服务商列表 */}
-
}>
+
}>
选择服务商
{deployTargets
.reduce((acc: DeployTarget[][], provider, index) => {
diff --git a/ui/src/components/workflow/DeployToAliyunOss.tsx b/ui/src/components/workflow/DeployToAliyunOss.tsx
index 5ce80b7b..130a98b8 100644
--- a/ui/src/components/workflow/DeployToAliyunOss.tsx
+++ b/ui/src/components/workflow/DeployToAliyunOss.tsx
@@ -105,7 +105,7 @@ const DeployToAliyunOSS = ({ data }: DeployFormProps) => {
{item.name}
{item.output?.map((output) => (
-
+
{item.name}-{output.label}
diff --git a/ui/src/components/workflow/NotifyForm.tsx b/ui/src/components/workflow/NotifyForm.tsx
new file mode 100644
index 00000000..66620f87
--- /dev/null
+++ b/ui/src/components/workflow/NotifyForm.tsx
@@ -0,0 +1,181 @@
+import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useForm } from "react-hook-form";
+import { z } from "zod";
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
+import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger } from "../ui/select";
+import { Input } from "../ui/input";
+import { useWorkflowStore, WorkflowState } from "@/providers/workflow";
+import { useShallow } from "zustand/shallow";
+import { usePanel } from "./PanelProvider";
+import { useTranslation } from "react-i18next";
+import { Button } from "../ui/button";
+import { useNotifyContext } from "@/providers/notify";
+import { useEffect, useState } from "react";
+import { NotifyChannels, channels as supportedChannels } from "@/domain/settings";
+import { SelectValue } from "@radix-ui/react-select";
+import { Textarea } from "../ui/textarea";
+import { RefreshCw, Settings } from "lucide-react";
+
+type NotifyFormProps = {
+ data: WorkflowNode;
+};
+
+const selectState = (state: WorkflowState) => ({
+ updateNode: state.updateNode,
+});
+type ChannelName = {
+ name: string;
+ label: string;
+};
+const NotifyForm = ({ data }: NotifyFormProps) => {
+ const { updateNode } = useWorkflowStore(useShallow(selectState));
+ const { hidePanel } = usePanel();
+ const { t } = useTranslation();
+ const { config: notifyConfig, initChannels } = useNotifyContext();
+
+ const [chanels, setChanels] = useState([]);
+
+ useEffect(() => {
+ setChanels(getChannels());
+ }, [notifyConfig]);
+
+ const getChannels = () => {
+ const rs: ChannelName[] = [];
+ if (!notifyConfig.content) {
+ return rs;
+ }
+
+ const chanels = notifyConfig.content as NotifyChannels;
+ for (const channel of supportedChannels) {
+ if (chanels[channel.name] && chanels[channel.name].enabled) {
+ rs.push(channel);
+ }
+ }
+ return rs;
+ };
+
+ const formSchema = z.object({
+ channel: z.string(),
+ title: z.string().min(1),
+ content: z.string().min(1),
+ });
+
+ let config: WorkflowNodeConfig = {
+ channel: "",
+ title: "",
+ content: "",
+ };
+
+ if (data) config = data.config ?? config;
+
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ channel: config.channel as string,
+ title: config.title as string,
+ content: config.content as string,
+ },
+ });
+
+ const onSubmit = (config: z.infer) => {
+ updateNode({ ...data, config });
+ hidePanel();
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default NotifyForm;
+
diff --git a/ui/src/components/workflow/PanelBody.tsx b/ui/src/components/workflow/PanelBody.tsx
index bba04935..89134f65 100644
--- a/ui/src/components/workflow/PanelBody.tsx
+++ b/ui/src/components/workflow/PanelBody.tsx
@@ -2,6 +2,7 @@ import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
import StartForm from "./StartForm";
import DeployPanelBody from "./DeployPanelBody";
import ApplyForm from "./ApplyForm";
+import NotifyForm from "./NotifyForm";
type PanelBodyProps = {
data: WorkflowNode;
@@ -16,7 +17,7 @@ const PanelBody = ({ data }: PanelBodyProps) => {
case WorkflowNodeType.Deploy:
return ;
case WorkflowNodeType.Notify:
- return ;
+ return ;
case WorkflowNodeType.Branch:
return 分支节点
;
case WorkflowNodeType.Condition:
diff --git a/ui/src/components/workflow/WorkflowProvider.tsx b/ui/src/components/workflow/WorkflowProvider.tsx
index db4d29f0..8299a228 100644
--- a/ui/src/components/workflow/WorkflowProvider.tsx
+++ b/ui/src/components/workflow/WorkflowProvider.tsx
@@ -1,11 +1,14 @@
import { ConfigProvider } from "@/providers/config";
import React from "react";
import { PanelProvider } from "./PanelProvider";
+import { NotifyProvider } from "@/providers/notify";
const WorkflowProvider = ({ children }: { children: React.ReactNode }) => {
return (
- {children}
+
+ {children}
+
);
};
diff --git a/ui/src/domain/settings.ts b/ui/src/domain/settings.ts
index 7962ef7a..c339aa8f 100644
--- a/ui/src/domain/settings.ts
+++ b/ui/src/domain/settings.ts
@@ -18,13 +18,7 @@ export type NotifyTemplate = {
};
export type NotifyChannels = {
- dingtalk?: NotifyChannel;
- lark?: NotifyChannel;
- telegram?: NotifyChannel;
- webhook?: NotifyChannel;
- serverchan?: NotifyChannel;
- mail?: NotifyChannelMail;
- bark?: NotifyChannelBark;
+ [key: string]: NotifyChannel;
};
export type NotifyChannel =
@@ -36,6 +30,37 @@ export type NotifyChannel =
| NotifyChannelMail
| NotifyChannelBark;
+export const channels = [
+ {
+ name: "dingtalk",
+ label: "common.provider.dingtalk",
+ },
+ {
+ name: "lark",
+ label: "common.provider.lark",
+ },
+ {
+ name: "telegram",
+ label: "common.provider.telegram",
+ },
+ {
+ name: "webhook",
+ label: "common.provider.webhook",
+ },
+ {
+ name: "serverchan",
+ label: "common.provider.serverchan",
+ },
+ {
+ name: "mail",
+ label: "common.provider.mail",
+ },
+ {
+ name: "bark",
+ label: "common.provider.bark",
+ },
+];
+
export type NotifyChannelDingTalk = {
accessToken: string;
secret: string;
@@ -94,3 +119,4 @@ export type SSLProviderSetting = {
};
};
};
+
diff --git a/ui/src/providers/notify/index.tsx b/ui/src/providers/notify/index.tsx
index 47f55676..29b25421 100644
--- a/ui/src/providers/notify/index.tsx
+++ b/ui/src/providers/notify/index.tsx
@@ -8,6 +8,7 @@ export type NotifyContext = {
config: Setting;
setChannel: (data: { channel: string; data: NotifyChannel }) => void;
setChannels: (data: Setting) => void;
+ initChannels: () => void;
};
const Context = createContext({} as NotifyContext);
@@ -22,13 +23,18 @@ export const NotifyProvider = ({ children }: NotifyProviderProps) => {
const [notify, dispatchNotify] = useReducer(notifyReducer, {});
useEffect(() => {
- const featchData = async () => {
- const chanels = await getSetting("notifyChannels");
- dispatchNotify({
- type: "SET_CHANNELS",
- payload: chanels,
- });
- };
+ featchData();
+ }, []);
+
+ const featchData = async () => {
+ const chanels = await getSetting("notifyChannels");
+ dispatchNotify({
+ type: "SET_CHANNELS",
+ payload: chanels,
+ });
+ };
+
+ const initChannels = useCallback(() => {
featchData();
}, []);
@@ -52,6 +58,7 @@ export const NotifyProvider = ({ children }: NotifyProviderProps) => {
config: notify,
setChannel,
setChannels,
+ initChannels,
}}
>
{children}