Skip to content

One-click completion with undo, and skip-with-reason #4

Description

@os-warren

The interaction the whole product rests on. If ticking a task costs more than a second, the list stops being maintained and every metric downstream becomes a report on a dataset nobody keeps.

Blocked-by: #3 (the hook does the stamping; these actions only flip status).

Files you own

  • src/actions/task.actions.ts (new) — action metadata, added to dulyActions in src/actions/index.ts
  • src/actions/task.handlers.ts (new)
  • src/actions/register-handlers.ts — add your registerTaskActionHandlers(ql) call inside the existing function
  • test/task-actions.test.ts (new)

Handlers are runtime code wired through register-handlers.ts, which the config already imports. An action whose handler is unregistered renders, is clickable, and fails at call time — there is no author-time gate for it.

Actions

duly_task_complete — row action, primary.

  • Sets status = 'done'. That is the entire payload. completed_at is the hook's job (Task lifecycle hook — completed_at and last_update_at stamping #3); do not send it.
  • No modal. No confirmation dialog. No required note, attachment or percentage.
  • Visible when record.status is open or in_progress. CEL predicates reference record.<field> — a bare status evaluates to null and hides the action on every record, and pnpm validate now rejects it.

duly_task_undo — row action, appears on a just-completed row.

  • Sets status = 'in_progress'; the hook clears completed_at.
  • Undo replaces confirmation. This is the design: an accidental tick costs one click to reverse, so the tick itself needs no ceremony.

duly_task_skip — row action, secondary.

  • Sets status = 'skipped' and requires skip_reason. This is the one place a modal is correct, because the object's skip_needs_reason validation will reject the write without it.
  • Skipping is a legitimate outcome — "the plant was down, there was nothing to return". Forcing that answer to be recorded as done or left open corrupts the data either way.

Also expose complete and skip as bulk actions on the list views: a week's worth of ticks in one gesture is the difference between a Monday-morning habit and a chore.

Do not

  • add a completion percentage, a required evidence upload, or a "are you sure?" step
  • make attachments a condition of completing anything — duly_task.enable.files is on so people can attach, never so they must
  • write completed_at or last_update_at from a handler

Acceptance

  • completing sends { status: 'done' } and nothing else; the record comes back with completed_at set
  • undo returns the record to in_progress with completed_at null
  • skip without a reason is rejected by validation with the object's message
  • bulk-completing 20 selected tasks issues one write path and leaves all 20 stamped
  • action predicates are all record.<field>-qualified and pnpm validate passes

Gates

pnpm validate && pnpm typecheck && pnpm test && pnpm build.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions