* fix(office): disable create button until project + title set
Office "New Task" dialog let user submit without picking a project, which
hit the backend isOfficeRequest() heuristic and failed validation with
"workflow_id is required for non-ephemeral tasks". Disable the button
until both title and project are set and surface the missing requirement
in a tooltip instead of a backend error toast.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(office): guard handleCreate on projectId + cover with tests
PR review feedback (claude, cubic): the handleCreate path only checked
title and workspace, so a keyboard shortcut or future programmatic
caller could still produce a request with no project and reproduce the
backend 'workflow_id is required' error. Guard it there too, and add
unit tests that pin the disabled-state + reason behavior of the
extracted CreateTaskButton. aria-label on the trigger wrapper surfaces
the reason to assistive tech even when the tooltip is closed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(office): cover submitting state for CreateTaskButton
PR review feedback (claude): the disabled check had three branches
(missing title / missing project / submitting); only two were
tested. Add the submitting case so a regression that drops it from the
disabled expression is caught.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix(office): unbreak new-task dialog "Create Task" button
Office task creation silently failed: the button click sent a malformed
payload, the backend dropped it, and no toast surfaced because Sonner's
Toaster was never mounted. Three causes, all fixed here.
- web: send priority as a string id ("medium") instead of a number; the
backend Priority field is a string and ShouldBindJSON was rejecting
the body with "invalid payload".
- web/backend: add project_id as a top-level field on createTask. The
dialog was burying it inside metadata where the HTTP handler never
read it, so isOfficeRequest() returned false and validation tripped
on "workflow_id is required for non-ephemeral tasks".
- web: mount the Sonner Toaster in the root layout. All sonner-based
toasts across the app (not just this dialog) were silently dropped
because no Toaster was rendered anywhere.
* fix(office): address PR #976 review feedback
- new-task-dialog: drop unreachable `|| undefined` guard on priority
(EMPTY_DRAFT.priority is always "medium" and the picker only sets
non-empty strings, so the fallback can never fire).
- layout: move sonner Toaster to top-right so it stops visually
overlapping with the custom ToastProvider's bottom-right stack.
- task_http_handlers_test: add regression test asserting that a
create-task body with project_id (and no workflow_id) reaches the
office code path and the office workflow auto-resolves. Guards the
exact wiring that caused the original silent failure.
---------
Co-authored-by: Kandev Agent <agent@kandev.dev>