Whole-form hx-select swaps with zero out-of-band swaps
Replace the section-swap + OOB approach with uniform whole-form swaps, eliminating both out-of-band swaps: - Discrete edits (vendor, account, location, mode, add/remove row) now swap all of #wizard-form via hx-select. The active action/tab already round-trips (:action is in edit-form-schema and the tab x-data inits from it), so a whole-form swap re-creates the tab state from the server value and the active tab is preserved -- no #wizard-snapshot OOB needed, since the snapshot hidden field rides along inside the form. - Move the totals into their own <tbody id="account-totals"> (new optional :footer-tbody param on data-grid-) so the amount field updates them with a plain targeted swap instead of an OOB swap of #total,#balance. The totals tbody is a sibling of the input rows, so the amount input is never replaced. - Memo unchanged (hx-swap=none). Net: 0 hx-select-oob, 0 morph. The focus invariant is unchanged -- the typed field is never inside a region it swaps. Tab clicks stay Alpine (instant); only the action value round-trips. Revert the now-unneeded #wizard-snapshot id. Full e2e suite: 27 passed / 2 failed (same pre-existing, unrelated failures). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,17 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
// These tests cover the "post the whole form, swap back only what changed"
|
// These tests cover the "post the whole form, hx-select what to swap" behaviour
|
||||||
// behaviour on the transaction edit page. Each edit hits its own route and the
|
// on the transaction edit page. Each edit hits its own route, the server
|
||||||
// server re-renders the entire form, but the client swaps back a targeted slice:
|
// re-renders the entire form, and the client selects what to swap back -- with
|
||||||
|
// no out-of-band swaps and no morph extension:
|
||||||
// - discrete changes (vendor, account, location, mode, add/remove row) swap
|
// - discrete changes (vendor, account, location, mode, add/remove row) swap
|
||||||
// the #manual-coding-section fragment via hx-select (+ an OOB refresh of the
|
// all of #wizard-form (the active action/tab round-trips through the form,
|
||||||
// #wizard-snapshot hidden field so the round-tripped wizard state stays in
|
// so it survives the swap);
|
||||||
// sync);
|
// - typed fields never swap the input the user is in -- the amount field swaps
|
||||||
// - typed fields never swap the input the user is in -- the amount field
|
// only the #account-totals tbody (a sibling of the input rows), and the memo
|
||||||
// OOB-swaps only the #total/#balance cells (hx-swap=none), and the memo
|
|
||||||
// posts with hx-swap=none.
|
// posts with hx-swap=none.
|
||||||
// Because the active input is never part of a swapped region, focus and caret
|
// Because the active input is never part of a swapped region, focus and caret
|
||||||
// survive a plain swap with no morph extension involved.
|
// survive a plain swap.
|
||||||
|
|
||||||
// Collect any uncaught page errors or console errors so a swap that throws
|
// Collect any uncaught page errors or console errors so a swap that throws
|
||||||
// (e.g. a tooltip callback dereferencing a stale $refs) fails the test loudly.
|
// (e.g. a tooltip callback dereferencing a stale $refs) fails the test loudly.
|
||||||
@@ -36,7 +36,7 @@ async function openManualAdvanced(page: any, transactionIndex = 0) {
|
|||||||
await page.click('button:has-text("Manual")');
|
await page.click('button:has-text("Manual")');
|
||||||
|
|
||||||
// First transaction has no accounts so it opens in "simple" mode. Switch to
|
// First transaction has no accounts so it opens in "simple" mode. Switch to
|
||||||
// advanced mode (a section swap) so the account grid is present.
|
// advanced mode (a whole-form swap) so the account grid is present.
|
||||||
const advancedLink = page.locator('a:has-text("Switch to advanced mode")');
|
const advancedLink = page.locator('a:has-text("Switch to advanced mode")');
|
||||||
if (await advancedLink.count()) {
|
if (await advancedLink.count()) {
|
||||||
await advancedLink.first().click();
|
await advancedLink.first().click();
|
||||||
@@ -45,7 +45,7 @@ async function openManualAdvanced(page: any, transactionIndex = 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drives the vendor typeahead like a user: open the dropdown, inject a result
|
// Drives the vendor typeahead like a user: open the dropdown, inject a result
|
||||||
// (Solr is unavailable in tests), click it, and wait for the section swap.
|
// (Solr is unavailable in tests), click it, and wait for the whole-form swap.
|
||||||
async function selectVendor(page: any, vendorId: number, label: string) {
|
async function selectVendor(page: any, vendorId: number, label: string) {
|
||||||
const vendor = page
|
const vendor = page
|
||||||
.locator('div[hx-post*="edit-vendor-changed"]')
|
.locator('div[hx-post*="edit-vendor-changed"]')
|
||||||
@@ -71,7 +71,7 @@ async function selectVendor(page: any, vendorId: number, label: string) {
|
|||||||
await page.waitForTimeout(400);
|
await page.waitForTimeout(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes every existing account row (each remove is its own section swap), so a
|
// Removes every existing account row (each remove is its own whole-form swap), so a
|
||||||
// test starts from a known-empty state regardless of what earlier tests saved
|
// test starts from a known-empty state regardless of what earlier tests saved
|
||||||
// onto the shared transaction.
|
// onto the shared transaction.
|
||||||
async function clearAccounts(page: any) {
|
async function clearAccounts(page: any) {
|
||||||
@@ -90,12 +90,12 @@ async function clearAccounts(page: any) {
|
|||||||
test.describe.configure({ mode: 'serial' });
|
test.describe.configure({ mode: 'serial' });
|
||||||
|
|
||||||
test.describe('Transaction Edit whole-form swap', () => {
|
test.describe('Transaction Edit whole-form swap', () => {
|
||||||
test('section swaps (toggle mode, add account) do not throw', async ({ page }) => {
|
test('whole-form swaps (toggle mode, add account) do not throw', async ({ page }) => {
|
||||||
const errors = trackErrors(page);
|
const errors = trackErrors(page);
|
||||||
|
|
||||||
await openManualAdvanced(page, 0);
|
await openManualAdvanced(page, 0);
|
||||||
|
|
||||||
// Add an account row -- another section swap.
|
// Add an account row -- another whole-form swap.
|
||||||
await page
|
await page
|
||||||
.locator('#account-grid-body')
|
.locator('#account-grid-body')
|
||||||
.locator('button:has-text("New account"), a:has-text("New account")')
|
.locator('button:has-text("New account"), a:has-text("New account")')
|
||||||
@@ -133,10 +133,9 @@ test.describe('Transaction Edit whole-form swap', () => {
|
|||||||
await amount.waitFor();
|
await amount.waitFor();
|
||||||
|
|
||||||
// Type a clean value via the keyboard. Typing fires the field's htmx trigger
|
// Type a clean value via the keyboard. Typing fires the field's htmx trigger
|
||||||
// (keyup), which posts the whole form but swaps back ONLY the total/balance
|
// (keyup), which posts the whole form but swaps back only the #account-totals
|
||||||
// cells out-of-band (hx-swap=none on the field itself). The amount field is
|
// tbody -- a sibling of this input's row, so the input is never replaced. It's
|
||||||
// type=number (no text caret), so we assert focus + node identity + value --
|
// type=number (no text caret), so we assert focus + node identity + value.
|
||||||
// the input is never replaced, which is what makes that hold.
|
|
||||||
await amount.click();
|
await amount.click();
|
||||||
await amount.press('Control+a');
|
await amount.press('Control+a');
|
||||||
|
|
||||||
@@ -174,7 +173,7 @@ test.describe('Transaction Edit whole-form swap', () => {
|
|||||||
expect(state.value).toBe('150');
|
expect(state.value).toBe('150');
|
||||||
|
|
||||||
// The TOTAL must have recomputed server-side from the posted amount and been
|
// The TOTAL must have recomputed server-side from the posted amount and been
|
||||||
// applied via the out-of-band swap.
|
// applied via the #account-totals swap.
|
||||||
await expect(page.locator('.account-total-row #total')).toContainText('150');
|
await expect(page.locator('.account-total-row #total')).toContainText('150');
|
||||||
|
|
||||||
expect(errors, errors.join('\n')).toEqual([]);
|
expect(errors, errors.join('\n')).toEqual([]);
|
||||||
@@ -250,7 +249,7 @@ test.describe('Transaction Edit whole-form swap', () => {
|
|||||||
await openManualAdvanced(page, 0);
|
await openManualAdvanced(page, 0);
|
||||||
|
|
||||||
// Start from a clean, empty account row so selecting the account actually
|
// Start from a clean, empty account row so selecting the account actually
|
||||||
// changes accountId (and fires the change-gated section swap).
|
// changes accountId (and fires the change-gated whole-form swap).
|
||||||
await clearAccounts(page);
|
await clearAccounts(page);
|
||||||
await page
|
await page
|
||||||
.locator('#account-grid-body')
|
.locator('#account-grid-body')
|
||||||
@@ -281,7 +280,7 @@ test.describe('Transaction Edit whole-form swap', () => {
|
|||||||
}, accountId);
|
}, accountId);
|
||||||
|
|
||||||
// Clicking the result runs `value = element; tippy.hide(); ...` and dispatches
|
// Clicking the result runs `value = element; tippy.hide(); ...` and dispatches
|
||||||
// the change that fires the section swap.
|
// the change that fires the whole-form swap.
|
||||||
const swap = page.waitForResponse(
|
const swap = page.waitForResponse(
|
||||||
(r: any) =>
|
(r: any) =>
|
||||||
r.url().includes('edit-form-changed') &&
|
r.url().includes('edit-form-changed') &&
|
||||||
@@ -292,7 +291,7 @@ test.describe('Transaction Edit whole-form swap', () => {
|
|||||||
await swap;
|
await swap;
|
||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
|
|
||||||
// The chosen account must survive the section swap.
|
// The chosen account must survive the whole-form swap.
|
||||||
const hidden = page
|
const hidden = page
|
||||||
.locator('#account-grid-body tbody tr.account-row')
|
.locator('#account-grid-body tbody tr.account-row')
|
||||||
.first()
|
.first()
|
||||||
|
|||||||
@@ -45,10 +45,10 @@
|
|||||||
[:label {:for "checkbox-all", :class "sr-only"} "checkbox"]]])
|
[:label {:for "checkbox-all", :class "sr-only"} "checkbox"]]])
|
||||||
|
|
||||||
(defn data-grid-
|
(defn data-grid-
|
||||||
[{:keys [headers thead-params id] :as params} & rest]
|
[{:keys [headers thead-params id footer-tbody] :as params} & rest]
|
||||||
[:div.shrink.overflow-y-scroll
|
[:div.shrink.overflow-y-scroll
|
||||||
[:table (merge {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400 shrink"}
|
[:table (merge {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400 shrink"}
|
||||||
(dissoc params :headers :thead-params))
|
(dissoc params :headers :thead-params :footer-tbody))
|
||||||
[:thead (update thead-params :class #(-> "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 group-[.raw]:sticky group-[.raw]:z-10 group-[.raw]:top-0"
|
[:thead (update thead-params :class #(-> "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 group-[.raw]:sticky group-[.raw]:z-10 group-[.raw]:top-0"
|
||||||
(hh/add-class (or % ""))))
|
(hh/add-class (or % ""))))
|
||||||
(into
|
(into
|
||||||
@@ -56,7 +56,11 @@
|
|||||||
headers)]
|
headers)]
|
||||||
(into
|
(into
|
||||||
[:tbody {}]
|
[:tbody {}]
|
||||||
rest)]])
|
rest)
|
||||||
|
;; Optional second <tbody> (valid HTML) so callers can keep a stable,
|
||||||
|
;; separately-swappable region in the same table -- e.g. totals rows that
|
||||||
|
;; update without touching the input-bearing rows above them.
|
||||||
|
footer-tbody]])
|
||||||
|
|
||||||
;; needed for tailwind
|
;; needed for tailwind
|
||||||
;; lg:table-cell md:table-cell
|
;; lg:table-cell md:table-cell
|
||||||
|
|||||||
@@ -305,11 +305,6 @@
|
|||||||
(list
|
(list
|
||||||
(fc/with-field :snapshot
|
(fc/with-field :snapshot
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
;; Stable id so a partial swap (e.g. the transaction
|
|
||||||
;; edit form swapping only #manual-coding-section) can
|
|
||||||
;; refresh the encoded snapshot out-of-band and keep the
|
|
||||||
;; round-tripped wizard state in sync.
|
|
||||||
:id "wizard-snapshot"
|
|
||||||
:value (pr-str (fc/field-value))}))
|
:value (pr-str (fc/field-value))}))
|
||||||
(fc/with-field :edit-path
|
(fc/with-field :edit-path
|
||||||
(com/hidden {:name (fc/field-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
|
|||||||
@@ -233,9 +233,8 @@
|
|||||||
:x-dispatch:changed "simpleAccountId"
|
:x-dispatch:changed "simpleAccountId"
|
||||||
:hx-trigger "changed"
|
:hx-trigger "changed"
|
||||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-include "closest form"}
|
:hx-include "closest form"}
|
||||||
(location-select*
|
(location-select*
|
||||||
@@ -250,9 +249,8 @@
|
|||||||
[:a.text-sm.text-blue-600.hover:underline.cursor-pointer
|
[:a.text-sm.text-blue-600.hover:underline.cursor-pointer
|
||||||
{:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-toggle-mode)
|
{:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-toggle-mode)
|
||||||
:hx-include "closest form"
|
:hx-include "closest form"
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
"Switch to advanced mode"]]]))
|
"Switch to advanced mode"]]]))
|
||||||
|
|
||||||
@@ -296,9 +294,8 @@
|
|||||||
:x-dispatch:changed "accountId"
|
:x-dispatch:changed "accountId"
|
||||||
:hx-trigger "changed"
|
:hx-trigger "changed"
|
||||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-include "closest form"}
|
:hx-include "closest form"}
|
||||||
(location-select* {:name (fc/field-name)
|
(location-select* {:name (fc/field-name)
|
||||||
@@ -317,12 +314,12 @@
|
|||||||
:class "w-16 account-amount-field"
|
:class "w-16 account-amount-field"
|
||||||
:value (fc/field-value)
|
:value (fc/field-value)
|
||||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-form-changed)
|
||||||
;; Typing an amount posts the whole form but swaps NOTHING into the field
|
;; Typing an amount posts the whole form but swaps back only the
|
||||||
;; itself (hx-swap=none). Only the TOTAL and BALANCE cells are pulled out of
|
;; #account-totals tbody -- a sibling of the input-bearing rows, so
|
||||||
;; the response and applied out-of-band, so the amount input is never replaced
|
;; the amount input is never replaced and the caret survives.
|
||||||
;; and the user's focus + caret survive with no morph involved.
|
:hx-target "#account-totals"
|
||||||
:hx-select-oob "#total,#balance"
|
:hx-select "#account-totals"
|
||||||
:hx-swap "none"
|
:hx-swap "outerHTML"
|
||||||
:hx-trigger "keyup changed delay:300ms"
|
:hx-trigger "keyup changed delay:300ms"
|
||||||
:hx-include "closest form"}]
|
:hx-include "closest form"}]
|
||||||
(if (= "%" amount-mode)
|
(if (= "%" amount-mode)
|
||||||
@@ -331,9 +328,8 @@
|
|||||||
(com/data-grid-cell {:class "align-top"}
|
(com/data-grid-cell {:class "align-top"}
|
||||||
(com/a-icon-button {:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-remove-account)
|
(com/a-icon-button {:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-remove-account)
|
||||||
:hx-vals (hx/json {:row-index (or index 0)})
|
:hx-vals (hx/json {:row-index (or index 0)})
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-include "closest form"
|
:hx-include "closest form"
|
||||||
:class "account-remove-action"} svg/x))))
|
:class "account-remove-action"} svg/x))))
|
||||||
@@ -475,12 +471,36 @@
|
|||||||
:name "step-params[amount-mode]"
|
:name "step-params[amount-mode]"
|
||||||
:orientation :horizontal
|
:orientation :horizontal
|
||||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/toggle-amount-mode)
|
:hx-post (bidi/path-for ssr-routes/only-routes ::route/toggle-amount-mode)
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-include "closest form"}))
|
:hx-include "closest form"}))
|
||||||
(com/data-grid-header {:class "w-16"})]}
|
(com/data-grid-header {:class "w-16"})]
|
||||||
|
;; Totals live in their own <tbody id="account-totals"> so the amount
|
||||||
|
;; field refreshes them with a plain targeted swap, never swapping the
|
||||||
|
;; input-bearing rows above (which would drop the caret).
|
||||||
|
:footer-tbody
|
||||||
|
[:tbody {:id "account-totals"}
|
||||||
|
(com/data-grid-row {:class "account-total-row"}
|
||||||
|
(com/data-grid-cell {})
|
||||||
|
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"])
|
||||||
|
(com/data-grid-cell {:id "total"
|
||||||
|
:class "text-right"}
|
||||||
|
(account-total* request))
|
||||||
|
(com/data-grid-cell {}))
|
||||||
|
(com/data-grid-row {:class "account-balance-row"}
|
||||||
|
(com/data-grid-cell {})
|
||||||
|
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "BALANCE"])
|
||||||
|
(com/data-grid-cell {:id "balance"
|
||||||
|
:class "text-right"}
|
||||||
|
(account-balance* request))
|
||||||
|
(com/data-grid-cell {}))
|
||||||
|
(com/data-grid-row {:class "account-grand-total-row"}
|
||||||
|
(com/data-grid-cell {})
|
||||||
|
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TRANSACTION TOTAL"])
|
||||||
|
(com/data-grid-cell {:class "text-right"}
|
||||||
|
(format "$%,.2f" total))
|
||||||
|
(com/data-grid-cell {}))]}
|
||||||
(fc/cursor-map (fn [cursor]
|
(fc/cursor-map (fn [cursor]
|
||||||
(transaction-account-row* {:value cursor
|
(transaction-account-row* {:value cursor
|
||||||
:client-id (-> request :entity :transaction/client :db/id)
|
:client-id (-> request :entity :transaction/client :db/id)
|
||||||
@@ -491,35 +511,12 @@
|
|||||||
(com/data-grid-row {:class "new-row"}
|
(com/data-grid-row {:class "new-row"}
|
||||||
(com/data-grid-cell {:colspan 4}
|
(com/data-grid-cell {:colspan 4}
|
||||||
(com/a-button {:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-new-account)
|
(com/a-button {:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-new-account)
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-include "closest form"
|
:hx-include "closest form"
|
||||||
:color :secondary}
|
:color :secondary}
|
||||||
"New account")))
|
"New account"))))))
|
||||||
(com/data-grid-row {:class "account-total-row"}
|
|
||||||
(com/data-grid-cell {})
|
|
||||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TOTAL"])
|
|
||||||
(com/data-grid-cell {:id "total"
|
|
||||||
:class "text-right"}
|
|
||||||
(account-total* request))
|
|
||||||
(com/data-grid-cell {}))
|
|
||||||
|
|
||||||
(com/data-grid-row {:class "account-balance-row"}
|
|
||||||
(com/data-grid-cell {})
|
|
||||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "BALANCE"])
|
|
||||||
(com/data-grid-cell {:id "balance"
|
|
||||||
:class "text-right"}
|
|
||||||
(account-balance* request))
|
|
||||||
(com/data-grid-cell {}))
|
|
||||||
|
|
||||||
(com/data-grid-row {:class "account-grand-total-row"}
|
|
||||||
(com/data-grid-cell {})
|
|
||||||
(com/data-grid-cell {:class "text-right"} [:span.font-bold.text-right "TRANSACTION TOTAL"])
|
|
||||||
(com/data-grid-cell {:class "text-right"}
|
|
||||||
(format "$%,.2f" total))
|
|
||||||
(com/data-grid-cell {})))))
|
|
||||||
|
|
||||||
(defn manual-coding-section*
|
(defn manual-coding-section*
|
||||||
"Renders the vendor field + account/location section for the manual tab.
|
"Renders the vendor field + account/location section for the manual tab.
|
||||||
@@ -536,9 +533,8 @@
|
|||||||
(com/hidden {:name "step-params[mode]" :value (name mode)})
|
(com/hidden {:name "step-params[mode]" :value (name mode)})
|
||||||
[:div {:hx-trigger "change"
|
[:div {:hx-trigger "change"
|
||||||
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-vendor-changed)
|
:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-vendor-changed)
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"
|
:hx-swap "outerHTML"
|
||||||
:hx-sync "this:replace"
|
:hx-sync "this:replace"
|
||||||
:hx-include "closest form"}
|
:hx-include "closest form"}
|
||||||
@@ -564,9 +560,8 @@
|
|||||||
[:a.text-sm.text-blue-600.hover:underline.cursor-pointer
|
[:a.text-sm.text-blue-600.hover:underline.cursor-pointer
|
||||||
{:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-toggle-mode)
|
{:hx-post (bidi/path-for ssr-routes/only-routes ::route/edit-wizard-toggle-mode)
|
||||||
:hx-include "closest form"
|
:hx-include "closest form"
|
||||||
:hx-target "#manual-coding-section"
|
:hx-target "#wizard-form"
|
||||||
:hx-select "#manual-coding-section"
|
:hx-select "#wizard-form"
|
||||||
:hx-select-oob "#wizard-snapshot"
|
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
"Switch to simple mode"]])
|
"Switch to simple mode"]])
|
||||||
(fc/with-field :transaction/accounts
|
(fc/with-field :transaction/accounts
|
||||||
|
|||||||
Reference in New Issue
Block a user