diff --git a/flocks/server/routes/workflow.py b/flocks/server/routes/workflow.py index 77ea94825..97a78f8fe 100644 --- a/flocks/server/routes/workflow.py +++ b/flocks/server/routes/workflow.py @@ -1436,7 +1436,7 @@ class SyslogConfigRequest(BaseModel): enabled: bool = False protocol: str = "udp" host: str = "0.0.0.0" - port: int = 5140 + port: int = Field(5140, ge=1, le=65535, description="Listener port (1-65535)") msg_format: str = Field("auto", alias="format") input_key: str = Field("syslog_message", alias="inputKey") diff --git a/webui/src/locales/en-US/workflow.json b/webui/src/locales/en-US/workflow.json index 303565d56..5f11d0227 100644 --- a/webui/src/locales/en-US/workflow.json +++ b/webui/src/locales/en-US/workflow.json @@ -214,6 +214,7 @@ "syslogFormat": "Parse format", "syslogInputKey": "Inputs key", "syslogHint": "When enabled, Flocks listens for syslog on the given address/port and passes parsed payloads to workflow inputs (default key: syslog_message).", + "syslogPortError": "Invalid port: must be an integer between 1 and 65535", "syslogActive": "Listening", "historySection": "Execution History", "noHistory": "No execution records", diff --git a/webui/src/locales/zh-CN/workflow.json b/webui/src/locales/zh-CN/workflow.json index 2524d9925..a87304085 100644 --- a/webui/src/locales/zh-CN/workflow.json +++ b/webui/src/locales/zh-CN/workflow.json @@ -214,6 +214,7 @@ "syslogFormat": "解析格式", "syslogInputKey": "Inputs 键名", "syslogHint": "开启后 Flocks 在指定地址/端口接收 syslog,解析结果写入工作流 inputs(默认键名 syslog_message)。", + "syslogPortError": "端口范围无效,请输入 1 ~ 65535 之间的整数", "syslogActive": "监听中", "historySection": "执行历史", "noHistory": "暂无执行记录", diff --git a/webui/src/pages/WorkflowDetail/tabs/IntegrationTab.tsx b/webui/src/pages/WorkflowDetail/tabs/IntegrationTab.tsx index 71e8666a7..b98bd9e18 100644 --- a/webui/src/pages/WorkflowDetail/tabs/IntegrationTab.tsx +++ b/webui/src/pages/WorkflowDetail/tabs/IntegrationTab.tsx @@ -322,6 +322,7 @@ function SyslogSection({ workflowId }: { workflowId: string }) { // falsely showing the listener as active. const [listener, setListener] = useState(null); const [saveError, setSaveError] = useState(''); + const [portError, setPortError] = useState(''); const refreshStatus = useCallback(async () => { try { @@ -387,7 +388,32 @@ function SyslogSection({ workflowId }: { workflowId: string }) { return () => window.clearInterval(handle); }, [isBinding, refreshStatus]); + const validatePort = (value: string): boolean => { + const trimmed = value.trim(); + if (!/^\d+$/.test(trimmed)) { + setPortError(t('detail.run.syslogPortError')); + return false; + } + const num = Number.parseInt(trimmed, 10); + if (num < 1 || num > 65535) { + setPortError(t('detail.run.syslogPortError')); + return false; + } + setPortError(''); + return true; + }; + + const handlePortChange = (value: string) => { + setPort(value); + if (value !== '') { + validatePort(value); + } else { + setPortError(''); + } + }; + const handleSave = async () => { + if (!validatePort(port)) return; setSaving(true); setSaved(false); setSaveError(''); @@ -466,7 +492,19 @@ function SyslogSection({ workflowId }: { workflowId: string }) { {inputField(t('detail.run.syslogHost'), host, setHost, '0.0.0.0')} - {inputField(t('detail.run.syslogPort'), port, setPort, '5140')} +
+ + handlePortChange(e.target.value)} + placeholder="5140" + className={`w-full text-xs border rounded-lg px-3 py-1.5 focus:outline-none focus:ring-1 ${portError ? 'border-red-400 focus:ring-red-500' : 'border-gray-200 focus:ring-red-500'}`} + /> + {portError && ( +

{portError}

+ )} +