Files
sim/apps
Waleed 7a33508af1 feat(scheduled-tasks): pause/resume, mutation toasts, submit guards, empty state (#5044)
* feat(scheduled-tasks): pause/resume, mutation toasts, submit guards, empty state

- Toasts on every job mutation (create/update/delete/exclude/pause/resume) so failures are never silent
- TaskModal stays open until the save persists; submit disabled in-flight to block double-submit
- Pause/Resume recurring tasks via the context menu; paused occurrences render dimmed so they stay resumable
- First-run empty state with a create CTA when the workspace has no tasks

* fix(scheduled-tasks): return edit-modal save promise so the modal awaits persistence

The edit TaskModal's onSubmit called updateTask without returning its promise,
so the await resolved immediately — the modal closed before the save finished,
failed edits didn't stay open, and a rejected mutateAsync went unhandled. Return
the promise so the await tracks the real mutation (matching the create path).

* refactor(scheduled-tasks): explicit return in edit-modal onSubmit for clarity

* fix(scheduled-tasks): optimistic create insert + always-reset submit guard

- Seed the created job into the workspace-list cache on success so the new task
  renders instantly and the first-run empty state never flashes between the
  success toast and the list refetch; onSettled still reconciles authoritatively.
- Reset the modal's submitting flag in a finally so the submit button can never
  stick disabled if the modal is kept open.

* revert(scheduled-tasks): drop first-run empty state

Remove the empty-state prompt and its supporting hasTasks flag; with the empty
state gone, also revert the create optimistic-insert (its only purpose was
avoiding the empty-state flash) back to plain toast + list invalidation.

* fix(scheduled-tasks): lock modal dismiss while a save is in flight

Cancel, the header X, Escape, and overlay click all route through one guarded
onOpenChange that no-ops while submitting, and the footer Cancel is disabled
(cancelDisabled) — so an in-progress create/edit can't be abandoned mid-save and
lose its draft. submitting moves up to TaskModal so the guard can read it.

* fix(settings): align general appearance dropdowns to a uniform width

Theme/Snap-to-grid (ChipSelect) hugged their content (~90px) while Timezone
(ChipCombobox) was pinned to 260px, so the three read as a ragged column. Give
all three a shared 240px trigger via fullWidth + a common width wrapper so they
align as one column; menus match their triggers. No behavioral change — timezone
keeps search, options and handlers are untouched.

* docs(scheduled-tasks): document why the dismiss guard doesn't block the success-close

* fix(scheduled-tasks): disable Delete while an edit save is in flight

Delete bypasses the modal's dismiss guard (it closes via closeTask, not
onOpenChange), so a click mid-save could run a delete against the same task as
the in-flight update. Disable it while submitting, matching Cancel.

* refactor(scheduled-tasks): TSDoc over inline comments in task modal

Move the Delete-lock rationale to a TSDoc block on secondaryActions, and
restructure handleSubmit to a boolean persist result so the failure path is
self-evident — removing the inline comments and the empty catch block.

* fix(scheduled-tasks): gate submit on a synchronous ref to fully block double-submit

The submitting state flag only reflects after a re-render, so two same-tick
invocations (Enter racing the click) could both pass a state-based guard and fire
two mutations. A submittingRef flips synchronously, so the second invocation is
rejected before it can submit again; the state still drives the button/cancel UI.
2026-06-14 11:01:28 -07:00
..