Skip to content

feat(dashboard): add ad-hoc job invocation#36

Open
knutties wants to merge 1 commit into
mainfrom
claude/vigilant-cerf-f4fwpv
Open

feat(dashboard): add ad-hoc job invocation#36
knutties wants to merge 1 commit into
mainfrom
claude/vigilant-cerf-f4fwpv

Conversation

@knutties

@knutties knutties commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds the ability to invoke jobs on-demand from the workspace dashboard. Users can now trigger one-off executions of active jobs with optional input overrides and scheduling options.

Key Changes

  • Invoke Button: Added an "Invoke" button to the jobs table for active, non-internal jobs
  • InvokeJobForm Component: New modal form that allows users to:
    • Choose between immediate or scheduled execution
    • Optionally override the job's input with custom JSON
    • Specify a run time for scheduled invocations
  • Job Creation: Leverages the existing POST /v1/jobs API endpoint to create ad-hoc jobs with:
    • IMMEDIATE trigger for instant execution
    • DELAYED trigger for scheduled execution with auto-generated idempotency keys
  • Input Handling: Pre-fills the form with the source job's input and validates JSON before submission
  • Timestamp Normalization: Added normalize_run_at() utility to convert HTML5 datetime-local input to RFC 3339 UTC format

Implementation Details

  • Internal jobs (endpoint_type == "INTERNAL") are excluded from invocation as they are kronos-managed
  • Scheduled invocations generate stable idempotency keys (adhoc-{job_id}-{timestamp}) to prevent duplicate submissions
  • Form state resets when a new job is selected, with input pre-populated from the source job
  • Error handling for invalid JSON input and API failures
  • Modal closes and job list refreshes on successful invocation

https://claude.ai/code/session_017VK45VyxzgMyBFJ2LG2D4L

Summary by CodeRabbit

  • New Features
    • Added "Invoke Job" functionality to the Jobs tab. Users can now invoke active jobs immediately or schedule them for later execution. A modal form guides users through setting up invocations with optional scheduling and automatic request deduplication.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR adds one-off job invocation to the Jobs tab. Users can now select eligible jobs and invoke them immediately or schedule them for later execution. A new form component handles validation, JSON input parsing, datetime normalization, and API submission with idempotency deduplication.

Changes

Invoke Job UI Feature

Layer / File(s) Summary
Invoke button and state management
crates/dashboard/src/pages/workspace_detail.rs
JobsTable allocates state for job selection and modal visibility, computes eligibility (active jobs excluding INTERNAL endpoints), and renders a conditional Invoke button in job row actions.
InvokeJobForm component and datetime normalization
crates/dashboard/src/pages/workspace_detail.rs
InvokeJobForm supports IMMEDIATE and SCHEDULED modes, validates scheduled timing, normalizes datetime input to UTC format, derives idempotency keys, submits via API, and surfaces errors; helper function converts datetime-local values into UTC-suffixed API format.

Sequence Diagram

sequenceDiagram
  participant User
  participant InvokeJobForm
  participant API
  participant JobsTable
  User->>InvokeJobForm: Select mode (IMMEDIATE/SCHEDULED)
  InvokeJobForm->>InvokeJobForm: Validate run_at (if SCHEDULED)
  InvokeJobForm->>InvokeJobForm: Normalize run_at to UTC
  InvokeJobForm->>InvokeJobForm: Generate idempotency key
  InvokeJobForm->>API: create_job(endpoint, input, run_at, idempotency_key)
  API-->>InvokeJobForm: Success or Error
  InvokeJobForm->>JobsTable: Refresh job list
  InvokeJobForm->>User: Close modal
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A button to invoke with a click,
A form that handles schedules quick,
DateTime strings in UTC dressed,
Jobs running on demand—what zest! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'feat(dashboard): add ad-hoc job invocation' clearly and concisely describes the main change: adding the ability to invoke jobs on-demand from the dashboard.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/vigilant-cerf-f4fwpv

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/dashboard/src/pages/workspace_detail.rs (1)

2287-2296: 💤 Low value

Minor edge case: negative timezone offsets produce invalid output.

If a value with a negative offset (e.g., 2024-01-01T12:00-05:00) is pasted, the function produces 2024-01-01T12:00-05:00Z which is invalid RFC 3339. The contains('+') check catches positive offsets but not negative ones.

This is unlikely from normal datetime-local input usage (which never includes timezone info), but could occur if users paste timestamps.

🔧 Suggested fix to handle negative offsets
 fn normalize_run_at(s: &str) -> String {
     let s = s.trim();
-    if s.ends_with('Z') || s.contains('+') {
+    // Already has timezone info (Z, +HH:MM, or -HH:MM suffix)
+    if s.ends_with('Z') || s.contains('+') || s.rfind('-').map_or(false, |i| i > 10) {
         s.to_string()
     } else if s.len() == 16 {
         format!("{s}:00Z")
     } else {
         format!("{s}Z")
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/dashboard/src/pages/workspace_detail.rs` around lines 2287 - 2296,
normalize_run_at currently treats strings with '+' timezone offsets correctly
but misses negative offsets, producing invalid RFC3339 like "...-05:00Z"; update
normalize_run_at to detect timezone offsets with either '+' or '-' in the
timezone portion (e.g., match a timezone offset pattern like /[+-]\d{2}:\d{2}$/
or check for '+' or '-' in the final 6 characters) and treat those as already
having timezone info (return s.to_string()); keep the existing checks for
ends_with('Z') and the 16-char "no-seconds" case (format "{s}:00Z") otherwise
append "Z".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/dashboard/src/pages/workspace_detail.rs`:
- Around line 2287-2296: normalize_run_at currently treats strings with '+'
timezone offsets correctly but misses negative offsets, producing invalid
RFC3339 like "...-05:00Z"; update normalize_run_at to detect timezone offsets
with either '+' or '-' in the timezone portion (e.g., match a timezone offset
pattern like /[+-]\d{2}:\d{2}$/ or check for '+' or '-' in the final 6
characters) and treat those as already having timezone info (return
s.to_string()); keep the existing checks for ends_with('Z') and the 16-char
"no-seconds" case (format "{s}:00Z") otherwise append "Z".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f6ebb1d7-313e-4322-9a62-fd6134fc165d

📥 Commits

Reviewing files that changed from the base of the PR and between f44bf96 and f342fc5.

📒 Files selected for processing (1)
  • crates/dashboard/src/pages/workspace_detail.rs

Adds an "Invoke" action to each active job in the workspace dashboard,
letting users fire a one-off run of an existing job either immediately
or at a scheduled time.

The action reuses the existing POST /v1/jobs API: it builds a fresh
IMMEDIATE (or DELAYED, for scheduled) job from the selected job's
endpoint and input, with the input optionally overridden for the run.
Scheduled invokes derive a stable idempotency key from the source job
and target time so a double-submit is naturally deduped.

Internal (kronos-managed) jobs are excluded since the API rejects
user-created jobs against internal endpoints.
@knutties knutties changed the title Add ad-hoc job invocation feature to workspace dashboard feat(dashboard): add ad-hoc job invocation Jun 10, 2026
@knutties knutties force-pushed the claude/vigilant-cerf-f4fwpv branch from f342fc5 to 0a00bcc Compare June 10, 2026 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants