SSR modernization: ssr-form-migration skill + Transaction Edit plain-form/Selmer migration #14
@@ -39,14 +39,15 @@ Each migration appends one row (after-numbers), referencing the before in the di
|
||||
| Phase | Modal | LOC | Routes | no-cursor twins | faked roots | snapshot merges | OOB | mixed hx- | cookbook reused / added |
|
||||
|-------|-------|-----|--------|-----------------|-------------|-----------------|-----|-----------|-------------------------|
|
||||
| 1 (baseline) | Transaction Edit `transaction/edit.clj` | 1608 | ~12 | 1 | 2 | ~75 | 0 | 8 | — / seeded 7 entries |
|
||||
| 2 (in progress) | Transaction Edit `transaction/edit.clj` | 1555 | ~12 | **0** | 2 | ~75 | 0 | 8 | — / 0 |
|
||||
| 2 (in progress) | Transaction Edit `transaction/edit.clj` | 1570 | ~12 | **0** | **0** | ~75 | 0 | 8 | — / 0 |
|
||||
|
||||
> **Phase 2 progress (partial).** Achieved with parity held (swap spec 6/6 + Shared
|
||||
> Location green): deleted the dead `*-no-cursor*` twin (no-cursor 1→0, −53 LOC) and fixed
|
||||
> a real production bug (`:mode` leaking into the upsert → 500 on every advanced manual
|
||||
> save). **Still open** for this modal — and intentionally *not* forced under parity risk:
|
||||
> faked cursor roots (2 — de-faking needs the render-fn rewrite, see `gotchas.md`), the
|
||||
> snapshot round-trip (~75 — removed by the wizard→plain-form reclassification), Selmer
|
||||
> conversion of the render fns, and route collapse (~12 → ~3). These are the bulk of the
|
||||
> modal migration and require restructuring the modal's rendering wholesale rather than
|
||||
> isolated edits; track as the continuation of Phase 2.
|
||||
> Location green, full suite 31 pass / no regression): deleted the dead `*-no-cursor*`
|
||||
> twin (no-cursor 1→0), **de-faked the simple-mode cursor** (faked roots 2→0) by rendering
|
||||
> the row from explicit data with explicit field names (`account-field-name`) + explicit
|
||||
> error lookup — the render-fn rewrite the `with-field-default` shortcut couldn't do — and
|
||||
> fixed a real production bug (`:mode` leaking into the upsert → 500 on every advanced
|
||||
> manual save). **Still open** for this modal: the snapshot round-trip (~75 — removed by
|
||||
> the wizard→plain-form reclassification), Selmer conversion of the render fns, and route
|
||||
> collapse (~12 → ~3). These remain the bulk of the migration and need wholesale
|
||||
> restructuring of the modal's rendering; track as the continuation of Phase 2.
|
||||
|
||||
@@ -183,10 +183,32 @@
|
||||
(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
|
||||
client-id)))})])
|
||||
|
||||
(defn- account-field-name
|
||||
"Explicit form-field name for account row `index`, field `field` -- the same string
|
||||
the form cursor produces at path [:step-params :transaction/accounts index field]
|
||||
(via path->name2), without faking a deep cursor to get there."
|
||||
[index field]
|
||||
(str "step-params[transaction/accounts][" index "]["
|
||||
(if (keyword? field)
|
||||
(str (when (namespace field) (str (namespace field) "/")) (name field))
|
||||
field)
|
||||
"]"))
|
||||
|
||||
(defn- account-field-errors
|
||||
"Errors for account row `index`, field `field`, read straight from the form errors
|
||||
at the same path the cursor would walk -- avoids re-rooting a cursor to look them up."
|
||||
[index field]
|
||||
(when (bound? #'fc/*form-errors*)
|
||||
(get-in fc/*form-errors* [:step-params :transaction/accounts index field])))
|
||||
|
||||
(defn simple-mode-fields*
|
||||
"Renders the simple-mode account + location row and the toggle-to-advanced link.
|
||||
Must be called within a fc/start-form + fc/with-field :step-params context.
|
||||
Caller must establish Alpine x-data with simpleAccountId in scope."
|
||||
Caller must establish Alpine x-data with simpleAccountId in scope.
|
||||
|
||||
The single account row is rendered from explicit data with explicit field names
|
||||
(account-field-name 0 ...) rather than faking a synthetic MapCursor rooted at
|
||||
accounts[0] -- the row always lives at index 0 in simple mode."
|
||||
[request]
|
||||
(let [snapshot (-> request :multi-form-state :snapshot)
|
||||
step-params (-> request :multi-form-state :step-params)
|
||||
@@ -204,50 +226,41 @@
|
||||
(:transaction/amount snapshot)
|
||||
0.0))]
|
||||
[:div
|
||||
(fc/with-field :transaction/accounts
|
||||
(fc/with-cursor (let [cur fc/*current*]
|
||||
(if (sequential? @cur)
|
||||
(nth cur 0 nil)
|
||||
(auto_ap.cursor.MapCursor. {} (cursor/state cur) (conj (cursor/path cur) 0))))
|
||||
[:span
|
||||
(fc/with-field :db/id
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value row-id}))
|
||||
[:div.flex.gap-2.mt-2
|
||||
(fc/with-field :transaction-account/account
|
||||
(com/validated-field
|
||||
{:label "Account"
|
||||
:errors (fc/field-errors)}
|
||||
[:div.w-72
|
||||
(account-typeahead* {:value account-val
|
||||
:client-id client-id
|
||||
:name (fc/field-name)
|
||||
:x-model "simpleAccountId"})]))
|
||||
(fc/with-field :transaction-account/location
|
||||
;; Selecting the account only affects the valid Location options, so the
|
||||
;; change swaps just this cell -- nothing else needs to re-render.
|
||||
[:div {:id "simple-account-location"}
|
||||
(com/validated-field
|
||||
{:label "Location"
|
||||
:errors (fc/field-errors)
|
||||
:x-hx-val:account-id "simpleAccountId"
|
||||
:hx-vals (hx/json (cond-> {:name (fc/field-name)}
|
||||
client-id (assoc :client-id client-id)))
|
||||
:x-dispatch:changed "simpleAccountId"
|
||||
:hx-trigger "changed"
|
||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
||||
:hx-target "#simple-account-location"
|
||||
:hx-select "#simple-account-location"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-include "closest form"}
|
||||
(location-select*
|
||||
{:name (fc/field-name)
|
||||
:account-location (:account/location account-id)
|
||||
:client-locations (pull-attr (dc/db conn) :client/locations client-id)
|
||||
:value location-val}))])
|
||||
(fc/with-field :transaction-account/amount
|
||||
(com/hidden {:name (fc/field-name)
|
||||
:value total}))]]))
|
||||
[:span
|
||||
(com/hidden {:name (account-field-name 0 :db/id)
|
||||
:value row-id})
|
||||
[:div.flex.gap-2.mt-2
|
||||
(com/validated-field
|
||||
{:label "Account"
|
||||
:errors (account-field-errors 0 :transaction-account/account)}
|
||||
[:div.w-72
|
||||
(account-typeahead* {:value account-val
|
||||
:client-id client-id
|
||||
:name (account-field-name 0 :transaction-account/account)
|
||||
:x-model "simpleAccountId"})])
|
||||
;; Selecting the account only affects the valid Location options, so the
|
||||
;; change swaps just this cell -- nothing else needs to re-render.
|
||||
[:div {:id "simple-account-location"}
|
||||
(com/validated-field
|
||||
{:label "Location"
|
||||
:errors (account-field-errors 0 :transaction-account/location)
|
||||
:x-hx-val:account-id "simpleAccountId"
|
||||
:hx-vals (hx/json (cond-> {:name (account-field-name 0 :transaction-account/location)}
|
||||
client-id (assoc :client-id client-id)))
|
||||
:x-dispatch:changed "simpleAccountId"
|
||||
:hx-trigger "changed"
|
||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
||||
:hx-target "#simple-account-location"
|
||||
:hx-select "#simple-account-location"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-include "closest form"}
|
||||
(location-select*
|
||||
{:name (account-field-name 0 :transaction-account/location)
|
||||
:account-location (:account/location account-id)
|
||||
:client-locations (pull-attr (dc/db conn) :client/locations client-id)
|
||||
:value location-val}))]
|
||||
(com/hidden {:name (account-field-name 0 :transaction-account/amount)
|
||||
:value total})]]
|
||||
[:div.mt-1
|
||||
[:a.text-sm.text-blue-600.hover:underline.cursor-pointer
|
||||
{:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-toggle-mode)
|
||||
|
||||
Reference in New Issue
Block a user