Add a create-schedule button to the Schedules UI tab #119

Open
opened 2026-06-15 09:08:11 +00:00 by rawan · 3 comments
Member

Problem
The Library > Schedules tab can list, enable/disable, run-now, and delete schedules, but there is no way to create one from the UI. The empty state just says "Create via schedule.create".

Backend already supports it
The schedule.create RPC method exists and works (crates/hero_shrimp_server/src/rpc/methods/schedule.rs), and the CLI uses it. Only the web UI is missing the wiring.

Proposed fix
Add a "+ new schedule" button to SchedulesTab in crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx. It opens a small form with:

  • name
  • cadence / cron expression
  • kind (dropdown from the supported_kinds already returned by schedule.list: dream, pattern_synthesize, skills_reload, job_run)
  • description (optional)

On submit, call rpc("schedule.create", {...}), then refresh the list. Mirror the existing button/toast patterns in the same component.

Acceptance criteria

  • A create button/form is visible on the Schedules tab.
  • Submitting creates a schedule via schedule.create and the new entry appears in the list.
  • Invalid cron/cadence shows the backend error via the existing toast.
**Problem** The Library > Schedules tab can list, enable/disable, run-now, and delete schedules, but there is no way to create one from the UI. The empty state just says "Create via schedule.create". **Backend already supports it** The `schedule.create` RPC method exists and works (`crates/hero_shrimp_server/src/rpc/methods/schedule.rs`), and the CLI uses it. Only the web UI is missing the wiring. **Proposed fix** Add a "+ new schedule" button to `SchedulesTab` in `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx`. It opens a small form with: - name - cadence / cron expression - kind (dropdown from the supported_kinds already returned by schedule.list: dream, pattern_synthesize, skills_reload, job_run) - description (optional) On submit, call `rpc("schedule.create", {...})`, then refresh the list. Mirror the existing button/toast patterns in the same component. **Acceptance criteria** - [ ] A create button/form is visible on the Schedules tab. - [ ] Submitting creates a schedule via `schedule.create` and the new entry appears in the list. - [ ] Invalid cron/cadence shows the backend error via the existing toast.
rawan self-assigned this 2026-06-15 09:17:45 +00:00
Author
Member

Implementation Spec for Issue #119

Objective

Add a "+ new schedule" button and inline form to the SchedulesTab component so users can create schedules from the Library UI, calling the existing schedule.create RPC and refreshing the list on success. No backend changes required.

Requirements

  • A create button is visible on the Schedules tab (both when schedules exist and in the empty state).
  • Clicking it reveals a form with: name (required), cadence/cron expression (required), kind (dropdown sourced from supported_kinds returned by schedule.list), and description (optional).
  • On submit, call rpc("schedule.create", {...}), then refresh the list so the new entry appears.
  • Invalid cron/cadence surfaces the backend error through the existing toast pattern.
  • Match existing button/toast/styling conventions in the same component (btn-ghost, btn-primary, input-base, toast).

Files to Modify

  • crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx — modify the SchedulesTab function. Only file changed; no new files, no backend changes. No new imports needed (createSignal, Show, For, rpc, toast already imported).

Implementation Plan

Step 1: Add form state signals

Files: crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx
Inside SchedulesTab, add signals alongside existing ones: showCreate (bool), creating (bool), fName, fCadence, fKind, fDesc (strings). Initialize fKind to "job_run".
Dependencies: none

Step 2: Add a submit() handler

Files: crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx
Modeled on existing runNow/toggle handlers. Guard empty name/cadence with toast(..., "bad"). Call rpc("schedule.create", { name, cadence, kind, description }) using cadence as the param name (matches CLI). On success: success toast, reset fields, hide form, refresh(). On error: toast("create failed: " + (e?.message || e), "bad"). try/catch/finally with creating(false) in finally.
Dependencies: Step 1

Step 3: Add toggle button + inline form

Files: crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx
Add a "+ new schedule" btn-ghost button in the header summary line (so it shows in both populated and empty states). Add <Show when={showCreate()}> form with name/cadence/kind(select from supported() with fallback to the four known kinds)/description inputs and cancel/create footer buttons, mirroring CrewPage form styling but inline.
Dependencies: Steps 1, 2

Step 4: Verify build

Run the UI typecheck/build to confirm no type errors.
Dependencies: Steps 1-3

Acceptance Criteria

  • A "+ new schedule" button is visible on the Schedules tab in both populated and empty states.
  • Clicking it shows a form with name, cadence/cron, kind dropdown (from supported_kinds), and optional description.
  • Submitting valid input calls schedule.create and the new entry appears in the list after refresh.
  • An invalid cron/cadence shows the backend error message via a red toast and does not clear the form.
  • Styling matches existing patterns in SchedulesTab/CrewPage.

Notes

  • Exact schedule.create params (from schedule.rs): name (required), cadence (required; handler accepts cron/expression/cadence — use cadence to match the CLI), kind (optional, defaults to job_run), description (optional). Payload: rpc("schedule.create", { name, cadence, kind, description }).
  • supported_kinds: dream, pattern_synthesize, skills_reload, job_run. Already read into the supported() signal; fall back to this literal list if empty.
  • Cadence accepts natural language (daily 9am, every 5 minutes) or raw cron. Invalid input returns an error message propagated by rpc() and shown via toast.
  • SchedulesTab does not use the generic CatalogList; keep new state local to the function.
## Implementation Spec for Issue #119 ### Objective Add a "+ new schedule" button and inline form to the `SchedulesTab` component so users can create schedules from the Library UI, calling the existing `schedule.create` RPC and refreshing the list on success. No backend changes required. ### Requirements - A create button is visible on the Schedules tab (both when schedules exist and in the empty state). - Clicking it reveals a form with: name (required), cadence/cron expression (required), kind (dropdown sourced from `supported_kinds` returned by `schedule.list`), and description (optional). - On submit, call `rpc("schedule.create", {...})`, then refresh the list so the new entry appears. - Invalid cron/cadence surfaces the backend error through the existing toast pattern. - Match existing button/toast/styling conventions in the same component (`btn-ghost`, `btn-primary`, `input-base`, `toast`). ### Files to Modify - `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` — modify the `SchedulesTab` function. Only file changed; no new files, no backend changes. No new imports needed (`createSignal`, `Show`, `For`, `rpc`, `toast` already imported). ### Implementation Plan #### Step 1: Add form state signals Files: `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` Inside `SchedulesTab`, add signals alongside existing ones: `showCreate` (bool), `creating` (bool), `fName`, `fCadence`, `fKind`, `fDesc` (strings). Initialize `fKind` to `"job_run"`. Dependencies: none #### Step 2: Add a submit() handler Files: `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` Modeled on existing `runNow`/`toggle` handlers. Guard empty name/cadence with `toast(..., "bad")`. Call `rpc("schedule.create", { name, cadence, kind, description })` using `cadence` as the param name (matches CLI). On success: success toast, reset fields, hide form, `refresh()`. On error: `toast("create failed: " + (e?.message || e), "bad")`. try/catch/finally with `creating(false)` in finally. Dependencies: Step 1 #### Step 3: Add toggle button + inline form Files: `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` Add a "+ new schedule" `btn-ghost` button in the header summary line (so it shows in both populated and empty states). Add `<Show when={showCreate()}>` form with name/cadence/kind(select from `supported()` with fallback to the four known kinds)/description inputs and cancel/create footer buttons, mirroring CrewPage form styling but inline. Dependencies: Steps 1, 2 #### Step 4: Verify build Run the UI typecheck/build to confirm no type errors. Dependencies: Steps 1-3 ### Acceptance Criteria - [ ] A "+ new schedule" button is visible on the Schedules tab in both populated and empty states. - [ ] Clicking it shows a form with name, cadence/cron, kind dropdown (from `supported_kinds`), and optional description. - [ ] Submitting valid input calls `schedule.create` and the new entry appears in the list after refresh. - [ ] An invalid cron/cadence shows the backend error message via a red toast and does not clear the form. - [ ] Styling matches existing patterns in `SchedulesTab`/`CrewPage`. ### Notes - Exact `schedule.create` params (from `schedule.rs`): `name` (required), cadence (required; handler accepts `cron`/`expression`/`cadence` — use `cadence` to match the CLI), `kind` (optional, defaults to `job_run`), `description` (optional). Payload: `rpc("schedule.create", { name, cadence, kind, description })`. - `supported_kinds`: `dream`, `pattern_synthesize`, `skills_reload`, `job_run`. Already read into the `supported()` signal; fall back to this literal list if empty. - Cadence accepts natural language (`daily 9am`, `every 5 minutes`) or raw cron. Invalid input returns an error message propagated by `rpc()` and shown via toast. - `SchedulesTab` does not use the generic `CatalogList`; keep new state local to the function.
Author
Member

Test Results

  • Scope: web UI typecheck (only LibraryPage.tsx changed)
  • LibraryPage.tsx type errors: 0
  • Pre-existing unrelated errors: 14 total, all in other files (ChatActivity, CostBadge, DiffViewer, HeroWelcome) — none introduced by this change

Details

Verified that the only modified file is crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx (no Rust files changed), so cargo test was not run.

Ran npx tsc --noEmit in crates/hero_shrimp_web/ui. Filtering for the changed file (grep -i librarypage) returns no matches, confirming LibraryPage.tsx compiles cleanly with no new type errors.

The 14 remaining errors are pre-existing and unrelated to this change:

src/components/ChatActivity.tsx(60,73): error TS2554: Expected 0 arguments, but got 1.
src/components/CostBadge.tsx(96,79): error TS2531: Object is possibly 'null'.
src/components/CostBadge.tsx(102,53): error TS2531: Object is possibly 'null'.
src/components/CostBadge.tsx(109,53): error TS2531: Object is possibly 'null'.
src/components/DiffViewer.tsx(74,47): error TS2345: Argument of type 'string | null' is not assignable to parameter of type 'string'.
src/components/HeroWelcome.tsx(104,101): error TS2322: Type '"1"' is not assignable to type 'number | "indefinite" | undefined'.
src/components/HeroWelcome.tsx(105,110): error TS2322: Type '"1"' is not assignable to type 'number | "indefinite" | undefined'.
src/components/HeroWelcome.tsx(174,39): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'.
src/components/HeroWelcome.tsx(174,52): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'?
src/components/HeroWelcome.tsx(175,39): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'.
src/components/HeroWelcome.tsx(175,52): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'?
src/components/HeroWelcome.tsx(182,28): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'.
src/components/HeroWelcome.tsx(182,41): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'?
src/components/HeroWelcome.tsx(183,29): error TS2339: Property 'messages' does not exist on type 'ConvSummary'.

Conclusion: PASS for the scope of this change — LibraryPage.tsx introduces no new type errors.

## Test Results - Scope: web UI typecheck (only `LibraryPage.tsx` changed) - LibraryPage.tsx type errors: 0 - Pre-existing unrelated errors: 14 total, all in other files (ChatActivity, CostBadge, DiffViewer, HeroWelcome) — none introduced by this change ### Details Verified that the only modified file is `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` (no Rust files changed), so `cargo test` was not run. Ran `npx tsc --noEmit` in `crates/hero_shrimp_web/ui`. Filtering for the changed file (`grep -i librarypage`) returns no matches, confirming `LibraryPage.tsx` compiles cleanly with no new type errors. The 14 remaining errors are pre-existing and unrelated to this change: ``` src/components/ChatActivity.tsx(60,73): error TS2554: Expected 0 arguments, but got 1. src/components/CostBadge.tsx(96,79): error TS2531: Object is possibly 'null'. src/components/CostBadge.tsx(102,53): error TS2531: Object is possibly 'null'. src/components/CostBadge.tsx(109,53): error TS2531: Object is possibly 'null'. src/components/DiffViewer.tsx(74,47): error TS2345: Argument of type 'string | null' is not assignable to parameter of type 'string'. src/components/HeroWelcome.tsx(104,101): error TS2322: Type '"1"' is not assignable to type 'number | "indefinite" | undefined'. src/components/HeroWelcome.tsx(105,110): error TS2322: Type '"1"' is not assignable to type 'number | "indefinite" | undefined'. src/components/HeroWelcome.tsx(174,39): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'. src/components/HeroWelcome.tsx(174,52): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'? src/components/HeroWelcome.tsx(175,39): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'. src/components/HeroWelcome.tsx(175,52): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'? src/components/HeroWelcome.tsx(182,28): error TS2339: Property 'last_at' does not exist on type 'ConvSummary'. src/components/HeroWelcome.tsx(182,41): error TS2551: Property 'updated_at' does not exist on type 'ConvSummary'. Did you mean 'updatedAt'? src/components/HeroWelcome.tsx(183,29): error TS2339: Property 'messages' does not exist on type 'ConvSummary'. ``` Conclusion: PASS for the scope of this change — `LibraryPage.tsx` introduces no new type errors.
Author
Member

Implementation Summary

Added a create-schedule UI to the Library > Schedules tab. No backend changes were needed; the UI now wires up the existing schedule.create RPC.

Changes

  • crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx (SchedulesTab):
    • Added a "+ new schedule" toggle button in the tab header, visible in both populated and empty states.
    • Added an inline create form (card) with: name (required), cadence/cron (required), kind (dropdown from supported_kinds, falling back to dream / pattern_synthesize / skills_reload / job_run), and optional description.
    • Added a submit() handler that calls rpc("schedule.create", { name, cadence, kind, description }) (using the cadence param to match the CLI), shows a success toast, resets the form, and refreshes the list.
    • On error, surfaces the backend message via the existing red toast and keeps the form populated.

Acceptance criteria

  • A create button/form is visible on the Schedules tab.
  • Submitting creates a schedule via schedule.create and the new entry appears in the list (via refresh).
  • Invalid cron/cadence shows the backend error via the existing toast.

Tests

  • Web UI typecheck (tsc --noEmit): 0 errors in LibraryPage.tsx. The only remaining errors are pre-existing and in unrelated files. No Rust files changed.
## Implementation Summary Added a create-schedule UI to the Library > Schedules tab. No backend changes were needed; the UI now wires up the existing `schedule.create` RPC. ### Changes - `crates/hero_shrimp_web/ui/src/components/LibraryPage.tsx` (SchedulesTab): - Added a "+ new schedule" toggle button in the tab header, visible in both populated and empty states. - Added an inline create form (card) with: name (required), cadence/cron (required), kind (dropdown from `supported_kinds`, falling back to dream / pattern_synthesize / skills_reload / job_run), and optional description. - Added a `submit()` handler that calls `rpc("schedule.create", { name, cadence, kind, description })` (using the `cadence` param to match the CLI), shows a success toast, resets the form, and refreshes the list. - On error, surfaces the backend message via the existing red toast and keeps the form populated. ### Acceptance criteria - [x] A create button/form is visible on the Schedules tab. - [x] Submitting creates a schedule via `schedule.create` and the new entry appears in the list (via refresh). - [x] Invalid cron/cadence shows the backend error via the existing toast. ### Tests - Web UI typecheck (`tsc --noEmit`): 0 errors in `LibraryPage.tsx`. The only remaining errors are pre-existing and in unrelated files. No Rust files changed.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_shrimp#119
No description provided.