fix(ssr): bulk-edit empty-selection 500 + modal-footer EDN leak
- BUG D: clicking "Bulk Edit" with no invoices selected 500'd. selected->ids
returns nil with no selection, and all-ids-not-locked fed that nil into a
Datomic `:in $ [?i ...]` query ("Unable to find data source"). Guard the body
with (when (seq all-ids) ...) so an empty selection yields [] and the modal
opens cleanly. Verified live: no "Oh, drat" toast, no 500.
- BUG B: modal-footer- called (hx/alpine-appear ...) twice; the 2nd return value
(an attribute map) landed in child position and rendered as literal EDN
({:x-show ...}) in the red error banner whenever unexpectedError flipped true.
Delete the duplicate. Verified: rendered HTML now has one alpine-appear and no
EDN-text child. (Pre-existing defect, also present on master.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# SSR Modal Regression Fixes — QA Findings & Resumable Task List
|
# SSR Modal Regression Fixes — QA Findings & Resumable Task List
|
||||||
|
|
||||||
> **Status:** BUG A, BUG C, BUG E/F, and the CSS size root cause are **FIXED + verified live**
|
> **Status:** BUG A, BUG C, BUG D, BUG B, BUG E/F, and the CSS size root cause are
|
||||||
> (2026-06-27). Remaining: animations (§3), BUG D, BUG B. Resume from §4.
|
> **FIXED + verified** (2026-06-27). Remaining: modal step animations (§3). Resume from §4/§3.
|
||||||
> **Owner:** Bryce
|
> **Owner:** Bryce
|
||||||
> **Branch:** `integreat-execute-refactor`
|
> **Branch:** `integreat-execute-refactor`
|
||||||
> **Date:** 2026-06-27
|
> **Date:** 2026-06-27
|
||||||
@@ -166,9 +166,13 @@ match.** (HIGH severity — breaks the flagship modal's core swap doctrine.)
|
|||||||
|
|
||||||
### P2 — robustness / cosmetic
|
### P2 — robustness / cosmetic
|
||||||
|
|
||||||
**BUG D — Invoice Bulk Edit with no selection → 500** (global "Oh, drat!" toast). Works fine with
|
**BUG D — Invoice Bulk Edit with no selection → 500** — **DONE & verified live.** With no
|
||||||
a selection. Should no-op or show a friendly "select invoices first" message.
|
selection, `selected->ids` returns `nil`, which `all-ids-not-locked` fed straight into a Datomic
|
||||||
- File: `src/clj/auto_ap/ssr/invoices.clj` (bulk-edit open handler).
|
`:in $ [?i ...]` query → "Unable to find data source" exception → global "Oh, drat!" toast.
|
||||||
|
- File: `src/clj/auto_ap/ssr/invoices.clj` — wrapped `all-ids-not-locked`'s body in
|
||||||
|
`(when (seq all-ids) ...)`, so an empty/nil selection yields `[]` and the modal opens cleanly
|
||||||
|
(also protects every other caller). Live: Bulk Edit with nothing selected now opens the modal,
|
||||||
|
no toast, no 500.
|
||||||
|
|
||||||
**BUG B — Footer leaks a raw Hiccup attr-map as text** in the red "unexpected error" banner
|
**BUG B — Footer leaks a raw Hiccup attr-map as text** in the red "unexpected error" banner
|
||||||
(`{:x-show "unexpectedError", ...}`). **Pre-existing in master** (NOT a migration regression), but
|
(`{:x-show "unexpectedError", ...}`). **Pre-existing in master** (NOT a migration regression), but
|
||||||
@@ -176,7 +180,9 @@ visible whenever `unexpectedError` flips true (e.g. it showed during BUG A). Cau
|
|||||||
calls `(hx/alpine-appear {...})` **twice** — the 2nd return value lands in child position and
|
calls `(hx/alpine-appear {...})` **twice** — the 2nd return value lands in child position and
|
||||||
renders as literal EDN.
|
renders as literal EDN.
|
||||||
- File: `src/clj/auto_ap/ssr/components/dialog.clj` ~line 59.
|
- File: `src/clj/auto_ap/ssr/components/dialog.clj` ~line 59.
|
||||||
- **FIX:** delete the duplicate `(hx/alpine-appear ...)` line in `modal-footer-`.
|
- **FIX — DONE & verified:** deleted the duplicate `(hx/alpine-appear ...)` line in `modal-footer-`.
|
||||||
|
Rendering the footer to HTML now shows a single `alpine-appear` (the legit attrs) and no literal
|
||||||
|
`{:x-show ...}` text child.
|
||||||
|
|
||||||
**Cosmetic — over-tall empty modals.** Invoice/Transaction Bulk Edit and similar use fixed
|
**Cosmetic — over-tall empty modals.** Invoice/Transaction Bulk Edit and similar use fixed
|
||||||
`md:h-[650px]`; with little content they show a large empty lower region. Consider letting height
|
`md:h-[650px]`; with little content they show a large empty lower region. Consider letting height
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
(defn modal-footer- [params & children]
|
(defn modal-footer- [params & children]
|
||||||
[:div {:class "p-4 border-t"}
|
[:div {:class "p-4 border-t"}
|
||||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex
|
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex
|
||||||
(hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
|
||||||
(hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
(hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
||||||
[:span {:class "w-2 h-2 bg-red-500 rounded-full"}]
|
[:span {:class "w-2 h-2 bg-red-500 rounded-full"}]
|
||||||
[:span.px-2.py-0.5 "An unexpected error has occured. Integreat staff have been notified."]]
|
[:span.px-2.py-0.5 "An unexpected error has occured. Integreat staff have been notified."]]
|
||||||
|
|||||||
@@ -1486,6 +1486,7 @@
|
|||||||
|
|
||||||
;; TODO clientize
|
;; TODO clientize
|
||||||
(defn all-ids-not-locked [all-ids]
|
(defn all-ids-not-locked [all-ids]
|
||||||
|
(when (seq all-ids)
|
||||||
(->> all-ids
|
(->> all-ids
|
||||||
(dc/q '[:find ?i
|
(dc/q '[:find ?i
|
||||||
:in $ [?i ...]
|
:in $ [?i ...]
|
||||||
@@ -1495,7 +1496,7 @@
|
|||||||
[?i :invoice/date ?d]
|
[?i :invoice/date ?d]
|
||||||
[(>= ?d ?lu)]]
|
[(>= ?d ?lu)]]
|
||||||
(dc/db conn))
|
(dc/db conn))
|
||||||
(map first)))
|
(map first))))
|
||||||
(defn- bulk-edit-account-row*
|
(defn- bulk-edit-account-row*
|
||||||
"One expense-account row (no cursor). The location cell swaps just itself
|
"One expense-account row (no cursor). The location cell swaps just itself
|
||||||
(#account-location-<index>, Rule 2); the percentage swaps only #expense-totals
|
(#account-location-<index>, Rule 2); the percentage swaps only #expense-totals
|
||||||
|
|||||||
Reference in New Issue
Block a user