Skip to content

feat(history): inline Cancel button for pending purchase rows #46

@cristim

Description

@cristim

Summary

Purchase History now shows pending approvals with the approver email (32f9e4ffc, b44283746), but there's no UI path to cancel a pending execution from History. The approval-link cancel endpoint is gated by a one-time email token, and the plan-backed cancel endpoints reject plan-less executions.

Captured in: known_issues/30_history_pending_cancel_ui.md

Current behaviour

  1. User creates an ad-hoc execution from Recommendations (→ plan_id = "").
  2. Approval email sends (or fails and the row lands in failed — see related refactor(credentials): drop legacy cert-based Azure WIF path #31).
  3. User wants to cancel from the CUDly dashboard rather than dig through inbox.
  4. No Cancel button on the pending row. Only the email token can cancel.
  5. Planned-purchase pause/resume/delete endpoints reject plan-less executions: execution not found or execution cannot transition.

Steps to reproduce

  1. From Recommendations, click Execute on any row to create a pending execution.
  2. Open Purchase History. Row shows Pending badge + approver email.
  3. Look for a Cancel action on the pending row — none.
  4. curl -X POST /api/purchases/planned/{id}/delete with session auth → execution cannot transition (the endpoint expects plan_id != "").

Expected behaviour

A session-authed Cancel button on pending rows that calls a cancel endpoint not gated by the email token.

Proposed fix

Option A — add a new session-authed cancel endpoint (or broaden cancelPurchase to accept either token= or an authenticated admin session), then wire a Cancel button in frontend/src/history.ts:renderHistoryList:

  • Shows only for status=="pending" or status=="notified".
  • Gated by the same permission as Purchase History rendering.
  • On click: confirmDialog, POST to the new endpoint, reload history.

Why not fixed yet

The token-authed path is secure by design — the email token proves intent. A session-authed bypass widens blast radius and needs an RBAC review: does the existing delete purchases verb cover this, or do we add cancel:own_executions?

References

  • Commits: 32f9e4ffc (pending in history), b44283746 (failed + expired states).
  • Files: internal/api/handler_purchases.go::cancelPurchase, frontend/src/history.ts::renderHistoryList.
  • Known-issue doc: known_issues/30_history_pending_cancel_ui.md.

Severity

Medium — users can still cancel via email, but the dashboard showing state without an action feels broken.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions