From 44ef355fe1f28b5fdd2e2d46b7f0e0306e97bdf2 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:53:41 +0800 Subject: [PATCH 01/15] fix(automations-ui): readable summary cards and NEXT RUN value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reflow the summary strip to at most three cards per row so the detail text no longer wraps one word per line, and let StatCard accept a valueClassName override so the NEXT RUN date renders at a smaller size instead of truncating to "Jun…". Default StatCard sizing is unchanged. --- .../static/js/design-system/primitives.js | 11 ++++++++++- .../components/automations-summary-strip.js | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/design-system/primitives.js b/crates/ironclaw_webui_v2_static/static/js/design-system/primitives.js index 12a39295f43..954333d17b6 100644 --- a/crates/ironclaw_webui_v2_static/static/js/design-system/primitives.js +++ b/crates/ironclaw_webui_v2_static/static/js/design-system/primitives.js @@ -42,6 +42,11 @@ export function cx(...classes) { * detail string (optional sub-text) * showDivider boolean * className string + * valueClassName string (optional) — overrides the value font-size classes. + * Defaults to the large numeric size; pass a smaller size for text values + * (e.g. a date) that would otherwise truncate. Note: `cn()` only + * concatenates (no tailwind-merge), so this REPLACES the size classes + * rather than appending to them. */ export function StatCard({ label, @@ -50,6 +55,7 @@ export function StatCard({ detail, showDivider = true, className = "", + valueClassName = "text-[1.75rem] md:text-[2rem]", }) { return html`
${value}
diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automations-summary-strip.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automations-summary-strip.js index 75d83159a0d..221188e5895 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automations-summary-strip.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automations-summary-strip.js @@ -39,12 +39,15 @@ export function AutomationsSummaryStrip({ summary }) { value: summary?.nextRun || t("automations.summary.none"), tone: "info", detail: t("automations.summary.nextRunDetail"), + // NEXT RUN is a date string, not a count — use a smaller size so it isn't + // truncated to "Jun…" inside a narrow card. + valueClassName: "text-lg md:text-xl", }, ]; return html` <${Panel} className="p-4 sm:p-5"> -
+
${cards.map((card) => html`
From a8c9e01365b245880734663a1662d9489939ff03 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:55:43 +0800 Subject: [PATCH 02/15] fix(automations-ui): surface delivery save errors and gate Slack hint The delivery-defaults panel swallowed save/clear failures and showed no feedback; it now renders an inline error from the mutation and flashes the "Saved" confirmation on Clear as well as Save. The "reply approve in Slack" footnote is hidden unless an external Slack-style target exists. --- .../static/js/i18n/en.js | 2 + .../automation-delivery-defaults-panel.js | 45 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js index 933dbfbc8f9..1b0ae462074 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js @@ -672,6 +672,8 @@ registerPack("en", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js index 5dcd416fc62..dc63f440a33 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js @@ -64,23 +64,32 @@ export function AutomationDeliveryDefaultsPanel({ deliveryState }) { opt?.capabilities?.final_replies && opt?.target?.status === "unavailable", ); + // The Slack approval footnote only makes sense when an external (Slack-style) + // target exists at all — paired or not. Web-only deployments shouldn't see a + // "reply in Slack" hint. + const hasExternalTargets = hasTargets || hasUnpairedTargets; - const handleSave = () => { - if (!canSave) return; - deliveryState - .saveFinalReplyTarget(draftTargetId || null) + // Flash the "Saved" confirmation; the mutation's rejection is reflected + // through `deliveryState.saveError` (rendered below), so the catch here only + // prevents an unhandled promise rejection. + const flashSavedOnSuccess = (promise) => + promise .then(() => { if (savedTimerRef.current) clearTimeout(savedTimerRef.current); setShowSaved(true); savedTimerRef.current = setTimeout(() => setShowSaved(false), 2200); }) .catch(() => {}); + + const handleSave = () => { + if (!canSave) return; + flashSavedOnSuccess(deliveryState.saveFinalReplyTarget(draftTargetId || null)); }; const handleClear = () => { if (!canClear) return; setDraftTargetId(""); - deliveryState.saveFinalReplyTarget(null).catch(() => {}); + flashSavedOnSuccess(deliveryState.saveFinalReplyTarget(null)); }; // ── Derived display values ────────────────────────────────────────── @@ -314,14 +323,28 @@ export function AutomationDeliveryDefaultsPanel({ deliveryState }) { ${t("automations.delivery.saved")} `} + ${deliveryState.saveError && + !showSaved && + html` + + <${Icon} name="close" className="h-3 w-3" /> + ${t("automations.delivery.saveFailed")} + + `}
- -
- ${footnoteSegments} -
+ + ${hasExternalTargets && + html` +
+ ${footnoteSegments} +
+ `}
From 97de732ad9fe3e8e4d235e0b6b8349a52103a5f1 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:58:06 +0800 Subject: [PATCH 03/15] fix(automations-ui): label sub-hourly cron schedules Minute- and hour-level cadences such as "* * * * *", "*/15 * * * *", and "0 * * * *" rendered as "Custom schedule" because they have no single clock time. They now read as "Every minute", "Every 15 minutes", and "Hourly at :00". --- .../automations/lib/automations-presenters.js | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js index 9fd5858044f..c10add1d309 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js @@ -110,13 +110,30 @@ export function scheduleLabel(cron, timezone) { if (!parts) return "Custom schedule"; const { minute, hour, dayOfMonth, month, dayOfWeek, year } = parts; - const time = formatCronTime(hour, minute); - if (!time) return "Custom schedule"; const tz = timezone && typeof timezone === "string" ? timezone : null; const tzSuffix = tz ? ` (${tz})` : ""; + const everyDate = + year === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*"; + + // Sub-hourly / hourly cadences, where hour (and possibly minute) is a + // wildcard or step and therefore has no single clock time. These are common + // ("every minute", "every 15 minutes", "hourly at :00") and previously fell + // through to the meaningless "Custom schedule". Timezone is irrelevant for a + // minute-of-hour cadence, so it is omitted here. + if (everyDate && hour === "*") { + if (minute === "*") return "Every minute"; + const step = minuteStep(minute); + if (step) return `Every ${step} minute${step === 1 ? "" : "s"}`; + if (isSingleNumber(minute, 0, 59)) { + return `Hourly at :${String(Number(minute)).padStart(2, "0")}`; + } + } + + const time = formatCronTime(hour, minute); + if (!time) return "Custom schedule"; - if (year === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { + if (everyDate) { return `Every day at ${time}${tzSuffix}`; } const normalizedDayOfWeek = normalizeDayOfWeek(dayOfWeek); @@ -326,6 +343,15 @@ function isSingleNumber(value, min, max) { return num >= min && num <= max; } +// Parse a `*/N` step expression into N, returning null when it isn't a valid +// minute step (1..=59). +function minuteStep(value) { + const match = /^\*\/(\d+)$/.exec(value); + if (!match) return null; + const step = Number(match[1]); + return step >= 1 && step <= 59 ? step : null; +} + function normalizeDayOfWeek(value) { const upper = String(value || "").toUpperCase(); const aliases = { From 5a3c797e339861c98d790ffd7cf84c2ebab45469 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:29:12 +0800 Subject: [PATCH 04/15] fix(automations-ui): space the run-row action button icons The "Open run" and "Logs" buttons in the recent-runs list rendered the icon flush against the label because the non-primary Button variants don't add a gap between children. Add the same icon margin the rest of the app uses for icon+label buttons. --- .../js/pages/automations/components/automation-recent-runs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-recent-runs.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-recent-runs.js index 1ec16b7d003..a48717b59f9 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-recent-runs.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-recent-runs.js @@ -71,7 +71,7 @@ export function RecentRunRow({ run, onOpenRun, onOpenLogs }) { disabled=${!canOpen} onClick=${canOpen ? () => onOpenRun(run.chat_path) : undefined} > - <${Icon} name="chat" className="h-4 w-4" /> + <${Icon} name="chat" className="mr-1.5 h-4 w-4" /> ${t("automations.detail.openRun")} <${Button} @@ -80,7 +80,7 @@ export function RecentRunRow({ run, onOpenRun, onOpenLogs }) { disabled=${!canOpenLogs} onClick=${canOpenLogs ? () => onOpenLogs(logsPath) : undefined} > - <${Icon} name="file" className="h-4 w-4" /> + <${Icon} name="file" className="mr-1.5 h-4 w-4" /> ${t("nav.logs")}
From 7e9044e4128b65060e30812dc27afcfed1d69d13 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:57:02 +0800 Subject: [PATCH 05/15] fix(automations-ui): consistent summary counts and next-run The Running/Failures summary cards counted individual runs while the matching filter tabs counted automations, so the numbers disagreed; both now count automations. The soonest "Next run" no longer includes paused triggers, which keep a stored slot they will never actually fire. --- .../static/js/i18n/en.js | 5 ++-- .../automations/lib/automations-presenters.js | 23 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js index 1b0ae462074..1598112f58b 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js @@ -690,9 +690,10 @@ registerPack("en", { "automations.summary.paused": "Paused", "automations.summary.pausedDetail": "Schedules not currently expected to run.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Automations with a run in progress.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": + "Automations with a failed run in recent history.", "automations.summary.nextRun": "Next run", "automations.summary.none": "None", "automations.summary.nextRunDetail": "Soonest scheduled run in this list.", diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js index c10add1d309..27ec286c50e 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js @@ -78,18 +78,19 @@ export function filterAutomations(automations, filter) { export function automationSummary(automations) { const active = automations.filter((automation) => isBrowserActive(automation)).length; - const running = automations.reduce( - (count, automation) => - count + automation.recent_runs.filter((run) => run.status === "running").length, - 0, - ); - const failures = automations.reduce( - (count, automation) => - count + automation.recent_runs.filter((run) => run.status === "error").length, - 0, - ); + // Count automations (not individual runs) so each card matches the + // same-named filter tab, which filters automations via has_running_run / + // has_failed_runs. + const running = automations.filter((automation) => automation.has_running_run).length; + const failures = automations.filter((automation) => automation.has_failed_runs).length; + // Only automations that will actually fire contribute to "soonest next run". + // Paused triggers keep their stored next_run_at slot, but they won't run, so + // surfacing their time here would imply a run that never happens. const next = automations - .filter((automation) => nextRunTimestamp(automation) !== null) + .filter( + (automation) => + isBrowserActive(automation) && nextRunTimestamp(automation) !== null, + ) .sort( (a, b) => (a.next_run_timestamp ?? Number.MAX_SAFE_INTEGER) - From c4f317e79fa87d61bab25358c350eb157efaf108 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:49:20 +0800 Subject: [PATCH 06/15] test(automations): lock the panel UI fixes into the served bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add static-asset assertions driving the composed router so each Automations panel UX fix — sub-hourly cron labels, summary card reflow + smaller NEXT RUN value, run-row icon spacing, and delivery save-error/Slack-hint gating — is guarded against a regression that drops it from the shipped SPA source. --- .../tests/webui_v2_serve.rs | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs b/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs index 52ac5e0d51e..7edcc9c4206 100644 --- a/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs +++ b/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs @@ -2784,3 +2784,122 @@ async fn public_route_mount_is_merged_without_bearer_auth_and_keeps_descriptor_p .expect("oneshot"); assert_eq!(protected.status(), StatusCode::UNAUTHORIZED); } + +// ─── Automations panel UI (fix/reborn-automations-ux) ───────────────── +// +// These lock the served automations SPA source shape so a regression that +// drops one of the panel UX fixes fails here. Behavioral JS coverage needs a +// browser harness this workspace does not own, so — per the existing +// `static_*` precedent — we assert the shipped asset content instead. + +#[tokio::test] +async fn static_automations_presenters_label_sub_hourly_schedules() { + let (app, _) = build_app(); + let response = app + .oneshot( + Request::builder() + .method(Method::GET) + .uri("/v2/js/pages/automations/lib/automations-presenters.js") + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("oneshot"); + assert_eq!(response.status(), StatusCode::OK); + let body = read_body_string(response).await; + + assert!( + body.contains("\"Every minute\""), + "presenters must label `* * * * *` as `Every minute` instead of `Custom schedule`" + ); + assert!( + body.contains("Every ${step} minute"), + "presenters must label `*/N * * * *` as `Every N minutes`" + ); + assert!( + body.contains("Hourly at :"), + "presenters must label `M * * * *` as an hourly cadence" + ); +} + +#[tokio::test] +async fn static_automations_summary_reflows_cards_and_shrinks_next_run() { + let (app, _) = build_app(); + let response = app + .oneshot( + Request::builder() + .method(Method::GET) + .uri("/v2/js/pages/automations/components/automations-summary-strip.js") + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("oneshot"); + assert_eq!(response.status(), StatusCode::OK); + let body = read_body_string(response).await; + + assert!( + body.contains("lg:grid-cols-3"), + "summary strip must cap cards per row so detail text stays readable" + ); + assert!( + !body.contains("xl:grid-cols-5"), + "summary strip must not force five cards into one row" + ); + assert!( + body.contains("valueClassName"), + "the NEXT RUN card must pass a smaller value font so the date is not truncated" + ); +} + +#[tokio::test] +async fn static_automations_run_row_spaces_action_button_icons() { + let (app, _) = build_app(); + let response = app + .oneshot( + Request::builder() + .method(Method::GET) + .uri("/v2/js/pages/automations/components/automation-recent-runs.js") + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("oneshot"); + assert_eq!(response.status(), StatusCode::OK); + let body = read_body_string(response).await; + + assert!( + body.contains("name=\"chat\" className=\"mr-1.5 h-4 w-4\""), + "the Open run button icon must be spaced away from its label" + ); + assert!( + body.contains("name=\"file\" className=\"mr-1.5 h-4 w-4\""), + "the Logs button icon must be spaced away from its label" + ); +} + +#[tokio::test] +async fn static_automations_delivery_surfaces_save_error_and_gates_slack_hint() { + let (app, _) = build_app(); + let response = app + .oneshot( + Request::builder() + .method(Method::GET) + .uri("/v2/js/pages/automations/components/automation-delivery-defaults-panel.js") + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("oneshot"); + assert_eq!(response.status(), StatusCode::OK); + let body = read_body_string(response).await; + + assert!( + body.contains("deliveryState.saveError"), + "the delivery panel must render the save error instead of swallowing it" + ); + assert!( + body.contains("hasExternalTargets"), + "the Slack approval footnote must be gated on an external target existing" + ); +} From 5c6c0dbc317e2d52347983ae8d320419363600af Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:13:24 +0800 Subject: [PATCH 07/15] feat(automations): surface scheduler-off state and run it by default on serve Scheduled automations never fired because the trigger poller is disabled by default and nothing told the user. The list response now carries scheduler_enabled (sourced from runtime readiness) and the panel shows a "scheduling is turned off" notice when it is false. The local `ironclaw-reborn serve` surface enables the poller by default; config and env still override it. --- .../src/reborn_services.rs | 16 ++- .../src/reborn_services/types.rs | 10 ++ .../tests/reborn_services_contract.rs | 34 +++++ crates/ironclaw_reborn_cli/src/runtime/mod.rs | 1 + .../src/runtime/trigger_poller.rs | 122 ++++++++++++------ .../src/automation.rs | 18 +++ .../ironclaw_reborn_composition/src/webui.rs | 7 +- .../tests/webui_v2_serve.rs | 1 + .../tests/webui_v2_handlers_contract.rs | 1 + .../static/js/i18n/en.js | 3 + .../js/pages/automations/automations-page.js | 15 +++ .../pages/automations/hooks/useAutomations.js | 6 + 12 files changed, 193 insertions(+), 41 deletions(-) diff --git a/crates/ironclaw_product_workflow/src/reborn_services.rs b/crates/ironclaw_product_workflow/src/reborn_services.rs index 1af197766db..3d970d81a54 100644 --- a/crates/ironclaw_product_workflow/src/reborn_services.rs +++ b/crates/ironclaw_product_workflow/src/reborn_services.rs @@ -484,6 +484,16 @@ pub trait AutomationProductFacade: Send + Sync { request: AutomationListRequest, ) -> Result, RebornServicesError>; + /// Whether the background trigger poller (scheduler) is running. + /// + /// Surfaced to the browser so the panel can warn that listed automations + /// will not fire while scheduling is off. Defaults to `true` so a facade + /// that does not know its scheduler state never produces a false "off" + /// notice; the production facade overrides this with the real value. + fn scheduler_enabled(&self) -> bool { + true + } + /// Looks up the stored trigger-thread scope for a given `thread_id`. /// /// Scans the caller-scoped triggers for one whose run history contains @@ -2140,11 +2150,15 @@ impl RebornServicesApi for RebornServices { }; let limit = clamp_automation_list_limit(request.limit); let run_limit = clamp_automation_run_limit(request.run_limit); + let scheduler_enabled = self.automation_facade.scheduler_enabled(); let automations = self .automation_facade .list_automations(caller, AutomationListRequest { limit, run_limit }) .await?; - Ok(RebornListAutomationsResponse { automations }) + Ok(RebornListAutomationsResponse { + automations, + scheduler_enabled, + }) } async fn list_connectable_channels( diff --git a/crates/ironclaw_product_workflow/src/reborn_services/types.rs b/crates/ironclaw_product_workflow/src/reborn_services/types.rs index 100c83c618e..b33f6450ac9 100644 --- a/crates/ironclaw_product_workflow/src/reborn_services/types.rs +++ b/crates/ironclaw_product_workflow/src/reborn_services/types.rs @@ -391,6 +391,16 @@ pub struct RebornListThreadsResponse { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RebornListAutomationsResponse { pub automations: Vec, + /// Whether the background trigger poller (scheduler) is running. When + /// `false`, listed schedule automations will never actually fire, and the + /// browser surfaces a "scheduling is off" notice. Defaults to `true` on the + /// wire so an older payload without the field is not misreported as off. + #[serde(default = "default_scheduler_enabled")] + pub scheduler_enabled: bool, +} + +fn default_scheduler_enabled() -> bool { + true } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/ironclaw_product_workflow/tests/reborn_services_contract.rs b/crates/ironclaw_product_workflow/tests/reborn_services_contract.rs index 98f99ef0b15..ebf84a15b0b 100644 --- a/crates/ironclaw_product_workflow/tests/reborn_services_contract.rs +++ b/crates/ironclaw_product_workflow/tests/reborn_services_contract.rs @@ -858,6 +858,7 @@ impl AutomationProductFacade for RecordingAutomationFacade { #[derive(Clone)] struct StaticAutomationFacade { output: Vec, + scheduler_enabled: bool, /// Scopes returned by `resolve_run_thread_scope`, keyed by the queried /// thread id so tests prove the lookup contract rather than accepting a /// cached scope for any request. @@ -869,11 +870,17 @@ impl StaticAutomationFacade { fn new(output: Vec) -> Self { Self { output, + scheduler_enabled: true, resolve_scopes: HashMap::new(), resolve_calls: Arc::new(Mutex::new(Vec::new())), } } + fn with_scheduler_enabled(mut self, scheduler_enabled: bool) -> Self { + self.scheduler_enabled = scheduler_enabled; + self + } + fn with_resolve_scope_for_thread( mut self, thread_id: ThreadId, @@ -890,6 +897,10 @@ impl StaticAutomationFacade { #[async_trait] impl AutomationProductFacade for StaticAutomationFacade { + fn scheduler_enabled(&self) -> bool { + self.scheduler_enabled + } + async fn list_automations( &self, _caller: ProductAgentBoundCaller, @@ -6394,6 +6405,29 @@ async fn list_automations_returns_empty_list() { .expect("list automations"); assert!(listed.automations.is_empty()); + // Default facade reports the scheduler as running. + assert!(listed.scheduler_enabled); +} + +#[tokio::test] +async fn list_automations_surfaces_disabled_scheduler() { + // Regression: when the trigger poller is off, the response must report + // scheduler_enabled=false so the browser can warn that listed automations + // will not fire. Previously the wire response had no such signal. + let services = RebornServices::new( + Arc::new(InMemorySessionThreadService::default()), + Arc::new(FakeTurnCoordinator::default()), + ) + .with_automation_product_facade(Arc::new( + StaticAutomationFacade::new(Vec::new()).with_scheduler_enabled(false), + )); + + let listed = services + .list_automations(caller(), WebUiListAutomationsRequest::default()) + .await + .expect("list automations"); + + assert!(!listed.scheduler_enabled); } #[tokio::test] diff --git a/crates/ironclaw_reborn_cli/src/runtime/mod.rs b/crates/ironclaw_reborn_cli/src/runtime/mod.rs index 56e4f9bf4ed..c6b97e87d47 100644 --- a/crates/ironclaw_reborn_cli/src/runtime/mod.rs +++ b/crates/ironclaw_reborn_cli/src/runtime/mod.rs @@ -363,6 +363,7 @@ pub(crate) fn build_runtime_input_with_options( .with_runner_settings(runner_settings(runtime_services.config_file.as_ref())?) .with_trigger_poller_settings(trigger_poller_settings( runtime_services.config_file.as_ref(), + caller, )?) .with_poll_settings(PollSettings { interval: Duration::from_millis(200), diff --git a/crates/ironclaw_reborn_cli/src/runtime/trigger_poller.rs b/crates/ironclaw_reborn_cli/src/runtime/trigger_poller.rs index 0e34a726fbd..5a7fcc11c58 100644 --- a/crates/ironclaw_reborn_cli/src/runtime/trigger_poller.rs +++ b/crates/ironclaw_reborn_cli/src/runtime/trigger_poller.rs @@ -2,6 +2,8 @@ use std::time::Duration; use ironclaw_reborn_composition::TriggerPollerSettings; +use super::RuntimeInputCaller; + /// Read a trigger-poller env var with **strict** presence semantics. /// /// `IRONCLAW_TRIGGER_POLLER_*` env vars are operator-control knobs: presence @@ -77,8 +79,12 @@ fn truncate_env_value_for_display(raw: &str) -> String { /// config-file `poll_interval_secs`. Must be > 0. /// 2. Config-file `[trigger_poller]` section — all fields are optional; any field /// absent here falls through to the compiled default. -/// 3. Compiled default — `TriggerPollerSettings::default()` (disabled, all limits -/// at the `ironclaw_triggers` crate defaults). +/// 3. Compiled default — `TriggerPollerSettings::default()` (all limits at the +/// `ironclaw_triggers` crate defaults). The `enabled` default depends on the +/// caller: the local `serve` surface enables the scheduler by default so +/// automations actually run, while every other caller defaults to disabled. +/// Config and env still override this (an env kill-switch wins), because +/// this layer is applied first. /// /// V1 invariant: `max_concurrent_fires_per_trigger` must be exactly 1. Passing /// any other value (via config or, were an env override ever added, env) returns @@ -88,9 +94,15 @@ fn truncate_env_value_for_display(raw: &str) -> String { /// config fails at boot-config parse rather than at first poller spawn. pub(super) fn trigger_poller_settings( config_file: Option<&ironclaw_reborn_config::RebornConfigFile>, + caller: RuntimeInputCaller, ) -> anyhow::Result { - // Layer 3: compiled default (disabled). + // Layer 3: compiled default. `enabled` is on by default for the local + // `serve` surface (so scheduled automations actually fire) and off + // everywhere else; config/env below still override it. let mut settings = TriggerPollerSettings::default(); + if caller == RuntimeInputCaller::Serve { + settings.enabled = true; + } // Layer 2: config-file [trigger_poller] section. if let Some(section) = config_file.and_then(|file| file.trigger_poller.as_ref()) { @@ -194,7 +206,7 @@ pub(super) fn trigger_poller_settings( #[cfg(test)] mod tests { use super::super::test_env::{EnvGuard, lock_trigger_env}; - use super::trigger_poller_settings; + use super::{RuntimeInputCaller, trigger_poller_settings}; use ironclaw_reborn_config::TriggerPollerConfigSection; use std::time::Duration; @@ -216,13 +228,45 @@ mod tests { let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let settings = trigger_poller_settings(None).expect("default trigger poller settings"); + let settings = trigger_poller_settings(None, RuntimeInputCaller::Run) + .expect("default trigger poller settings"); assert!(!settings.enabled, "default must be disabled"); assert_eq!(settings.startup_jitter_max, Duration::ZERO); assert_eq!(settings.tick_jitter_max, Duration::ZERO); } + #[test] + fn trigger_poller_settings_serve_default_is_enabled() { + // Regression: the local `serve` surface must default the scheduler on so + // scheduled automations actually fire, while other callers stay off. + let _lock = lock_trigger_env(); + let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); + let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); + + let settings = trigger_poller_settings(None, RuntimeInputCaller::Serve) + .expect("serve trigger poller settings"); + + assert!(settings.enabled, "serve must default the scheduler on"); + } + + #[test] + fn trigger_poller_settings_serve_default_respects_env_kill_switch() { + // The serve-on default is layer 3, so an explicit env kill-switch still + // wins and turns the scheduler off. + let _lock = lock_trigger_env(); + let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", "0"); + let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); + + let settings = trigger_poller_settings(None, RuntimeInputCaller::Serve) + .expect("serve trigger poller settings with kill switch"); + + assert!( + !settings.enabled, + "env kill-switch must override the serve-on default" + ); + } + #[test] fn trigger_poller_settings_config_enabled_maps_worker_fields() { let _lock = lock_trigger_env(); @@ -239,8 +283,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = - trigger_poller_settings(Some(&config)).expect("trigger poller settings from config"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("trigger poller settings from config"); assert!(settings.enabled, "config enabled=true must be reflected"); assert_eq!(settings.worker.poll_interval, Duration::from_secs(15)); @@ -259,7 +303,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("max_concurrent_fires_per_trigger=2 must be rejected"); assert!( @@ -277,7 +321,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("poll_interval_secs=0 must be rejected"); assert!( @@ -299,7 +343,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = trigger_poller_settings(Some(&config)).expect("env override should succeed"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("env override should succeed"); assert!( settings.enabled, "IRONCLAW_TRIGGER_POLLER_ENABLED=true must override config enabled=false" @@ -319,8 +364,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = - trigger_poller_settings(Some(&config)).expect("env kill-switch should succeed"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("env kill-switch should succeed"); assert!( !settings.enabled, "IRONCLAW_TRIGGER_POLLER_ENABLED=false must override config enabled=true" @@ -340,8 +385,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = - trigger_poller_settings(Some(&config)).expect("env interval override should succeed"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("env interval override should succeed"); assert_eq!( settings.worker.poll_interval, Duration::from_secs(45), @@ -355,7 +400,7 @@ mod tests { let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); let _interval = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS", "0"); - let err = trigger_poller_settings(None) + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) .expect_err("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS=0 must be rejected"); assert!( @@ -371,8 +416,8 @@ mod tests { let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); let _interval = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS", "10s"); - let err = - trigger_poller_settings(None).expect_err("non-numeric env interval must be rejected"); + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) + .expect_err("non-numeric env interval must be rejected"); let msg = err.to_string(); assert!( @@ -387,7 +432,7 @@ mod tests { let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", "yes"); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let err = trigger_poller_settings(None) + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) .expect_err("IRONCLAW_TRIGGER_POLLER_ENABLED=yes must be rejected"); let msg = err.to_string(); @@ -406,8 +451,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = - trigger_poller_settings(Some(&config)).expect_err("fires_per_tick=0 must be rejected"); + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect_err("fires_per_tick=0 must be rejected"); assert!( err.to_string().contains("fires_per_tick"), @@ -426,7 +471,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("poll_interval_secs above the cap must be rejected"); let msg = err.to_string(); @@ -445,7 +490,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("fires_per_tick above the cap must be rejected"); let msg = err.to_string(); @@ -464,7 +509,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("startup_jitter_max_secs above the cap must be rejected"); assert!( @@ -482,7 +527,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("tick_jitter_max_secs above the cap must be rejected"); assert!( @@ -497,7 +542,7 @@ mod tests { let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); let _interval = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS", "86400"); - let err = trigger_poller_settings(None) + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) .expect_err("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS above the cap must be rejected"); let msg = err.to_string(); @@ -515,7 +560,7 @@ mod tests { let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", "YES"); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let err = trigger_poller_settings(None) + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) .expect_err("IRONCLAW_TRIGGER_POLLER_ENABLED=YES must be rejected"); let msg = err.to_string(); @@ -537,7 +582,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = trigger_poller_settings(Some(&config)) + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect("poll_interval_secs at the cap must be accepted"); assert_eq!(settings.worker.poll_interval, Duration::from_secs(3600)); } @@ -554,7 +599,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = trigger_poller_settings(Some(&config)) + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect("fires_per_tick at the cap must be accepted"); assert_eq!(settings.worker.fires_per_tick, 1000); } @@ -572,8 +617,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = - trigger_poller_settings(Some(&config)).expect("jitter at the cap must be accepted"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("jitter at the cap must be accepted"); assert_eq!(settings.startup_jitter_max, Duration::from_secs(3600)); assert_eq!(settings.tick_jitter_max, Duration::from_secs(3600)); } @@ -589,7 +634,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)) + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) .expect_err("max_concurrent_fires_per_trigger=0 must be rejected"); assert!( err.to_string().contains("max_concurrent_fires_per_trigger"), @@ -603,7 +648,8 @@ mod tests { let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", "1"); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let settings = trigger_poller_settings(None).expect("ENABLED=1 must succeed"); + let settings = + trigger_poller_settings(None, RuntimeInputCaller::Run).expect("ENABLED=1 must succeed"); assert!( settings.enabled, "IRONCLAW_TRIGGER_POLLER_ENABLED=1 must enable" @@ -622,7 +668,8 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let settings = trigger_poller_settings(Some(&config)).expect("ENABLED=0 must succeed"); + let settings = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run) + .expect("ENABLED=0 must succeed"); assert!( !settings.enabled, "IRONCLAW_TRIGGER_POLLER_ENABLED=0 must disable" @@ -639,7 +686,8 @@ mod tests { let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", &long_value); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let err = trigger_poller_settings(None).expect_err("long ENABLED value must be rejected"); + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) + .expect_err("long ENABLED value must be rejected"); let msg = err.to_string(); assert!( @@ -668,7 +716,7 @@ mod tests { }; let config = make_config_with_trigger_poller(section); - let err = trigger_poller_settings(Some(&config)).expect_err( + let err = trigger_poller_settings(Some(&config), RuntimeInputCaller::Run).expect_err( "empty IRONCLAW_TRIGGER_POLLER_ENABLED must be rejected, not silently dropped", ); @@ -685,7 +733,7 @@ mod tests { let _enabled = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_ENABLED", " "); let _interval = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS"); - let err = trigger_poller_settings(None) + let err = trigger_poller_settings(None, RuntimeInputCaller::Run) .expect_err("whitespace-only IRONCLAW_TRIGGER_POLLER_ENABLED must be rejected"); assert!( @@ -701,7 +749,7 @@ mod tests { let _enabled = EnvGuard::clear("IRONCLAW_TRIGGER_POLLER_ENABLED"); let _interval = EnvGuard::set("IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS", ""); - let err = trigger_poller_settings(None).expect_err( + let err = trigger_poller_settings(None, RuntimeInputCaller::Run).expect_err( "empty IRONCLAW_TRIGGER_POLLER_INTERVAL_SECS must be rejected, not silently dropped", ); diff --git a/crates/ironclaw_reborn_composition/src/automation.rs b/crates/ironclaw_reborn_composition/src/automation.rs index 440c20ba93c..50491185dbf 100644 --- a/crates/ironclaw_reborn_composition/src/automation.rs +++ b/crates/ironclaw_reborn_composition/src/automation.rs @@ -35,6 +35,11 @@ const AUTOMATION_BACKEND_TIMEOUT: Duration = Duration::from_secs(30); pub struct RebornAutomationProductFacade { trigger_repository: Arc, backend_timeout: Duration, + /// Whether the background trigger poller is running. Surfaced to the WebUI + /// so the panel can warn that listed automations will not fire while + /// scheduling is off. Defaults to `true`; production wiring sets the real + /// value from runtime readiness. + scheduler_enabled: bool, } impl std::fmt::Debug for RebornAutomationProductFacade { @@ -51,9 +56,17 @@ impl RebornAutomationProductFacade { Self { trigger_repository, backend_timeout: AUTOMATION_BACKEND_TIMEOUT, + scheduler_enabled: true, } } + /// Set whether the background trigger poller (scheduler) is running. Wired + /// by WebUI composition from runtime readiness. + pub(crate) fn with_scheduler_enabled(mut self, scheduler_enabled: bool) -> Self { + self.scheduler_enabled = scheduler_enabled; + self + } + #[cfg(test)] pub(crate) fn with_backend_timeout( trigger_repository: Arc, @@ -62,12 +75,17 @@ impl RebornAutomationProductFacade { Self { trigger_repository, backend_timeout, + scheduler_enabled: true, } } } #[async_trait::async_trait] impl AutomationProductFacade for RebornAutomationProductFacade { + fn scheduler_enabled(&self) -> bool { + self.scheduler_enabled + } + async fn list_automations( &self, caller: ProductAgentBoundCaller, diff --git a/crates/ironclaw_reborn_composition/src/webui.rs b/crates/ironclaw_reborn_composition/src/webui.rs index 21ec0fd4cb6..fb8d71baa3f 100644 --- a/crates/ironclaw_reborn_composition/src/webui.rs +++ b/crates/ironclaw_reborn_composition/src/webui.rs @@ -166,9 +166,10 @@ pub(crate) fn build_webui_services_with_connectable_channels( from_local }; if let Some(repository) = automation_repository { - api = api.with_automation_product_facade(Arc::new(RebornAutomationProductFacade::new( - repository, - ))); + api = api.with_automation_product_facade(Arc::new( + RebornAutomationProductFacade::new(repository) + .with_scheduler_enabled(services.readiness.workers.trigger_poller), + )); } if let Some(local_runtime) = &services.local_runtime { api = api.with_outbound_preferences_facade(Arc::new(RebornOutboundPreferencesFacade::new( diff --git a/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs b/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs index 7edcc9c4206..940d596f8b5 100644 --- a/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs +++ b/crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs @@ -954,6 +954,7 @@ impl RebornServicesApi for StubServices { ) -> Result { Ok(RebornListAutomationsResponse { automations: Vec::new(), + scheduler_enabled: true, }) } diff --git a/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs b/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs index 5631121d4c2..4139916a651 100644 --- a/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs +++ b/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs @@ -518,6 +518,7 @@ impl RebornServicesApi for StubServices { "Daily status", "0 9 * * *", )], + scheduler_enabled: true, }) } diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js index 1598112f58b..3597390c3fe 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/en.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/en.js @@ -655,6 +655,9 @@ registerPack("en", { "automations.filter.paused": "Paused", "automations.refresh": "Refresh automations", "automations.error.loadFailed": "Unable to load automations", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/automations-page.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/automations-page.js index 5831f7c6bf6..2ae62282a27 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/automations-page.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/automations-page.js @@ -46,6 +46,21 @@ export function AutomationsPage() { ${showErrorOnly ? null : html` + ${!automationsState.isLoading && + !automationsState.schedulerEnabled && + html` +
+
+ ${t("automations.schedulerOff.title")} +
+
+ ${t("automations.schedulerOff.description")} +
+
+ `} <${AutomationsSummaryStrip} summary=${automationsState.summary} /> <${AutomationDeliveryDefaultsPanel} deliveryState=${deliveryState} /> diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/hooks/useAutomations.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/hooks/useAutomations.js index e309adcd3f7..b9fe0159e98 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/hooks/useAutomations.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/hooks/useAutomations.js @@ -31,9 +31,15 @@ export function useAutomations() { [automations] ); + // The scheduler (trigger poller) may be turned off, in which case listed + // automations never fire. Treat an absent flag as enabled so we don't show a + // false "off" notice against an older payload. + const schedulerEnabled = query.data?.scheduler_enabled !== false; + return { automations, summary, + schedulerEnabled, isLoading: query.isLoading, isRefreshing: query.isFetching, error: query.error || null, From bad26e451e4d3b7ba0dffe08f8c78d6c7c7a8a7f Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:06:45 +0800 Subject: [PATCH 08/15] fix(i18n): add automations.delivery.saveFailed to every locale pack The new key was added only to en.js, which breaks the i18n consistency test that requires all locale packs to share the English key set. Add it to the ten other packs (English placeholder, matching the existing untranslated automations strings there). --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 2 ++ crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 2 ++ 10 files changed, 20 insertions(+) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index b9f6c321007..e06d7eb1995 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -646,6 +646,8 @@ registerPack("ar", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index b760a4223b9..47fff26c381 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -646,6 +646,8 @@ registerPack("de", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 6ceec1a7ba6..0b4c4ddd73e 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -646,6 +646,8 @@ registerPack("es", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index e36cc204ca2..ad8dbb36cb4 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -646,6 +646,8 @@ registerPack("fr", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index 0cff6860cf2..78f09ff920f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -646,6 +646,8 @@ registerPack("hi", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index b23d186a481..ce412f618bf 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -646,6 +646,8 @@ registerPack("ja", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index 44f3c414343..58b597fe887 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -646,6 +646,8 @@ registerPack("ko", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index dc5a73078c7..163cd8e2c08 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -646,6 +646,8 @@ registerPack("pt-BR", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index d3a245a64d1..baff91011fc 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -646,6 +646,8 @@ registerPack("uk", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index d9f60bd3db6..235869f9a7f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -646,6 +646,8 @@ registerPack("zh-CN", { "automations.delivery.save": "Save", "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", + "automations.delivery.saveFailed": + "Couldn't save the delivery target. Please try again.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", From 7ddf6cf6f7cf5151c608cceb1656d2974dbc884b Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:12:34 +0800 Subject: [PATCH 09/15] fix(automations-ui): clear stale Saved flash before a new delivery write The save-error alert is gated on !showSaved, so a "Saved" flash still showing from a prior success would hide the error of a new failing save/clear. Reset the flash (and its timer) at the start of every attempt. --- .../components/automation-delivery-defaults-panel.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js index dc63f440a33..ced94b05cfe 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/components/automation-delivery-defaults-panel.js @@ -71,15 +71,19 @@ export function AutomationDeliveryDefaultsPanel({ deliveryState }) { // Flash the "Saved" confirmation; the mutation's rejection is reflected // through `deliveryState.saveError` (rendered below), so the catch here only - // prevents an unhandled promise rejection. - const flashSavedOnSuccess = (promise) => - promise + // prevents an unhandled promise rejection. Clear any lingering "Saved" flash + // up front: the error alert is gated on `!showSaved`, so a stale flash from a + // prior success would otherwise hide the error of a new failing attempt. + const flashSavedOnSuccess = (promise) => { + if (savedTimerRef.current) clearTimeout(savedTimerRef.current); + setShowSaved(false); + return promise .then(() => { - if (savedTimerRef.current) clearTimeout(savedTimerRef.current); setShowSaved(true); savedTimerRef.current = setTimeout(() => setShowSaved(false), 2200); }) .catch(() => {}); + }; const handleSave = () => { if (!canSave) return; From 56073af55fd97a78cb0067f0957d70e07da27836 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:14:06 +0800 Subject: [PATCH 10/15] fix(automations): harden next-run filter and lock scheduler_enabled on the wire Use loose `!= null` in the soonest-next-run filter so a missing next_run_timestamp can't slip through, and assert scheduler_enabled in the list-automations handler contract test so a serialization drift of the new field is caught at the wire, not just in the facade. --- crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs | 3 +++ .../static/js/pages/automations/lib/automations-presenters.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs b/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs index 4139916a651..20595ace707 100644 --- a/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs +++ b/crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs @@ -1451,6 +1451,9 @@ async fn list_automations_forwards_query_limits_to_facade() { body["automations"][0]["recent_runs"][0]["status"], "running" ); + // The scheduler status must survive handler serialization onto the wire so + // the browser can warn when scheduling is off. + assert_eq!(body["scheduler_enabled"], true); let calls = services .list_automations_calls diff --git a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js index 27ec286c50e..f5b83e84bf0 100644 --- a/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js +++ b/crates/ironclaw_webui_v2_static/static/js/pages/automations/lib/automations-presenters.js @@ -89,7 +89,7 @@ export function automationSummary(automations) { const next = automations .filter( (automation) => - isBrowserActive(automation) && nextRunTimestamp(automation) !== null, + isBrowserActive(automation) && nextRunTimestamp(automation) != null, ) .sort( (a, b) => From 5c6aed0ce5a1ed7c6fb53b1eaea15c772ca02cc9 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:15:28 +0800 Subject: [PATCH 11/15] fix(i18n): add automations.schedulerOff keys to every locale pack The scheduler-off notice keys were added only to en.js, which breaks the i18n consistency test requiring all locale packs to share the English key set. Add both keys to the ten other packs (English placeholder). --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 3 +++ crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 3 +++ 10 files changed, 30 insertions(+) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index e06d7eb1995..f84915047b9 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -632,6 +632,9 @@ registerPack("ar", { "automations.filter.paused": "متوقف مؤقتًا", "automations.refresh": "تحديث عمليات الأتمتة", "automations.error.loadFailed": "غير قادر على تحميل عمليات الأتمتة", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index 47fff26c381..62a6aea5bc7 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -632,6 +632,9 @@ registerPack("de", { "automations.filter.paused": "Angehalten", "automations.refresh": "Automatisierungen aktualisieren", "automations.error.loadFailed": "Automatisierungen können nicht geladen werden", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 0b4c4ddd73e..234b701d5e3 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -632,6 +632,9 @@ registerPack("es", { "automations.filter.paused": "En pausa", "automations.refresh": "Actualizar automatizaciones", "automations.error.loadFailed": "No se pueden cargar automatizaciones", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index ad8dbb36cb4..b7733ab363d 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -632,6 +632,9 @@ registerPack("fr", { "automations.filter.paused": "En pause", "automations.refresh": "Actualiser les automatisations", "automations.error.loadFailed": "Impossible de charger les automatisations", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index 78f09ff920f..f5d11db8010 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -632,6 +632,9 @@ registerPack("hi", { "automations.filter.paused": "रोका गया", "automations.refresh": "ऑटोमेशन ताज़ा करें", "automations.error.loadFailed": "ऑटोमेशन लोड करने में असमर्थ", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index ce412f618bf..e94637abe0a 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -632,6 +632,9 @@ registerPack("ja", { "automations.filter.paused": "一時停止", "automations.refresh": "自動化の更新", "automations.error.loadFailed": "自動化をロードできません", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index 58b597fe887..8fdef95ca08 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -632,6 +632,9 @@ registerPack("ko", { "automations.filter.paused": "일시 중지됨", "automations.refresh": "자동화 새로 고침", "automations.error.loadFailed": "자동화를 로드할 수 없음", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index 163cd8e2c08..fe8f43d3648 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -632,6 +632,9 @@ registerPack("pt-BR", { "automations.filter.paused": "Pausado", "automations.refresh": "Atualizar automações", "automations.error.loadFailed": "Não é possível carregar automações", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index baff91011fc..85cd7a05084 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -632,6 +632,9 @@ registerPack("uk", { "automations.filter.paused": "Призупинено", "automations.refresh": "Оновити автоматизації", "automations.error.loadFailed": "Неможливо завантажити автоматизації", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index 235869f9a7f..9ca4c97184f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -632,6 +632,9 @@ registerPack("zh-CN", { "automations.filter.paused": "暂已挂起与暂停的自动化", "automations.refresh": "更新最新自动化", "automations.error.loadFailed": "提取系统自动化计划列表不成功!", + "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.description": + "These automations are saved but won't run until the scheduler is enabled.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", From f93c097b7394ac3b4daaa1ec57f67bb3abe88711 Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:47:03 +0800 Subject: [PATCH 12/15] i18n(automations): translate schedulerOff strings in all locale packs The scheduler-off notice was English in every non-English pack, giving Arabic/German/Spanish/French/Hindi/Japanese/Korean/pt-BR/Ukrainian/zh-CN users a mixed-language UI. Provide real translations. --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 4 ++-- crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index f84915047b9..98cec39a869 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -632,9 +632,9 @@ registerPack("ar", { "automations.filter.paused": "متوقف مؤقتًا", "automations.refresh": "تحديث عمليات الأتمتة", "automations.error.loadFailed": "غير قادر على تحميل عمليات الأتمتة", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "تم إيقاف الجدولة", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "هذه الأتمتة محفوظة لكنها لن تعمل حتى يتم تفعيل المجدول.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index 62a6aea5bc7..fbdbd258427 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -632,9 +632,9 @@ registerPack("de", { "automations.filter.paused": "Angehalten", "automations.refresh": "Automatisierungen aktualisieren", "automations.error.loadFailed": "Automatisierungen können nicht geladen werden", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "Planung ist deaktiviert", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "Diese Automatisierungen sind gespeichert, werden aber erst ausgeführt, wenn die Planung aktiviert ist.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 234b701d5e3..58bc1606995 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -632,9 +632,9 @@ registerPack("es", { "automations.filter.paused": "En pausa", "automations.refresh": "Actualizar automatizaciones", "automations.error.loadFailed": "No se pueden cargar automatizaciones", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "La programación está desactivada", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "Estas automatizaciones están guardadas, pero no se ejecutarán hasta que se active la programación.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index b7733ab363d..b7ca51331a3 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -632,9 +632,9 @@ registerPack("fr", { "automations.filter.paused": "En pause", "automations.refresh": "Actualiser les automatisations", "automations.error.loadFailed": "Impossible de charger les automatisations", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "La planification est désactivée", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "Ces automatisations sont enregistrées mais ne s'exécuteront pas tant que la planification n'est pas activée.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index f5d11db8010..6547ccfa492 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -632,9 +632,9 @@ registerPack("hi", { "automations.filter.paused": "रोका गया", "automations.refresh": "ऑटोमेशन ताज़ा करें", "automations.error.loadFailed": "ऑटोमेशन लोड करने में असमर्थ", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "शेड्यूलिंग बंद है", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "ये ऑटोमेशन सहेजे गए हैं लेकिन शेड्यूलर सक्षम होने तक नहीं चलेंगे।", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index e94637abe0a..a6a6d82d599 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -632,9 +632,9 @@ registerPack("ja", { "automations.filter.paused": "一時停止", "automations.refresh": "自動化の更新", "automations.error.loadFailed": "自動化をロードできません", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "スケジュールは無効です", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "これらのオートメーションは保存されていますが、スケジューラーを有効にするまで実行されません。", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index 8fdef95ca08..3682b1fce02 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -632,9 +632,9 @@ registerPack("ko", { "automations.filter.paused": "일시 중지됨", "automations.refresh": "자동화 새로 고침", "automations.error.loadFailed": "자동화를 로드할 수 없음", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "예약 실행이 꺼져 있습니다", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "이 자동화는 저장되었지만 스케줄러를 켜기 전에는 실행되지 않습니다.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index fe8f43d3648..dc1e8ab05e5 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -632,9 +632,9 @@ registerPack("pt-BR", { "automations.filter.paused": "Pausado", "automations.refresh": "Atualizar automações", "automations.error.loadFailed": "Não é possível carregar automações", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "O agendamento está desativado", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "Estas automações estão salvas, mas não serão executadas até que o agendamento seja ativado.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index 85cd7a05084..c0ac1113920 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -632,9 +632,9 @@ registerPack("uk", { "automations.filter.paused": "Призупинено", "automations.refresh": "Оновити автоматизації", "automations.error.loadFailed": "Неможливо завантажити автоматизації", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "Планування вимкнено", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "Ці автоматизації збережено, але вони не запускатимуться, доки не ввімкнено планувальник.", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index 9ca4c97184f..44c39afd40f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -632,9 +632,9 @@ registerPack("zh-CN", { "automations.filter.paused": "暂已挂起与暂停的自动化", "automations.refresh": "更新最新自动化", "automations.error.loadFailed": "提取系统自动化计划列表不成功!", - "automations.schedulerOff.title": "Scheduling is turned off", + "automations.schedulerOff.title": "调度已关闭", "automations.schedulerOff.description": - "These automations are saved but won't run until the scheduler is enabled.", + "这些自动化已保存,但在启用调度器之前不会运行。", "automations.delivery.eyebrow": "Delivery defaults", "automations.delivery.title": "Where triggered results are sent", "automations.delivery.explainer": "Choose where automation results are delivered when a triggered run finishes.", From 1fd3335236fac949a4dce5718151a09cfbdca9ca Mon Sep 17 00:00:00 2001 From: italic-jinxin <106428113+italic-jinxin@users.noreply.github.com> Date: Mon, 15 Jun 2026 19:47:43 +0800 Subject: [PATCH 13/15] i18n(automations): translate delivery.saveFailed in all locale packs The save-failed delivery error was English in every non-English pack. Provide real translations so users don't see mixed-language UI when a save fails. --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 2 +- crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index e06d7eb1995..5e3f329cc0e 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -647,7 +647,7 @@ registerPack("ar", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "تعذّر حفظ وجهة التسليم. يرجى المحاولة مرة أخرى.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index 47fff26c381..92056c27d17 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -647,7 +647,7 @@ registerPack("de", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "Zustellungsziel konnte nicht gespeichert werden. Bitte versuche es erneut.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 0b4c4ddd73e..59be5efd8c4 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -647,7 +647,7 @@ registerPack("es", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "No se pudo guardar el destino de entrega. Inténtalo de nuevo.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index ad8dbb36cb4..31822ded396 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -647,7 +647,7 @@ registerPack("fr", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "Impossible d'enregistrer la cible de distribution. Veuillez réessayer.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index 78f09ff920f..042489c9a69 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -647,7 +647,7 @@ registerPack("hi", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "डिलीवरी लक्ष्य सहेजा नहीं जा सका। कृपया पुनः प्रयास करें।", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index ce412f618bf..c6b7be1e869 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -647,7 +647,7 @@ registerPack("ja", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "配信先を保存できませんでした。もう一度お試しください。", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index 58b597fe887..8fced01f32a 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -647,7 +647,7 @@ registerPack("ko", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "전달 대상을 저장하지 못했습니다. 다시 시도해 주세요.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index 163cd8e2c08..86e0e1386fa 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -647,7 +647,7 @@ registerPack("pt-BR", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "Não foi possível salvar o destino de entrega. Tente novamente.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index baff91011fc..fbde771dff0 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -647,7 +647,7 @@ registerPack("uk", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "Не вдалося зберегти ціль доставки. Спробуйте ще раз.", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index 235869f9a7f..57807994424 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -647,7 +647,7 @@ registerPack("zh-CN", { "automations.delivery.clear": "Clear", "automations.delivery.saved": "Saved", "automations.delivery.saveFailed": - "Couldn't save the delivery target. Please try again.", + "无法保存投递目标,请重试。", "automations.delivery.footnote": "Approval requests sent to your DM are answered by replying {command} in Slack.", "automations.delivery.pill.ready": "Ready", "automations.delivery.pill.unavailable": "Unavailable", From 1087a2aa945d096745f0803d90f31937a02f9dbe Mon Sep 17 00:00:00 2001 From: Robert Yan Date: Mon, 15 Jun 2026 15:08:41 +0000 Subject: [PATCH 14/15] Localize automation summary counts --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 8 ++++---- crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 8 ++++---- 10 files changed, 40 insertions(+), 40 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index 8e8dc6dc5c3..fd859d071dc 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -662,9 +662,9 @@ registerPack("ar", { "automations.summary.active": "نشطة", "automations.summary.activeDetail": "الجداول الزمنية الممكّنة في انتظار التشغيل التالي.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "الأتمتات التي لديها تشغيل قيد التقدم.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "الأتمتات التي لديها تشغيل فاشل في السجل الحديث.", "automations.summary.paused": "متوقف مؤقتًا", "automations.summary.pausedDetail": "لا يُتوقع تشغيل الجداول حاليًا.", "automations.summary.nextRun": "التشغيل التالي", @@ -987,9 +987,9 @@ registerPack("ar", { "automations.status.needsReview": "بحاجة إلى مراجعة", "automations.status.running": "قيد التشغيل", "automations.summary.failures": "الإخفاقات", - "automations.summary.failuresDetail": "عمليات التشغيل الفاشلة في السجل المرئي.", + "automations.summary.failuresDetail": "الأتمتات التي لديها تشغيل فاشل في السجل الحديث.", "automations.summary.running": "قيد التشغيل الآن", - "automations.summary.runningDetail": "عمليات التشغيل الجارية حاليًا.", + "automations.summary.runningDetail": "الأتمتات التي لديها تشغيل قيد التقدم.", "automations.table.noRuns": "لا توجد عمليات تشغيل", "automations.table.recentRuns": "عمليات التشغيل الأخيرة", "skills.cancel": "إلغاء", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index ca3a85275cf..28d6f9248b8 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -662,9 +662,9 @@ registerPack("de", { "automations.summary.active": "Aktive", "automations.summary.activeDetail": "Aktivierte Zeitpläne, die auf ihre nächste Ausführung warten.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Automatisierungen mit einem aktiven Lauf.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "Automatisierungen mit einem fehlgeschlagenen Lauf im aktuellen Verlauf.", "automations.summary.paused": "Angehalten", "automations.summary.pausedDetail": "Zeitpläne werden derzeit voraussichtlich nicht ausgeführt.", "automations.summary.nextRun": "Nächster Lauf", @@ -987,9 +987,9 @@ registerPack("de", { "automations.status.needsReview": "Prüfung erforderlich", "automations.status.running": "Läuft", "automations.summary.failures": "Fehler", - "automations.summary.failuresDetail": "Fehlgeschlagene Läufe im sichtbaren Verlauf.", + "automations.summary.failuresDetail": "Automatisierungen mit einem fehlgeschlagenen Lauf im aktuellen Verlauf.", "automations.summary.running": "Läuft jetzt", - "automations.summary.runningDetail": "Aktuell laufende Läufe.", + "automations.summary.runningDetail": "Automatisierungen mit einem aktiven Lauf.", "automations.table.noRuns": "Keine Läufe", "automations.table.recentRuns": "Aktuelle Läufe", "skills.cancel": "Abbrechen", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 50f038ad994..444def9ec6e 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -662,9 +662,9 @@ registerPack("es", { "automations.summary.active": "Activo", "automations.summary.activeDetail": "Horarios habilitados esperando su próxima ejecución.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Automatizaciones con una ejecución en curso.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "Automatizaciones con una ejecución fallida en el historial reciente.", "automations.summary.paused": "En pausa", "automations.summary.pausedDetail": "Actualmente no se espera que se ejecuten los horarios.", "automations.summary.nextRun": "Próxima ejecución", @@ -988,9 +988,9 @@ registerPack("es", { "automations.status.needsReview": "Requiere revisión", "automations.status.running": "En ejecución", "automations.summary.failures": "Fallos", - "automations.summary.failuresDetail": "Ejecuciones fallidas en el historial visible.", + "automations.summary.failuresDetail": "Automatizaciones con una ejecución fallida en el historial reciente.", "automations.summary.running": "En ejecución ahora", - "automations.summary.runningDetail": "Ejecuciones actualmente en curso.", + "automations.summary.runningDetail": "Automatizaciones con una ejecución en curso.", "automations.table.noRuns": "Sin ejecuciones", "automations.table.recentRuns": "Ejecuciones recientes", "skills.cancel": "Cancelar", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index 18f014a8867..f01ab59e19b 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -662,9 +662,9 @@ registerPack("fr", { "automations.summary.active": "Actif", "automations.summary.activeDetail": "Planifications activées en attente de leur prochaine exécution.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Automatisations avec une exécution en cours.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "Automatisations avec une exécution échouée dans l’historique récent.", "automations.summary.paused": "En pause", "automations.summary.pausedDetail": "Les programmes ne devraient pas s'exécuter actuellement.", "automations.summary.nextRun": "Prochaine exécution", @@ -987,9 +987,9 @@ registerPack("fr", { "automations.status.needsReview": "À vérifier", "automations.status.running": "En cours", "automations.summary.failures": "Échecs", - "automations.summary.failuresDetail": "Exécutions échouées dans l’historique visible.", + "automations.summary.failuresDetail": "Automatisations avec une exécution échouée dans l’historique récent.", "automations.summary.running": "En cours", - "automations.summary.runningDetail": "Exécutions actuellement en cours.", + "automations.summary.runningDetail": "Automatisations avec une exécution en cours.", "automations.table.noRuns": "Aucune exécution", "automations.table.recentRuns": "Exécutions récentes", "skills.cancel": "Annuler", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index cdd90fe6998..4d7c07cbeed 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -662,9 +662,9 @@ registerPack("hi", { "automations.summary.active": "सक्रिय", "automations.summary.activeDetail": "सक्षम शेड्यूल अपने अगले रन की प्रतीक्षा कर रहे हैं।", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "वे ऑटोमेशन जिनका रन चल रहा है।", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "वे ऑटोमेशन जिनका हाल के इतिहास में रन विफल हुआ है।", "automations.summary.paused": "रोका गया", "automations.summary.pausedDetail": "शेड्यूल फिलहाल चलने की उम्मीद नहीं है।", "automations.summary.nextRun": "अगला रन", @@ -987,9 +987,9 @@ registerPack("hi", { "automations.status.needsReview": "समीक्षा चाहिए", "automations.status.running": "चल रहा है", "automations.summary.failures": "विफलताएं", - "automations.summary.failuresDetail": "दिखाई दे रहे इतिहास में विफल रन।", + "automations.summary.failuresDetail": "वे ऑटोमेशन जिनका हाल के इतिहास में रन विफल हुआ है।", "automations.summary.running": "अभी चल रहा है", - "automations.summary.runningDetail": "वर्तमान में चल रहे रन।", + "automations.summary.runningDetail": "वे ऑटोमेशन जिनका रन चल रहा है।", "automations.table.noRuns": "कोई रन नहीं", "automations.table.recentRuns": "हाल के रन", "skills.cancel": "रद्द करें", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index e5d1686bb03..ebccde01278 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -662,9 +662,9 @@ registerPack("ja", { "automations.summary.active": "アクティブ", "automations.summary.activeDetail": "次の実行を待機しているスケジュールを有効にしました。", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "実行中の実行があるオートメーション。", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "最近の履歴に失敗した実行があるオートメーション。", "automations.summary.paused": "一時停止", "automations.summary.pausedDetail": "スケジュールは現在実行される予定がありません。", "automations.summary.nextRun": "次の実行", @@ -987,9 +987,9 @@ registerPack("ja", { "automations.status.needsReview": "確認が必要", "automations.status.running": "実行中", "automations.summary.failures": "失敗", - "automations.summary.failuresDetail": "表示中の履歴にある失敗した実行。", + "automations.summary.failuresDetail": "最近の履歴に失敗した実行があるオートメーション。", "automations.summary.running": "現在実行中", - "automations.summary.runningDetail": "現在進行中の実行。", + "automations.summary.runningDetail": "実行中の実行があるオートメーション。", "automations.table.noRuns": "実行なし", "automations.table.recentRuns": "最近の実行", "skills.cancel": "キャンセル", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index d3b0176fa19..66e9b5ada40 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -662,9 +662,9 @@ registerPack("ko", { "automations.summary.active": "활성", "automations.summary.activeDetail": "다음 실행을 기다리는 활성화된 일정입니다.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "진행 중인 실행이 있는 자동화입니다.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "최근 기록에 실패한 실행이 있는 자동화입니다.", "automations.summary.paused": "일시중지됨", "automations.summary.pausedDetail": "현재 실행될 것으로 예상되지 않는 일정입니다.", "automations.summary.nextRun": "다음 실행", @@ -987,9 +987,9 @@ registerPack("ko", { "automations.status.needsReview": "검토 필요", "automations.status.running": "실행 중", "automations.summary.failures": "실패", - "automations.summary.failuresDetail": "표시된 기록의 실패한 실행입니다.", + "automations.summary.failuresDetail": "최근 기록에 실패한 실행이 있는 자동화입니다.", "automations.summary.running": "현재 실행 중", - "automations.summary.runningDetail": "현재 진행 중인 실행입니다.", + "automations.summary.runningDetail": "진행 중인 실행이 있는 자동화입니다.", "automations.table.noRuns": "실행 없음", "automations.table.recentRuns": "최근 실행", "skills.cancel": "취소", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index e1c105e61ec..392ee051a0f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -662,9 +662,9 @@ registerPack("pt-BR", { "automations.summary.active": "Ativo", "automations.summary.activeDetail": "Programações habilitadas aguardando sua próxima execução.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Automações com uma execução em andamento.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "Automações com uma execução com falha no histórico recente.", "automations.summary.paused": "Pausado", "automations.summary.pausedDetail": "Programações que não estão previstas para serem executadas no momento.", "automations.summary.nextRun": "Próxima execução", @@ -987,9 +987,9 @@ registerPack("pt-BR", { "automations.status.needsReview": "Precisa de revisão", "automations.status.running": "Em execução", "automations.summary.failures": "Falhas", - "automations.summary.failuresDetail": "Execuções com falha no histórico visível.", + "automations.summary.failuresDetail": "Automações com uma execução com falha no histórico recente.", "automations.summary.running": "Em execução agora", - "automations.summary.runningDetail": "Execuções atualmente em andamento.", + "automations.summary.runningDetail": "Automações com uma execução em andamento.", "automations.table.noRuns": "Nenhuma execução", "automations.table.recentRuns": "Execuções recentes", "skills.cancel": "Cancelar", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index d87fb67c8d4..e2f92dff4e2 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -662,9 +662,9 @@ registerPack("uk", { "automations.summary.active": "Активний", "automations.summary.activeDetail": "Увімкнені розклади, які очікують наступного запуску.", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "Автоматизації із запуском, що виконується.", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "Автоматизації з невдалим запуском у нещодавній історії.", "automations.summary.paused": "Призупинено", "automations.summary.pausedDetail": "Розклади наразі не запускаються.", "automations.summary.nextRun": "Наступний запуск", @@ -987,9 +987,9 @@ registerPack("uk", { "automations.status.needsReview": "Потребує перевірки", "automations.status.running": "Виконується", "automations.summary.failures": "Збої", - "automations.summary.failuresDetail": "Невдалі запуски у видимій історії.", + "automations.summary.failuresDetail": "Автоматизації з невдалим запуском у нещодавній історії.", "automations.summary.running": "Виконується зараз", - "automations.summary.runningDetail": "Запуски, що виконуються зараз.", + "automations.summary.runningDetail": "Автоматизації із запуском, що виконується.", "automations.table.noRuns": "Немає запусків", "automations.table.recentRuns": "Останні запуски", "skills.cancel": "Скасувати", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index b2ba6e92b7e..40d7eeac42b 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -662,9 +662,9 @@ registerPack("zh-CN", { "automations.summary.active": "可用计划项", "automations.summary.activeDetail": "目前所有已经启动运作在期待在最近运行时刻触发的自动化项目。", "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Runs currently in progress.", + "automations.summary.runningDetail": "有运行正在进行的自动化。", "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Failed runs in the visible history.", + "automations.summary.failuresDetail": "最近历史中有失败运行的自动化。", "automations.summary.paused": "暂停情况项", "automations.summary.pausedDetail": "目前存在于系统中但预计近期不会再发生活跃或执行任何活动事件调度的已排期计划项目任务状态说明。", "automations.summary.nextRun": "次运行时间阶段", @@ -987,9 +987,9 @@ registerPack("zh-CN", { "automations.status.needsReview": "需要审核", "automations.status.running": "运行中", "automations.summary.failures": "失败", - "automations.summary.failuresDetail": "可见历史中的失败运行。", + "automations.summary.failuresDetail": "最近历史中有失败运行的自动化。", "automations.summary.running": "正在运行", - "automations.summary.runningDetail": "当前正在进行的运行。", + "automations.summary.runningDetail": "有运行正在进行的自动化。", "automations.table.noRuns": "没有运行", "automations.table.recentRuns": "最近运行", "skills.cancel": "取消", From afa7f0c617687f9bb680cec583d86162c4209443 Mon Sep 17 00:00:00 2001 From: Robert Yan Date: Mon, 15 Jun 2026 15:15:51 +0000 Subject: [PATCH 15/15] Remove duplicate automation summary locale keys --- crates/ironclaw_webui_v2_static/static/js/i18n/ar.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/de.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/es.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/fr.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/hi.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/ja.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/ko.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/uk.js | 4 ---- crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js | 4 ---- 10 files changed, 40 deletions(-) diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js index fd859d071dc..9378c25fc9f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ar.js @@ -661,10 +661,6 @@ registerPack("ar", { "automations.summary.scheduledDetail": "عمليات الأتمتة المجدولة مرئية لهذا الوكيل.", "automations.summary.active": "نشطة", "automations.summary.activeDetail": "الجداول الزمنية الممكّنة في انتظار التشغيل التالي.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "الأتمتات التي لديها تشغيل قيد التقدم.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "الأتمتات التي لديها تشغيل فاشل في السجل الحديث.", "automations.summary.paused": "متوقف مؤقتًا", "automations.summary.pausedDetail": "لا يُتوقع تشغيل الجداول حاليًا.", "automations.summary.nextRun": "التشغيل التالي", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js index 28d6f9248b8..c1dc1d0439b 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/de.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/de.js @@ -661,10 +661,6 @@ registerPack("de", { "automations.summary.scheduledDetail": "Geplante Automatisierungen, die für diesen Agenten sichtbar sind.", "automations.summary.active": "Aktive", "automations.summary.activeDetail": "Aktivierte Zeitpläne, die auf ihre nächste Ausführung warten.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Automatisierungen mit einem aktiven Lauf.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Automatisierungen mit einem fehlgeschlagenen Lauf im aktuellen Verlauf.", "automations.summary.paused": "Angehalten", "automations.summary.pausedDetail": "Zeitpläne werden derzeit voraussichtlich nicht ausgeführt.", "automations.summary.nextRun": "Nächster Lauf", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js index 444def9ec6e..1f98a6b7ce9 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/es.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/es.js @@ -661,10 +661,6 @@ registerPack("es", { "automations.summary.scheduledDetail": "Automatizaciones programadas visibles para este agente.", "automations.summary.active": "Activo", "automations.summary.activeDetail": "Horarios habilitados esperando su próxima ejecución.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Automatizaciones con una ejecución en curso.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Automatizaciones con una ejecución fallida en el historial reciente.", "automations.summary.paused": "En pausa", "automations.summary.pausedDetail": "Actualmente no se espera que se ejecuten los horarios.", "automations.summary.nextRun": "Próxima ejecución", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js index f01ab59e19b..1fa2e62323f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/fr.js @@ -661,10 +661,6 @@ registerPack("fr", { "automations.summary.scheduledDetail": "Automatisations planifiées visibles par cet agent.", "automations.summary.active": "Actif", "automations.summary.activeDetail": "Planifications activées en attente de leur prochaine exécution.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Automatisations avec une exécution en cours.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Automatisations avec une exécution échouée dans l’historique récent.", "automations.summary.paused": "En pause", "automations.summary.pausedDetail": "Les programmes ne devraient pas s'exécuter actuellement.", "automations.summary.nextRun": "Prochaine exécution", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js index 4d7c07cbeed..259e7e0c426 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/hi.js @@ -661,10 +661,6 @@ registerPack("hi", { "automations.summary.scheduledDetail": "शेड्यूल किए गए ऑटोमेशन इस एजेंट को दिखाई देते हैं।", "automations.summary.active": "सक्रिय", "automations.summary.activeDetail": "सक्षम शेड्यूल अपने अगले रन की प्रतीक्षा कर रहे हैं।", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "वे ऑटोमेशन जिनका रन चल रहा है।", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "वे ऑटोमेशन जिनका हाल के इतिहास में रन विफल हुआ है।", "automations.summary.paused": "रोका गया", "automations.summary.pausedDetail": "शेड्यूल फिलहाल चलने की उम्मीद नहीं है।", "automations.summary.nextRun": "अगला रन", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js index ebccde01278..809f5511126 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ja.js @@ -661,10 +661,6 @@ registerPack("ja", { "automations.summary.scheduledDetail": "このエージェントに表示されるスケジュール済みの自動化。", "automations.summary.active": "アクティブ", "automations.summary.activeDetail": "次の実行を待機しているスケジュールを有効にしました。", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "実行中の実行があるオートメーション。", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "最近の履歴に失敗した実行があるオートメーション。", "automations.summary.paused": "一時停止", "automations.summary.pausedDetail": "スケジュールは現在実行される予定がありません。", "automations.summary.nextRun": "次の実行", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js index 66e9b5ada40..726d6dc4b95 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/ko.js @@ -661,10 +661,6 @@ registerPack("ko", { "automations.summary.scheduledDetail": "예약된 자동화가 이 에이전트에 표시됩니다.", "automations.summary.active": "활성", "automations.summary.activeDetail": "다음 실행을 기다리는 활성화된 일정입니다.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "진행 중인 실행이 있는 자동화입니다.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "최근 기록에 실패한 실행이 있는 자동화입니다.", "automations.summary.paused": "일시중지됨", "automations.summary.pausedDetail": "현재 실행될 것으로 예상되지 않는 일정입니다.", "automations.summary.nextRun": "다음 실행", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js index 392ee051a0f..111a485e65f 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/pt-BR.js @@ -661,10 +661,6 @@ registerPack("pt-BR", { "automations.summary.scheduledDetail": "Automações agendadas visíveis para este agente.", "automations.summary.active": "Ativo", "automations.summary.activeDetail": "Programações habilitadas aguardando sua próxima execução.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Automações com uma execução em andamento.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Automações com uma execução com falha no histórico recente.", "automations.summary.paused": "Pausado", "automations.summary.pausedDetail": "Programações que não estão previstas para serem executadas no momento.", "automations.summary.nextRun": "Próxima execução", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js index e2f92dff4e2..63229d5ba78 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/uk.js @@ -661,10 +661,6 @@ registerPack("uk", { "automations.summary.scheduledDetail": "Заплановані автоматизації, видимі для цього агента.", "automations.summary.active": "Активний", "automations.summary.activeDetail": "Увімкнені розклади, які очікують наступного запуску.", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "Автоматизації із запуском, що виконується.", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "Автоматизації з невдалим запуском у нещодавній історії.", "automations.summary.paused": "Призупинено", "automations.summary.pausedDetail": "Розклади наразі не запускаються.", "automations.summary.nextRun": "Наступний запуск", diff --git a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js index 40d7eeac42b..068e5c6ac8c 100644 --- a/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js +++ b/crates/ironclaw_webui_v2_static/static/js/i18n/zh-CN.js @@ -661,10 +661,6 @@ registerPack("zh-CN", { "automations.summary.scheduledDetail": "列出了系统当前为这位 AI 代理可见的所有正在进行的自动化项目与计划清单调度项。", "automations.summary.active": "可用计划项", "automations.summary.activeDetail": "目前所有已经启动运作在期待在最近运行时刻触发的自动化项目。", - "automations.summary.running": "Running now", - "automations.summary.runningDetail": "有运行正在进行的自动化。", - "automations.summary.failures": "Failures", - "automations.summary.failuresDetail": "最近历史中有失败运行的自动化。", "automations.summary.paused": "暂停情况项", "automations.summary.pausedDetail": "目前存在于系统中但预计近期不会再发生活跃或执行任何活动事件调度的已排期计划项目任务状态说明。", "automations.summary.nextRun": "次运行时间阶段",