fix conflict

This commit is contained in:
yoan
2025-01-19 19:02:58 +08:00
142 changed files with 3458 additions and 8971 deletions

View File

@@ -42,14 +42,14 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
<div className="mt-4 rounded-md bg-black p-4 text-stone-200">
<div className="flex flex-col space-y-3">
{data!.logs.map((item, i) => {
{data!.logs?.map((item, i) => {
return (
<div key={i} className="flex flex-col space-y-2">
<div>{item.nodeName}</div>
<div className="flex flex-col space-y-1">
{item.outputs.map((output, j) => {
{item.outputs?.map((output, j) => {
return (
<div key={j} className="flex space-x-2 text-sm">
<div key={j} className="flex space-x-2 text-sm" style={{ wordBreak: "break-word" }}>
<div className="whitespace-nowrap">[{dayjs(output.time).format("YYYY-MM-DD HH:mm:ss")}]</div>
{output.error ? <div className="text-red-500">{output.error}</div> : <div>{output.content}</div>}
</div>

View File

@@ -2,7 +2,22 @@ import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } f
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon, PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
import { useControllableValue } from "ahooks";
import { AutoComplete, type AutoCompleteProps, Button, Divider, Form, type FormInstance, Input, Select, Space, Switch, Tooltip, Typography } from "antd";
import {
AutoComplete,
type AutoCompleteProps,
Button,
Divider,
Flex,
Form,
type FormInstance,
Input,
InputNumber,
Select,
Space,
Switch,
Tooltip,
Typography,
} from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -42,8 +57,8 @@ const MULTIPLE_INPUT_DELIMITER = ";";
const initFormModel = (): ApplyNodeConfigFormFieldValues => {
return {
keyAlgorithm: "RSA2048",
propagationTimeout: 60,
disableFollowCNAME: true,
skipBeforeExpiryDays: 20,
};
};
@@ -77,13 +92,24 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
.split(MULTIPLE_INPUT_DELIMITER)
.every((e) => validIPv4Address(e) || validIPv6Address(e) || validDomainName(e));
}, t("common.errmsg.host_invalid")),
propagationTimeout: z
dnsPropagationTimeout: z
.union([
z.number().int().gte(1, t("workflow_node.apply.form.propagation_timeout.placeholder")),
z.string().refine((v) => !v || /^[1-9]\d*$/.test(v), t("workflow_node.apply.form.propagation_timeout.placeholder")),
z.number().int().gte(1, t("workflow_node.apply.form.dns_propagation_timeout.placeholder")),
z.string().refine((v) => !v || /^[1-9]\d*$/.test(v), t("workflow_node.apply.form.dns_propagation_timeout.placeholder")),
])
.nullish(),
dnsTTL: z
.union([
z.number().int().gte(1, t("workflow_node.apply.form.dns_ttl.placeholder")),
z.string().refine((v) => !v || /^[1-9]\d*$/.test(v), t("workflow_node.apply.form.dns_ttl.placeholder")),
])
.nullish(),
disableFollowCNAME: z.boolean().nullish(),
skipBeforeExpiryDays: z
.number({ message: t("workflow_node.apply.form.skip_before_expiry_days.placeholder") })
.int(t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
.gte(1, t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
.lte(60, t("workflow_node.apply.form.skip_before_expiry_days.placeholder")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
@@ -313,18 +339,34 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
</Form.Item>
<Form.Item
name="propagationTimeout"
label={t("workflow_node.apply.form.propagation_timeout.label")}
name="dnsPropagationTimeout"
label={t("workflow_node.apply.form.dns_propagation_timeout.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.propagation_timeout.tooltip") }}></span>}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.dns_propagation_timeout.tooltip") }}></span>}
>
<Input
type="number"
allowClear
min={0}
max={3600}
placeholder={t("workflow_node.apply.form.propagation_timeout.placeholder")}
addonAfter={t("workflow_node.apply.form.propagation_timeout.suffix")}
placeholder={t("workflow_node.apply.form.dns_propagation_timeout.placeholder")}
addonAfter={t("workflow_node.apply.form.dns_propagation_timeout.unit")}
/>
</Form.Item>
<Form.Item
name="dnsTTL"
label={t("workflow_node.apply.form.dns_ttl.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.dns_ttl.tooltip") }}></span>}
>
<Input
type="number"
allowClear
min={0}
max={86400}
placeholder={t("workflow_node.apply.form.dns_ttl.placeholder")}
addonAfter={t("workflow_node.apply.form.dns_ttl.unit")}
/>
</Form.Item>
@@ -337,6 +379,33 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
<Switch />
</Form.Item>
</Form>
<Divider className="my-1">
<Typography.Text className="text-xs font-normal" type="secondary">
{t("workflow_node.apply.form.strategy_config.label")}
</Typography.Text>
</Divider>
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
<Form.Item
label={t("workflow_node.apply.form.skip_before_expiry_days.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.skip_before_expiry_days.tooltip") }}></span>}
>
<Flex align="center" gap={8} wrap="wrap">
<div>{t("workflow_node.apply.form.skip_before_expiry_days.prefix")}</div>
<Form.Item name="skipBeforeExpiryDays" noStyle rules={[formRule]}>
<InputNumber
className="w-36"
min={1}
max={60}
placeholder={t("workflow_node.apply.form.skip_before_expiry_days.placeholder")}
addonAfter={t("workflow_node.apply.form.skip_before_expiry_days.unit")}
/>
</Form.Item>
<div>{t("workflow_node.apply.form.skip_before_expiry_days.suffix")}</div>
</Flex>
</Form.Item>
</Form>
</Form.Provider>
);
}

View File

@@ -1,7 +1,7 @@
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
import { Button, Divider, Form, type FormInstance, Select, Tooltip, Typography } from "antd";
import { Button, Divider, Flex, Form, type FormInstance, Select, Switch, Tooltip, Typography } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -65,7 +65,9 @@ export type DeployNodeConfigFormInstance = {
};
const initFormModel = (): DeployNodeConfigFormFieldValues => {
return {};
return {
skipOnLastSucceeded: true,
};
};
const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNodeConfigFormProps>(
@@ -91,6 +93,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
.nonempty(t("workflow_node.deploy.form.provider_access.placeholder"))
.refine(() => !!formInst.getFieldValue("provider"), t("workflow_node.deploy.form.provider.placeholder")),
providerConfig: z.any(),
skipOnLastSucceeded: z.boolean(),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
@@ -340,6 +343,27 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
{nestedFormEl}
</Show>
<Divider className="my-1">
<Typography.Text className="text-xs font-normal" type="secondary">
{t("workflow_node.deploy.form.strategy_config.label")}
</Typography.Text>
</Divider>
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
<Form.Item label={t("workflow_node.deploy.form.skip_on_last_succeeded.label")}>
<Flex align="center" gap={8} wrap="wrap">
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.prefix")}</div>
<Form.Item name="skipOnLastSucceeded" noStyle rules={[formRule]}>
<Switch
checkedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.on")}
unCheckedChildren={t("workflow_node.deploy.form.skip_on_last_succeeded.enabled.off")}
/>
</Form.Item>
<div>{t("workflow_node.deploy.form.skip_on_last_succeeded.suffix")}</div>
</Flex>
</Form.Item>
</Form>
</Form.Provider>
);
}

View File

@@ -6,7 +6,7 @@ import { z } from "zod";
import { validDomainName } from "@/utils/validators";
type DeployNodeConfigFormAliyunOSSConfigFieldValues = Nullish<{
endpoint: string;
region: string;
bucket: string;
domain: string;
}>;
@@ -33,9 +33,9 @@ const DeployNodeConfigFormAliyunOSSConfig = ({
const { t } = useTranslation();
const formSchema = z.object({
endpoint: z
.string({ message: t("workflow_node.deploy.form.aliyun_oss_endpoint.placeholder") })
.url(t("common.errmsg.url_invalid"))
region: z
.string({ message: t("workflow_node.deploy.form.aliyun_oss_region.placeholder") })
.nonempty(t("workflow_node.deploy.form.aliyun_oss_region.placeholder"))
.trim(),
bucket: z
.string({ message: t("workflow_node.deploy.form.aliyun_oss_bucket.placeholder") })
@@ -61,12 +61,12 @@ const DeployNodeConfigFormAliyunOSSConfig = ({
onValuesChange={handleFormChange}
>
<Form.Item
name="endpoint"
label={t("workflow_node.deploy.form.aliyun_oss_endpoint.label")}
name="region"
label={t("workflow_node.deploy.form.aliyun_oss_region.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_oss_endpoint.tooltip") }}></span>}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_oss_region.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.aliyun_oss_endpoint.placeholder")} />
<Input placeholder={t("workflow_node.deploy.form.aliyun_oss_region.placeholder")} />
</Form.Item>
<Form.Item

View File

@@ -5,6 +5,7 @@ import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import Show from "@/components/Show";
import { CERTIFICATE_FORMATS } from "@/domain/certificate";
type DeployNodeConfigFormLocalConfigFieldValues = Nullish<{
format: string;
@@ -27,9 +28,9 @@ export type DeployNodeConfigFormLocalConfigProps = {
onValuesChange?: (values: DeployNodeConfigFormLocalConfigFieldValues) => void;
};
const FORMAT_PEM = "PEM" as const;
const FORMAT_PFX = "PFX" as const;
const FORMAT_JKS = "JKS" as const;
const FORMAT_PEM = CERTIFICATE_FORMATS.PEM;
const FORMAT_PFX = CERTIFICATE_FORMATS.PFX;
const FORMAT_JKS = CERTIFICATE_FORMATS.JKS;
const SHELLENV_SH = "sh" as const;
const SHELLENV_CMD = "cmd" as const;

View File

@@ -5,6 +5,7 @@ import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import Show from "@/components/Show";
import { CERTIFICATE_FORMATS } from "@/domain/certificate";
type DeployNodeConfigFormSSHConfigFieldValues = Nullish<{
format: string;
@@ -26,9 +27,9 @@ export type DeployNodeConfigFormSSHConfigProps = {
onValuesChange?: (values: DeployNodeConfigFormSSHConfigFieldValues) => void;
};
const FORMAT_PEM = "PEM" as const;
const FORMAT_PFX = "PFX" as const;
const FORMAT_JKS = "JKS" as const;
const FORMAT_PEM = CERTIFICATE_FORMATS.PEM;
const FORMAT_PFX = CERTIFICATE_FORMATS.PFX;
const FORMAT_JKS = CERTIFICATE_FORMATS.JKS;
const initFormModel = (): DeployNodeConfigFormSSHConfigFieldValues => {
return {

View File

@@ -7,7 +7,7 @@ import {
MoreOutlined as MoreOutlinedIcon,
} from "@ant-design/icons";
import { useControllableValue } from "ahooks";
import { Button, Card, Drawer, Dropdown, Input, Modal, Popover, Space } from "antd";
import { Button, Card, Drawer, Dropdown, Input, type InputRef, Modal, Popover, Space } from "antd";
import { produce } from "immer";
import { isEqual } from "radash";
@@ -71,9 +71,10 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
const [modalApi, ModelContextHolder] = Modal.useModal();
const nameInputRef = useRef<InputRef>(null);
const nameRef = useRef<string>();
const handleRenameClick = async () => {
const handleRenameConfirm = async () => {
const oldName = node.name;
const newName = nameRef.current?.trim()?.substring(0, 64) || oldName;
if (oldName === newName) {
@@ -131,11 +132,12 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
content: (
<div className="pb-2 pt-4">
<Input
ref={(ref) => setTimeout(() => ref?.focus({ cursor: "end" }), 0)}
ref={nameInputRef}
autoFocus
defaultValue={node.name}
onChange={(e) => (nameRef.current = e.target.value)}
onPressEnter={async () => {
await handleRenameClick();
await handleRenameConfirm();
dialog.destroy();
}}
/>
@@ -143,8 +145,9 @@ const SharedNodeMenu = ({ trigger, node, disabled, branchId, branchIndex, afterU
),
icon: null,
okText: t("common.button.save"),
onOk: handleRenameClick,
onOk: handleRenameConfirm,
});
setTimeout(() => nameInputRef.current?.focus(), 1);
},
},
{