Approval withdrawal: warning + edit-event-instead path #83
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
m's report (2026-05-25 13:08)
Scope
Currently: withdrawing an approval request silently deletes the underlying event. m wants:
What to do
frontend/src/client/approvals.tsor similarinternal/handlers/approvals.goapproval-withdrawn-via-editvsapproval-withdrawn-and-deleted.Files most likely touched
frontend/src/client/approvals.tsfrontend/src/client/i18n.ts— confirm dialog copyinternal/handlers/approvals.go— split the destructive path from the edit-instead path; audit-log distinctioninternal/services/approval_service.go(if exists)Hard rules
go build ./... && go test ./internal/... && cd frontend && bun run buildclean.mai/<worker>/approval-withdraw-warning.Out of scope
Reporting
mai report completedwith branch + SHAs + the UX path: trigger withdraw → see modal → pick "Edit event" → event editor opens → save → confirm approval request is alive with new state; alternative: pick destructive → confirm event + request deleted; cancel: nothing changes.Done — branch
mai/artemis/gitster-approval-withdrawCommit:
72b6414New shared modal, new backend endpoint, both deadline + appointment detail pages wired. No schema migration needed — re-uses the existing counter-allowlist (
buildCounterSetClauses) fromSuggestChanges(t-paliad-216).UX paths
Trigger. Click "Genehmigungsanfrage zurückziehen" on a pending deadline / appointment you authored.
Modal copy (adapts to lifecycle):
"Wenn Sie die Anfrage zurückziehen, wird die Frist/der Termin gelöscht.""Ihre vorgeschlagenen Änderungen werden verworfen — der Eintrag kehrt in den Zustand vor Ihrer Bearbeitung zurück.""Wenn Sie die Löschanfrage zurückziehen, bleibt der Eintrag bestehen."Three paths:
POST /api/approval-requests/{id}/edit-entitywith the new field payload. The approval request stays pending; the entity row +approval_request.payloadare synced to the new values. Audit row:<entity>_approval_edited_by_requester(new event type, distinct from the original*_requestedrow)./revokeendpoint runs unchanged. For CREATE that hard-deletes the entity (the surprise m flagged); for UPDATE/COMPLETE it reverts topre_image; for DELETE it cancels the delete request. Audit row:<entity>_approval_revoked.Audit distinction (per spec)
Two paths emit different
project_events.event_typerows so the Verlauf reads correctly:<entity>_approval_edited_by_requester(new)<entity>_approval_revoked(existing)applyRevert(= DELETE for CREATE)Backend
ApprovalService.EditPendingEntity(ctx, requestID, callerID, fields)— new service method.requested_byAND status MUST bepending. ReturnsErrNotApprover/ErrRequestNotPendingotherwise.buildCounterSetClauses(the wider counter-allowlist fromSuggestChanges) — every editable field on the entity, not just the date-bearing approval triggers. Unknown keys silently dropped. Empty-fields / title-cleared →ErrSuggestionRequiresChange.applyEntityUpdate(incl.event_type_idsjunction rewrite for deadlines).approval_requests.payloadmerged with new fields (jsonb deep-merge usingmaps.Copy).project_eventsrow inserted with new*_approval_edited_by_requesterevent type + metadata{edited_fields: [...]}.POST /api/approval-requests/{id}/edit-entity— new handler ininternal/handlers/approvals.go.{"fields": {<entity-shape>}}mapApprovalError: 400suggestion_requires_change, 403not_authorized, 404, 409request_not_pending.Frontend
frontend/src/client/components/withdraw-warning-modal.ts— new shared modal built onopenModal()primitive (t-paliad-217 Slice A). Adapts copy by lifecycle, exposes 3 paths via destructive-button-in-body + primary CTA in footer.frontend/src/client/deadlines-detail.ts—initWithdrawrewrite; Save handler branches onpendingEditModeto the new endpoint.frontend/src/client/appointments-detail.ts— same pattern; appointment edit form already lives inline (always visible, frozen during pending) sopendingEditModeunfreezes it.approvals.withdraw.*..withdraw-warning-body+.withdraw-warning-{intro,sub,destructive-row,destructive-btn}.Build hygiene
go build ./...cleango vet ./...cleango test ./internal/...clean (no new tests — the new path uses the SQL infrastructure that already has live-DB coverage viaSuggestChanges)bun run buildclean (2807 keys, +14 new, scan clean)Out of scope (intentionally, per spec)
Ready for maria's review + merge. Awaiting head merge gate.