feat: add 1panel deployer

This commit is contained in:
Fu Diwei
2025-03-07 15:43:40 +08:00
parent 6ccbdeb89a
commit 29dda4ec66
32 changed files with 1098 additions and 10 deletions

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5156" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M69.530864 0h884.938272v1024H69.530864z" fill="#E0E0E0" fill-opacity="0"></path><path d="M79.560165 259.855802v503.572017l435.09465 250.73251 434.041152-250.73251-1.053498-502.518519-432.987654-250.73251-435.09465 249.679012z" fill="#005EFD"></path><path d="M93.255638 268.283786v486.716049l422.452675 241.251029 419.292181-242.304527v-485.662551l-421.399177-242.304527-420.345679 242.304527z" fill="#FFFFFF"></path><path d="M139.609547 294.621235l95.868313 56.888888 371.884774-218.074074-93.761317-53.728395-373.99177 214.913581z" fill="#005EFD"></path><path d="M139.609547 293.567737v435.09465l243.358025 139.061728 92.707819-55.835391-241.251029-140.115226 1.053498-320.263375-95.868313-57.942386zM791.269663 350.096329v321.780412l95.269925 55.732148V294.364181L645.749992 154.506008 551.527243 210.238156l239.74242 139.858173z" fill="#0854C1"></path><path d="M420.893498 886.470058l93.339918 56.052411 372.306172-214.692346-94.387094-57.110123L420.893498 886.470058zM385.074568 416.826996h49.88102v280.230453l93.3947 55.835391v-474.074075l-143.27572 81.119342v56.888889z" fill="#005EFD"></path><path d="M528.350288 752.89284l31.604938-16.855968v-440.362139l-31.604938-16.855968v474.074075z" fill="#0854C1"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -9,6 +9,7 @@ import { type AccessModel } from "@/domain/access";
import { ACCESS_PROVIDERS } from "@/domain/provider";
import { useAntdForm, useAntdFormName } from "@/hooks";
import AccessForm1PanelConfig from "./AccessForm1PanelConfig";
import AccessFormACMEHttpReqConfig from "./AccessFormACMEHttpReqConfig";
import AccessFormAliyunConfig from "./AccessFormAliyunConfig";
import AccessFormAWSConfig from "./AccessFormAWSConfig";
@@ -99,6 +100,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
NOTICE: If you add new child component, please keep ASCII order.
*/
switch (fieldProvider) {
case ACCESS_PROVIDERS["1PANEL"]:
return <AccessForm1PanelConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.ACMEHTTPREQ:
return <AccessFormACMEHttpReqConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.ALIYUN:

View File

@@ -0,0 +1,72 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import { type AccessConfigFor1Panel } from "@/domain/access";
type AccessForm1PanelConfigFieldValues = Nullish<AccessConfigFor1Panel>;
export type AccessForm1PanelConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessForm1PanelConfigFieldValues;
onValuesChange?: (values: AccessForm1PanelConfigFieldValues) => void;
};
const initFormModel = (): AccessForm1PanelConfigFieldValues => {
return {
apiUrl: "http://<your-host-addr>:20410/",
apiKey: "",
};
};
const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessForm1PanelConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
apiUrl: z.string().url(t("common.errmsg.url_invalid")),
apiKey: z
.string()
.min(1, t("access.form.1panel_api_key.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 }))
.trim(),
});
const formRule = createSchemaFieldRule(formSchema);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
return (
<Form
form={formInst}
disabled={disabled}
initialValues={initialValues ?? initFormModel()}
layout="vertical"
name={formName}
onValuesChange={handleFormChange}
>
<Form.Item
name="apiUrl"
label={t("access.form.1panel_api_url.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.1panel_api_url.tooltip") }}></span>}
>
<Input placeholder={t("access.form.1panel_api_url.placeholder")} />
</Form.Item>
<Form.Item
name="apiKey"
label={t("access.form.1panel_api_key.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.1panel_api_key.tooltip") }}></span>}
>
<Input.Password autoComplete="new-password" placeholder={t("access.form.1panel_api_key.placeholder")} />
</Form.Item>
</Form>
);
};
export default AccessForm1PanelConfig;

View File

@@ -17,7 +17,7 @@ export type AccessFormBaotaPanelConfigProps = {
const initFormModel = (): AccessFormBaotaPanelConfigFieldValues => {
return {
apiUrl: "http://<your-ipaddr>:8888/",
apiUrl: "http://<your-host-addr>:8888/",
apiKey: "",
};
};

View File

@@ -17,7 +17,7 @@ export type AccessFormCdnflyConfigProps = {
const initFormModel = (): AccessFormCdnflyConfigFieldValues => {
return {
apiUrl: "http://<your-ipaddr>:88/",
apiUrl: "http://<your-host-addr>:88/",
apiKey: "",
apiSecret: "",
};

View File

@@ -17,7 +17,7 @@ export type AccessFormPowerDNSConfigProps = {
const initFormModel = (): AccessFormPowerDNSConfigFieldValues => {
return {
apiUrl: "http://<your-ipaddr>:8082/",
apiUrl: "http://<your-host-addr>:8082/",
apiKey: "",
};
};

View File

@@ -17,7 +17,7 @@ export type AccessFormSafeLineConfigProps = {
const initFormModel = (): AccessFormSafeLineConfigFieldValues => {
return {
apiUrl: "http://<your-ipaddr>:9443/",
apiUrl: "http://<your-host-addr>:9443/",
apiToken: "",
};
};

View File

@@ -15,6 +15,8 @@ import { type WorkflowNode, type WorkflowNodeConfigForDeploy } from "@/domain/wo
import { useAntdForm, useAntdFormName, useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow";
import DeployNodeConfigForm1PanelConsoleConfig from "./DeployNodeConfigForm1PanelConsoleConfig";
import DeployNodeConfigForm1PanelSiteConfig from "./DeployNodeConfigForm1PanelSiteConfig";
import DeployNodeConfigFormAliyunALBConfig from "./DeployNodeConfigFormAliyunALBConfig";
import DeployNodeConfigFormAliyunCASDeployConfig from "./DeployNodeConfigFormAliyunCASDeployConfig";
import DeployNodeConfigFormAliyunCDNConfig from "./DeployNodeConfigFormAliyunCDNConfig";
@@ -138,6 +140,10 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
NOTICE: If you add new child component, please keep ASCII order.
*/
switch (fieldProvider) {
case DEPLOY_PROVIDERS["1PANEL_CONSOLE"]:
return <DeployNodeConfigForm1PanelConsoleConfig {...nestedFormProps} />;
case DEPLOY_PROVIDERS["1PANEL_SITE"]:
return <DeployNodeConfigForm1PanelSiteConfig {...nestedFormProps} />;
case DEPLOY_PROVIDERS.ALIYUN_ALB:
return <DeployNodeConfigFormAliyunALBConfig {...nestedFormProps} />;
case DEPLOY_PROVIDERS.ALIYUN_CAS_DEPLOY:

View File

@@ -0,0 +1,56 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
type DeployNodeConfigForm1PanelConsoleConfigFieldValues = Nullish<{
autoRestart?: boolean;
}>;
export type DeployNodeConfigForm1PanelConsoleConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: DeployNodeConfigForm1PanelConsoleConfigFieldValues;
onValuesChange?: (values: DeployNodeConfigForm1PanelConsoleConfigFieldValues) => void;
};
const initFormModel = (): DeployNodeConfigForm1PanelConsoleConfigFieldValues => {
return {};
};
const DeployNodeConfigForm1PanelConsoleConfig = ({
form: formInst,
formName,
disabled,
initialValues,
onValuesChange,
}: DeployNodeConfigForm1PanelConsoleConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
autoRestart: z.boolean().nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
return (
<Form
form={formInst}
disabled={disabled}
initialValues={initialValues ?? initFormModel()}
layout="vertical"
name={formName}
onValuesChange={handleFormChange}
>
<Form.Item name="autoRestart" label={t("workflow_node.deploy.form.1panel_console_auto_restart.label")} rules={[formRule]}>
<Switch />
</Form.Item>
</Form>
);
};
export default DeployNodeConfigForm1PanelConsoleConfig;

View File

@@ -0,0 +1,63 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
type DeployNodeConfigForm1PanelSiteConfigFieldValues = Nullish<{
websiteId: string | number;
}>;
export type DeployNodeConfigForm1PanelSiteConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: DeployNodeConfigForm1PanelSiteConfigFieldValues;
onValuesChange?: (values: DeployNodeConfigForm1PanelSiteConfigFieldValues) => void;
};
const initFormModel = (): DeployNodeConfigForm1PanelSiteConfigFieldValues => {
return {};
};
const DeployNodeConfigForm1PanelSiteConfig = ({
form: formInst,
formName,
disabled,
initialValues,
onValuesChange,
}: DeployNodeConfigForm1PanelSiteConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
websiteId: z.union([z.string(), z.number()]).refine((v) => {
return /^\d+$/.test(v + "") && +v > 0;
}, t("workflow_node.deploy.form.1panel_site_website_id.placeholder")),
});
const formRule = createSchemaFieldRule(formSchema);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
return (
<Form
form={formInst}
disabled={disabled}
initialValues={initialValues ?? initFormModel()}
layout="vertical"
name={formName}
onValuesChange={handleFormChange}
>
<Form.Item
name="websiteId"
label={t("workflow_node.deploy.form.1panel_site_website_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.1panel_site_website_id.tooltip") }}></span>}
>
<Input type="number" placeholder={t("workflow_node.deploy.form.1panel_site_website_id.placeholder")} />
</Form.Item>
</Form>
);
};
export default DeployNodeConfigForm1PanelSiteConfig;

View File

@@ -6,6 +6,7 @@ export interface AccessModel extends BaseModel {
NOTICE: If you add new type, please keep ASCII order.
*/ Record<string, unknown> &
(
| AccessConfigFor1Panel
| AccessConfigForACMEHttpReq
| AccessConfigForAliyun
| AccessConfigForAWS
@@ -46,6 +47,11 @@ export interface AccessModel extends BaseModel {
}
// #region AccessConfig
export type AccessConfigFor1Panel = {
apiUrl: string;
apiKey: string;
};
export type AccessConfigForACMEHttpReq = {
endpoint: string;
mode?: string;

View File

@@ -4,6 +4,7 @@
NOTICE: If you add new constant, please keep ASCII order.
*/
export const ACCESS_PROVIDERS = Object.freeze({
["1PANEL"]: "1panel",
ACMEHTTPREQ: "acmehttpreq",
ALIYUN: "aliyun",
AWS: "aws",
@@ -84,6 +85,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
[ACCESS_PROVIDERS.BYTEPLUS, "provider.byteplus", "/imgs/providers/byteplus.svg", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS.UCLOUD, "provider.ucloud", "/imgs/providers/ucloud.svg", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS.SAFELINE, "provider.safeline", "/imgs/providers/safeline.svg", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS["1PANEL"], "provider.1panel", "/imgs/providers/1panel.svg", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS.BAOTAPANEL, "provider.baotapanel", "/imgs/providers/baotapanel.svg", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS.CACHEFLY, "provider.cachefly", "/imgs/providers/cachefly.png", [ACCESS_USAGES.DEPLOY]],
[ACCESS_PROVIDERS.CDNFLY, "provider.cdnfly", "/imgs/providers/cdnfly.png", [ACCESS_USAGES.DEPLOY]],
@@ -211,6 +213,8 @@ export const applyDNSProvidersMap: Map<ApplyDNSProvider["type"] | string, ApplyD
NOTICE: If you add new constant, please keep ASCII order.
*/
export const DEPLOY_PROVIDERS = Object.freeze({
["1PANEL_CONSOLE"]: `${ACCESS_PROVIDERS["1PANEL"]}-console`,
["1PANEL_SITE"]: `${ACCESS_PROVIDERS["1PANEL"]}-site`,
ALIYUN_ALB: `${ACCESS_PROVIDERS.ALIYUN}-alb`,
ALIYUN_CAS_DEPLOY: `${ACCESS_PROVIDERS.ALIYUN}-casdeploy`,
ALIYUN_CDN: `${ACCESS_PROVIDERS.ALIYUN}-cdn`,
@@ -345,6 +349,8 @@ export const deployProvidersMap: Map<DeployProvider["type"] | string, DeployProv
[DEPLOY_PROVIDERS.CDNFLY, "provider.cdnfly", DEPLOY_CATEGORIES.CDN],
[DEPLOY_PROVIDERS.EDGIO_APPLICATIONS, "provider.edgio.applications", DEPLOY_CATEGORIES.WEBSITE],
[DEPLOY_PROVIDERS.GCORE_CDN, "provider.gcore.cdn", DEPLOY_CATEGORIES.CDN],
[DEPLOY_PROVIDERS["1PANEL_SITE"], "provider.1panel.site", DEPLOY_CATEGORIES.WEBSITE],
[DEPLOY_PROVIDERS["1PANEL_CONSOLE"], "provider.1panel.console", DEPLOY_CATEGORIES.OTHER],
[DEPLOY_PROVIDERS.BAOTAPANEL_SITE, "provider.baotapanel.site", DEPLOY_CATEGORIES.WEBSITE],
[DEPLOY_PROVIDERS.BAOTAPANEL_CONSOLE, "provider.baotapanel.console", DEPLOY_CATEGORIES.OTHER],
[DEPLOY_PROVIDERS.SAFELINE, "provider.safeline", DEPLOY_CATEGORIES.FIREWALL],

View File

@@ -23,6 +23,12 @@
"access.form.provider.label": "Provider",
"access.form.provider.placeholder": "Please select a provider",
"access.form.provider.tooltip": "DNS provider: The provider that hosts your domain names and manages your DNS records.<br>Host provider: The provider that hosts your servers or cloud services for deploying certificates.<br><br><i>Cannot be edited after saving.</i>",
"access.form.1panel_api_url.label": "1Panel URL",
"access.form.1panel_api_url.placeholder": "Please enter 1Panel URL",
"access.form.1panel_api_url.tooltip": "For more information, see <a href=\"https://docs.1panel.pro/dev_manual/api_manual/\" target=\"_blank\">https://docs.1panel.pro/dev_manual/api_manual/</a>",
"access.form.1panel_api_key.label": "1Panel API key",
"access.form.1panel_api_key.placeholder": "Please enter 1Panel API key",
"access.form.1panel_api_key.tooltip": "For more information, see <a href=\"https://docs.1panel.pro/dev_manual/api_manual/\" target=\"_blank\">https://docs.1panel.pro/dev_manual/api_manual/</a>",
"access.form.acmehttpreq_endpoint.label": "Endpoint",
"access.form.acmehttpreq_endpoint.placeholder": "Please enter endpoint",
"access.form.acmehttpreq_endpoint.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",

View File

@@ -1,5 +1,7 @@
{
"provider.1panel": "1Panel",
"provider.1panel.console": "1Panel - Console",
"provider.1panel.site": "1Panel - Website",
"provider.acmehttpreq": "Http Request (ACME Proxy)",
"provider.aliyun": "Alibaba Cloud",
"provider.aliyun.alb": "Alibaba Cloud - ALB (Application Load Balancer)",
@@ -28,7 +30,7 @@
"provider.baishan.cdn": "Baishan - CDN (Content Delivery Network)",
"provider.baotapanel": "aaPanel (aka BaoTaPanel)",
"provider.baotapanel.console": "aaPanel (aka BaoTaPanel) - Console",
"provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Site",
"provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Website",
"provider.byteplus": "BytePlus",
"provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)",
"provider.cachefly": "CacheFly",

View File

@@ -90,6 +90,10 @@
"workflow_node.deploy.form.certificate.placeholder": "Please select certificate",
"workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous application stage node.",
"workflow_node.deploy.form.params_config.label": "Parameter settings",
"workflow_node.deploy.form.1panel_console_auto_restart.label": "Auto restart after deployment",
"workflow_node.deploy.form.1panel_site_website_id.label": "1Panel website ID",
"workflow_node.deploy.form.1panel_site_website_id.placeholder": "Please enter 1Panel website ID",
"workflow_node.deploy.form.1panel_site_website_id.tooltip": "You can find it on 1Panel WebUI.",
"workflow_node.deploy.form.aliyun_alb_resource_type.label": "Resource type",
"workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "Please select resource type",
"workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "ALB load balancer",

View File

@@ -23,6 +23,12 @@
"access.form.provider.label": "提供商",
"access.form.provider.placeholder": "请选择提供商",
"access.form.provider.tooltip": "提供商分为两种类型:<br>【DNS 提供商】你的 DNS 托管方,通常等同于域名注册商,用于在申请证书时管理您的域名解析记录。<br>【主机提供商】你的服务器或云服务的托管方,用于部署签发的证书。<br><br>该字段保存后不可修改。",
"access.form.1panel_api_url.label": "1Panel URL",
"access.form.1panel_api_url.placeholder": "请输入 1Panel URL",
"access.form.1panel_api_url.tooltip": "这是什么?请参阅 <a href=\"https://1panel.cn/docs/dev_manual/api_manual/\" target=\"_blank\">https://1panel.cn/docs/dev_manual/api_manual/</a>",
"access.form.1panel_api_key.label": "1Panel 接口密钥",
"access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥",
"access.form.1panel_api_key.tooltip": "这是什么?请参阅 <a href=\"https://1panel.cn/docs/dev_manual/api_manual/\" target=\"_blank\">https://1panel.cn/docs/dev_manual/api_manual/</a>",
"access.form.acmehttpreq_endpoint.label": "服务端点",
"access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点",
"access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",

View File

@@ -1,5 +1,7 @@
{
"provider.1panel": "1Panel",
"provider.1panel.console": "1Panel - 面板",
"provider.1panel.site": "1Panel - 网站",
"provider.acmehttpreq": "Http Request (ACME Proxy)",
"provider.aliyun": "阿里云",
"provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB",

View File

@@ -90,6 +90,10 @@
"workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书",
"workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请阶段。如果选项为空请先确保前序节点配置正确。",
"workflow_node.deploy.form.params_config.label": "参数设置",
"workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务",
"workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID",
"workflow_node.deploy.form.1panel_site_website_id.placeholder": "请输入 1Panel 网站 ID",
"workflow_node.deploy.form.1panel_site_website_id.tooltip": "请在 1Panel 管理面板查看。",
"workflow_node.deploy.form.aliyun_alb_resource_type.label": "证书替换方式",
"workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "请选择证书替换方式",
"workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",