mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-07 13:09:51 +00:00
feat: add certtest workflow template
This commit is contained in:
parent
6731c465e7
commit
f885b49daf
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 9.0 KiB |
BIN
ui/public/imgs/workflow/tpl-certtest.png
Normal file
BIN
ui/public/imgs/workflow/tpl-certtest.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 20 KiB |
@ -55,7 +55,6 @@ const workflowNodeTypeDefaultNames: Map<WorkflowNodeType, string> = new Map([
|
||||
[WorkflowNodeType.ExecuteResultBranch, i18n.t("workflow_node.execute_result_branch.default_name")],
|
||||
[WorkflowNodeType.ExecuteSuccess, i18n.t("workflow_node.execute_success.default_name")],
|
||||
[WorkflowNodeType.ExecuteFailure, i18n.t("workflow_node.execute_failure.default_name")],
|
||||
[WorkflowNodeType.Custom, i18n.t("workflow_node.custom.default_name")],
|
||||
]);
|
||||
|
||||
const workflowNodeTypeDefaultInputs: Map<WorkflowNodeType, WorkflowNodeIO[]> = new Map([
|
||||
@ -240,25 +239,153 @@ const isBranchLike = (node: WorkflowNode) => {
|
||||
};
|
||||
|
||||
type InitWorkflowOptions = {
|
||||
template?: "standard";
|
||||
template?: "standard" | "certtest";
|
||||
};
|
||||
|
||||
export const initWorkflow = (options: InitWorkflowOptions = {}): WorkflowModel => {
|
||||
const root = newNode(WorkflowNodeType.Start, {}) as WorkflowNode;
|
||||
root.config = { trigger: WORKFLOW_TRIGGERS.MANUAL };
|
||||
|
||||
if (options.template === "standard") {
|
||||
let current = root;
|
||||
current.next = newNode(WorkflowNodeType.Apply, {});
|
||||
switch (options.template) {
|
||||
case "standard":
|
||||
{
|
||||
let current = root;
|
||||
|
||||
current = current.next;
|
||||
current.next = newNode(WorkflowNodeType.Deploy, {});
|
||||
const applyNode = newNode(WorkflowNodeType.Apply);
|
||||
current.next = applyNode;
|
||||
|
||||
current = current.next;
|
||||
current.next = newNode(WorkflowNodeType.ExecuteResultBranch, {});
|
||||
current = current.next;
|
||||
current.next = newNode(WorkflowNodeType.ExecuteResultBranch);
|
||||
|
||||
current = current.next!.branches![1];
|
||||
current.next = newNode(WorkflowNodeType.Notify, {});
|
||||
current = current.next!.branches![1];
|
||||
current.next = newNode(WorkflowNodeType.Notify, {
|
||||
nodeConfig: {
|
||||
subject: "[Certimate] Workflow Failure Alert!",
|
||||
message: "Your workflow run for the certificate application has failed. Please check the details.",
|
||||
} as WorkflowNodeConfigForNotify,
|
||||
});
|
||||
|
||||
current = applyNode.next!.branches![0];
|
||||
current.next = newNode(WorkflowNodeType.Deploy, {
|
||||
nodeConfig: {
|
||||
certificate: `${applyNode.id}#certificate`,
|
||||
skipOnLastSucceeded: true,
|
||||
} as WorkflowNodeConfigForDeploy,
|
||||
});
|
||||
|
||||
current = current.next;
|
||||
current.next = newNode(WorkflowNodeType.ExecuteResultBranch);
|
||||
|
||||
current = current.next!.branches![1];
|
||||
current.next = newNode(WorkflowNodeType.Notify, {
|
||||
nodeConfig: {
|
||||
subject: "[Certimate] Workflow Failure Alert!",
|
||||
message: "Your workflow run for the certificate deployment has failed. Please check the details.",
|
||||
} as WorkflowNodeConfigForNotify,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "certtest":
|
||||
{
|
||||
let current = root;
|
||||
|
||||
const monitorNode = newNode(WorkflowNodeType.Monitor);
|
||||
current.next = monitorNode;
|
||||
|
||||
current = current.next;
|
||||
current.next = newNode(WorkflowNodeType.ExecuteResultBranch);
|
||||
|
||||
current = current.next!.branches![1];
|
||||
current.next = newNode(WorkflowNodeType.Notify, {
|
||||
nodeConfig: {
|
||||
subject: "[Certimate] Workflow Failure Alert!",
|
||||
message: "Your workflow run for the certificate monitoring has failed. Please check the details.",
|
||||
} as WorkflowNodeConfigForNotify,
|
||||
});
|
||||
|
||||
current = monitorNode.next!.branches![0];
|
||||
const branchNode = newNode(WorkflowNodeType.Branch);
|
||||
current.next = branchNode;
|
||||
|
||||
current = branchNode.branches![0];
|
||||
current.name = i18n.t("workflow_node.condition.default_name.template_certtest_on_expire_soon");
|
||||
current.config = {
|
||||
expression: {
|
||||
left: {
|
||||
left: {
|
||||
selector: {
|
||||
id: monitorNode.id,
|
||||
name: "certificate.validity",
|
||||
type: "boolean",
|
||||
},
|
||||
type: "var",
|
||||
},
|
||||
operator: "eq",
|
||||
right: {
|
||||
type: "const",
|
||||
value: "true",
|
||||
valueType: "boolean",
|
||||
},
|
||||
type: "comparison",
|
||||
},
|
||||
operator: "and",
|
||||
right: {
|
||||
left: {
|
||||
selector: {
|
||||
id: monitorNode.id,
|
||||
name: "certificate.daysLeft",
|
||||
type: "number",
|
||||
},
|
||||
type: "var",
|
||||
},
|
||||
operator: "lte",
|
||||
right: {
|
||||
type: "const",
|
||||
value: "30",
|
||||
valueType: "number",
|
||||
},
|
||||
type: "comparison",
|
||||
},
|
||||
type: "logical",
|
||||
},
|
||||
} as WorkflowNodeConfigForCondition;
|
||||
current.next = newNode(WorkflowNodeType.Notify, {
|
||||
nodeConfig: {
|
||||
subject: "[Certimate] Certificate Expiry Alert!",
|
||||
message: "The certificate will expire soon. Please pay attention to your website.",
|
||||
} as WorkflowNodeConfigForNotify,
|
||||
});
|
||||
|
||||
current = branchNode.branches![1];
|
||||
current.name = i18n.t("workflow_node.condition.default_name.template_certtest_on_expired");
|
||||
current.config = {
|
||||
expression: {
|
||||
left: {
|
||||
selector: {
|
||||
id: monitorNode.id,
|
||||
name: "certificate.validity",
|
||||
type: "boolean",
|
||||
},
|
||||
type: "var",
|
||||
},
|
||||
operator: "eq",
|
||||
right: {
|
||||
type: "const",
|
||||
value: "false",
|
||||
valueType: "boolean",
|
||||
},
|
||||
type: "comparison",
|
||||
},
|
||||
} as WorkflowNodeConfigForCondition;
|
||||
current.next = newNode(WorkflowNodeType.Notify, {
|
||||
nodeConfig: {
|
||||
subject: "[Certimate] Certificate Expiry Alert!",
|
||||
message: "The certificate has already expired. Please pay attention to your website.",
|
||||
} as WorkflowNodeConfigForNotify,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -275,6 +402,8 @@ export const initWorkflow = (options: InitWorkflowOptions = {}): WorkflowModel =
|
||||
};
|
||||
|
||||
type NewNodeOptions = {
|
||||
nodeName?: string;
|
||||
nodeConfig?: Record<string, unknown>;
|
||||
branchIndex?: number;
|
||||
};
|
||||
|
||||
@ -284,8 +413,9 @@ export const newNode = (nodeType: WorkflowNodeType, options: NewNodeOptions = {}
|
||||
|
||||
const node: WorkflowNode = {
|
||||
id: nanoid(),
|
||||
name: nodeName,
|
||||
name: options.nodeName ?? nodeName,
|
||||
type: nodeType,
|
||||
config: options.nodeConfig,
|
||||
};
|
||||
|
||||
switch (nodeType) {
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -30,6 +30,8 @@
|
||||
"workflow.new.templates.title": "Choose a Workflow Template",
|
||||
"workflow.new.templates.template.standard.title": "Standard template",
|
||||
"workflow.new.templates.template.standard.description": "A standard operating procedure that includes application, deployment, and notification steps.",
|
||||
"workflow.new.templates.template.certtest.title": "Monitoring template",
|
||||
"workflow.new.templates.template.certtest.description": "A monitoring operating procedure that includes monitoring, and notification steps.",
|
||||
"workflow.new.templates.template.blank.title": "Blank template",
|
||||
"workflow.new.templates.template.blank.description": "Customize all the contents of the workflow from the beginning.",
|
||||
"workflow.new.modal.title": "Create workflow",
|
||||
|
@ -876,6 +876,8 @@
|
||||
|
||||
"workflow_node.condition.label": "Branch",
|
||||
"workflow_node.condition.default_name": "Branch",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expire_soon": "If the certificate will expire soon ...",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expired": "If the certificate has expired ...",
|
||||
"workflow_node.condition.form.expression.label": "Conditions to enter the branch",
|
||||
"workflow_node.condition.form.expression.logical_operator.errmsg": "Please select logical operator of conditions",
|
||||
"workflow_node.condition.form.expression.logical_operator.option.and.label": "Meeting all of the conditions (AND)",
|
||||
|
@ -29,7 +29,9 @@
|
||||
"workflow.new.subtitle": "使用工作流来申请证书、部署上传和发送通知",
|
||||
"workflow.new.templates.title": "选择工作流模板",
|
||||
"workflow.new.templates.template.standard.title": "标准模板",
|
||||
"workflow.new.templates.template.standard.description": "一个包含申请 + 部署 + 通知步骤的标准工作流程。",
|
||||
"workflow.new.templates.template.standard.description": "一个包含证书申请 + 证书部署 + 消息通知步骤的工作流程。",
|
||||
"workflow.new.templates.template.certtest.title": "监控模板",
|
||||
"workflow.new.templates.template.certtest.description": "一个包含证书监控 + 消息通知步骤的工作流程。",
|
||||
"workflow.new.templates.template.blank.title": "空白模板",
|
||||
"workflow.new.templates.template.blank.description": "从零开始自定义工作流的任务内容。",
|
||||
"workflow.new.modal.title": "新建工作流",
|
||||
|
@ -875,6 +875,8 @@
|
||||
|
||||
"workflow_node.condition.label": "分支",
|
||||
"workflow_node.condition.default_name": "分支",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expire_soon": "若网站证书即将到期 ...",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expired": "若网站证书已到期 ...",
|
||||
"workflow_node.condition.form.expression.label": "分支进入条件",
|
||||
"workflow_node.condition.form.expression.logical_operator.errmsg": "请选择条件组合方式",
|
||||
"workflow_node.condition.form.expression.logical_operator.option.and.label": "满足以下所有条件 (AND)",
|
||||
@ -900,9 +902,9 @@
|
||||
"workflow_node.execute_result_branch.label": "执行结果分支",
|
||||
"workflow_node.execute_result_branch.default_name": "执行结果分支",
|
||||
|
||||
"workflow_node.execute_success.label": "若前序节点执行成功…",
|
||||
"workflow_node.execute_success.default_name": "若前序节点执行成功…",
|
||||
"workflow_node.execute_success.label": "若上一节点执行成功…",
|
||||
"workflow_node.execute_success.default_name": "若上一节点执行成功…",
|
||||
|
||||
"workflow_node.execute_failure.label": "若前序节点执行失败…",
|
||||
"workflow_node.execute_failure.default_name": "若前序节点执行失败…"
|
||||
"workflow_node.execute_failure.label": "若上一节点执行失败…",
|
||||
"workflow_node.execute_failure.default_name": "若上一节点执行失败…"
|
||||
}
|
||||
|
@ -12,9 +12,10 @@ import { useAntdForm } from "@/hooks";
|
||||
import { save as saveWorkflow } from "@/repository/workflow";
|
||||
import { getErrMsg } from "@/utils/error";
|
||||
|
||||
const TEMPLATE_KEY_BLANK = "blank" as const;
|
||||
const TEMPLATE_KEY_STANDARD = "standard" as const;
|
||||
type TemplateKeys = typeof TEMPLATE_KEY_BLANK | typeof TEMPLATE_KEY_STANDARD;
|
||||
const TEMPLATE_KEY_CERTTEST = "monitor" as const;
|
||||
const TEMPLATE_KEY_BLANK = "blank" as const;
|
||||
type TemplateKeys = typeof TEMPLATE_KEY_BLANK | typeof TEMPLATE_KEY_CERTTEST | typeof TEMPLATE_KEY_STANDARD;
|
||||
|
||||
const WorkflowNew = () => {
|
||||
const navigate = useNavigate();
|
||||
@ -27,8 +28,8 @@ const WorkflowNew = () => {
|
||||
xs: { flex: "100%" },
|
||||
md: { flex: "100%" },
|
||||
lg: { flex: "50%" },
|
||||
xl: { flex: "50%" },
|
||||
xxl: { flex: "50%" },
|
||||
xl: { flex: "33.3333%" },
|
||||
xxl: { flex: "33.3333%" },
|
||||
};
|
||||
const [templateSelectKey, setTemplateSelectKey] = useState<TemplateKeys>();
|
||||
|
||||
@ -64,6 +65,10 @@ const WorkflowNew = () => {
|
||||
workflow = initWorkflow({ template: "standard" });
|
||||
break;
|
||||
|
||||
case TEMPLATE_KEY_CERTTEST:
|
||||
workflow = initWorkflow({ template: "certtest" });
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Invalid state: `templateSelectKey`";
|
||||
}
|
||||
@ -116,7 +121,7 @@ const WorkflowNew = () => {
|
||||
</Card>
|
||||
|
||||
<div className="p-4">
|
||||
<div className="mx-auto max-w-[960px] px-2">
|
||||
<div className="mx-auto max-w-[1600px] px-2">
|
||||
<Typography.Text type="secondary">
|
||||
<div className="mb-8 mt-4 text-xl">{t("workflow.new.templates.title")}</div>
|
||||
</Typography.Text>
|
||||
@ -139,6 +144,25 @@ const WorkflowNew = () => {
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col {...templateGridSpans}>
|
||||
<Card
|
||||
className="size-full"
|
||||
cover={<img className="min-h-[120px] object-contain" src="/imgs/workflow/tpl-certtest.png" />}
|
||||
hoverable
|
||||
onClick={() => handleTemplateClick(TEMPLATE_KEY_CERTTEST)}
|
||||
>
|
||||
<div className="flex w-full items-center gap-4">
|
||||
<Card.Meta
|
||||
className="grow"
|
||||
title={t("workflow.new.templates.template.certtest.title")}
|
||||
description={t("workflow.new.templates.template.certtest.description")}
|
||||
/>
|
||||
<Spin spinning={templateSelectKey === TEMPLATE_KEY_CERTTEST} />
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col {...templateGridSpans}>
|
||||
<Card
|
||||
className="size-full"
|
||||
|
Loading…
x
Reference in New Issue
Block a user