diff --git a/ui/web/src/i18n/locales/en/cron.json b/ui/web/src/i18n/locales/en/cron.json index 521cb4c4..e169a897 100644 --- a/ui/web/src/i18n/locales/en/cron.json +++ b/ui/web/src/i18n/locales/en/cron.json @@ -128,7 +128,22 @@ "deleteAfterRun": "Delete after run", "deleteAfterRunDesc": "Auto-delete this job after first successful run", "timezone": "Timezone", - "timezoneDesc": "Timezone for cron expressions" + "timezoneDesc": "Timezone for cron expressions", + "commandSection": "Command", + "commandArgv": "Command", + "noCommand": "No command configured", + "commandCwd": "Working directory", + "defaultWorkingDirectory": "Gateway default", + "commandTimeout": "Timeout", + "commandOutputLimit": "Output limit", + "commandEnv": "Environment", + "commandInput": "Input", + "commandNoOutputTimeout": "No-output timeout", + "seconds": "{{count}}s", + "bytes": "{{count}} bytes", + "defaultValue": "Default", + "none": "None", + "envVars": "{{count}} vars" }, "stateless": "Stateless", "statelessHelp": "Skip session persistence. Each run starts fresh without loading previous messages. Saves tokens for crons that don't need past context.", @@ -145,5 +160,9 @@ "failedRun": "Failed to run cron job", "updated": "Job updated", "failedUpdate": "Failed to update job" + }, + "payload": { + "agent": "Agent", + "command": "Command" } } diff --git a/ui/web/src/i18n/locales/ko/cron.json b/ui/web/src/i18n/locales/ko/cron.json index 1cf17e0d..8ebad7ce 100644 --- a/ui/web/src/i18n/locales/ko/cron.json +++ b/ui/web/src/i18n/locales/ko/cron.json @@ -128,7 +128,22 @@ "deleteAfterRun": "실행 후 삭제", "deleteAfterRunDesc": "첫 번째 성공적인 실행 후 이 작업 자동 삭제", "timezone": "시간대", - "timezoneDesc": "Cron 표현식의 시간대" + "timezoneDesc": "Cron 표현식의 시간대", + "commandSection": "명령", + "commandArgv": "명령", + "noCommand": "설정된 명령 없음", + "commandCwd": "작업 디렉터리", + "defaultWorkingDirectory": "게이트웨이 기본값", + "commandTimeout": "타임아웃", + "commandOutputLimit": "출력 제한", + "commandEnv": "환경 변수", + "commandInput": "입력", + "commandNoOutputTimeout": "무출력 타임아웃", + "seconds": "{{count}}초", + "bytes": "{{count}} bytes", + "defaultValue": "기본값", + "none": "없음", + "envVars": "{{count}}개" }, "stateless": "상태 없음", "statelessHelp": "세션 지속성 건너뜁니다. 각 실행은 이전 메시지 없이 새로 시작됩니다. 이전 컨텍스트가 필요 없는 cron의 토큰을 절약합니다.", @@ -145,5 +160,9 @@ "failedRun": "Cron 작업 실행 실패", "updated": "작업 업데이트됨", "failedUpdate": "작업 업데이트 실패" + }, + "payload": { + "agent": "에이전트", + "command": "명령" } } diff --git a/ui/web/src/i18n/locales/vi/cron.json b/ui/web/src/i18n/locales/vi/cron.json index 85c23ba0..480e3cf4 100644 --- a/ui/web/src/i18n/locales/vi/cron.json +++ b/ui/web/src/i18n/locales/vi/cron.json @@ -128,7 +128,22 @@ "deleteAfterRun": "Xóa sau khi chạy", "deleteAfterRunDesc": "Tự động xóa công việc sau lần chạy thành công đầu tiên", "timezone": "Múi giờ", - "timezoneDesc": "Múi giờ cho biểu thức cron" + "timezoneDesc": "Múi giờ cho biểu thức cron", + "commandSection": "Lệnh", + "commandArgv": "Lệnh", + "noCommand": "Chưa cấu hình lệnh", + "commandCwd": "Thư mục làm việc", + "defaultWorkingDirectory": "Mặc định gateway", + "commandTimeout": "Thời gian chờ", + "commandOutputLimit": "Giới hạn output", + "commandEnv": "Môi trường", + "commandInput": "Input", + "commandNoOutputTimeout": "Timeout khi không có output", + "seconds": "{{count}}s", + "bytes": "{{count}} bytes", + "defaultValue": "Mặc định", + "none": "Không có", + "envVars": "{{count}} biến" }, "stateless": "Không trạng thái", "statelessHelp": "Bỏ qua lưu session. Mỗi lần chạy bắt đầu mới. Tiết kiệm token cho các cron không cần context cũ.", @@ -145,5 +160,9 @@ "failedRun": "Không thể chạy tác vụ định kỳ", "updated": "Đã cập nhật job", "failedUpdate": "Cập nhật job thất bại" + }, + "payload": { + "agent": "Agent", + "command": "Lệnh" } } diff --git a/ui/web/src/i18n/locales/zh/cron.json b/ui/web/src/i18n/locales/zh/cron.json index 0e5b232f..b1263a84 100644 --- a/ui/web/src/i18n/locales/zh/cron.json +++ b/ui/web/src/i18n/locales/zh/cron.json @@ -128,7 +128,22 @@ "deleteAfterRun": "运行后删除", "deleteAfterRunDesc": "首次成功运行后自动删除此任务", "timezone": "时区", - "timezoneDesc": "Cron表达式的时区" + "timezoneDesc": "Cron表达式的时区", + "commandSection": "命令", + "commandArgv": "命令", + "noCommand": "未配置命令", + "commandCwd": "工作目录", + "defaultWorkingDirectory": "网关默认值", + "commandTimeout": "超时", + "commandOutputLimit": "输出限制", + "commandEnv": "环境变量", + "commandInput": "输入", + "commandNoOutputTimeout": "无输出超时", + "seconds": "{{count}}秒", + "bytes": "{{count}} bytes", + "defaultValue": "默认值", + "none": "无", + "envVars": "{{count}}个变量" }, "stateless": "无状态", "statelessHelp": "跳过会话持久化。每次运行从零开始。为不需要历史上下文的定时任务节省令牌。", @@ -145,5 +160,9 @@ "failedRun": "运行定时任务失败", "updated": "任务已更新", "failedUpdate": "更新任务失败" + }, + "payload": { + "agent": "Agent", + "command": "命令" } } diff --git a/ui/web/src/pages/cron/cron-detail/cron-overview-tab.tsx b/ui/web/src/pages/cron/cron-detail/cron-overview-tab.tsx index f7cddd97..8e40b6b5 100644 --- a/ui/web/src/pages/cron/cron-detail/cron-overview-tab.tsx +++ b/ui/web/src/pages/cron/cron-detail/cron-overview-tab.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; -import { Calendar, Clock, AlertTriangle, Pencil } from "lucide-react"; +import { Calendar, Clock, AlertTriangle, Pencil, Terminal } from "lucide-react"; import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; import { Button } from "@/components/ui/button"; @@ -15,7 +15,7 @@ import { useChannels } from "@/pages/channels/hooks/use-channels"; import { useWs } from "@/hooks/use-ws"; import { Methods } from "@/api/protocol"; import type { CronJob, CronJobPatch } from "../hooks/use-cron"; -import { CronStatusBadge } from "../cron-utils"; +import { CronStatusBadge, formatCommand, isCommandCron } from "../cron-utils"; import { useAgents } from "@/pages/agents/hooks/use-agents"; import { CronScheduleSection } from "./cron-schedule-section"; import { CronDeliverySection } from "./cron-delivery-section"; @@ -66,6 +66,8 @@ export function CronOverviewTab({ job, onUpdate }: CronOverviewTabProps) { const [stateless, setStateless] = useState(job.stateless ?? false); const [saving, setSaving] = useState(false); + const command = job.payload?.command; + const commandEnvCount = command?.env ? Object.keys(command.env).length : 0; // Fetch delivery targets on mount const fetchTargets = useCallback(async () => { @@ -98,7 +100,7 @@ export function CronOverviewTab({ job, onUpdate }: CronOverviewTabProps) { } const patch: import("../hooks/use-cron").CronJobPatch = { schedule, - message: message.trim(), + message: isCommandCron(job) ? undefined : message.trim(), agentId: agentId.trim() || "", deliver, deliverChannel: deliver ? channel.trim() || undefined : undefined, @@ -134,31 +136,88 @@ export function CronOverviewTab({ job, onUpdate }: CronOverviewTabProps) { readonly={readonly} /> - {/* Message section */} -
-
-

{t("detail.messageSection")}

- {!readonly && ( - - )} -
- {editingMessage ? ( -