4 Commits

Author SHA1 Message Date
85aaf7b759 mcp repl fixes 2026-06-02 23:40:05 -07:00
3641846f70 Merge pull request 'docs: SSR rendering modernization rollout plan' (#12) from docs/ssr-rendering-modernization-plan into staging
Reviewed-on: #12
2026-06-02 23:26:45 -07:00
8215e6376d Merge pull request 'fix(ssr): require Apply for all date-range filters' (#13) from integreat-fix-other-dates into staging
Reviewed-on: #13
2026-06-02 22:42:49 -07:00
3759258ebe fix(ssr): require Apply for all date-range filters
Most grid pages auto-submitted their date-range filter on every change
event, which fired mid-typing and re-rendered the date inputs, breaking
manual date entry. Invoices and ledgers already gated date submission
behind an explicit Apply button; this brings the other ten pages in line.

- date-range component: stop `change` from the date inputs bubbling to
  the form (@change.stop) and always render the Apply button, so typed or
  picked dates submit only via the Apply button's `datesApplied` event.
  The All/Week/Month/Year presets and all other filters are unaffected.
- payments, invoice import, transactions, import batches, sales
  summaries, expected deposits, cash drawer shifts, refunds, tenders,
  sales orders: add `datesApplied` to the form hx-trigger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:42:17 -07:00
13 changed files with 48 additions and 27 deletions

View File

@@ -62,7 +62,15 @@
(.setHandler server stats-handler))
(.setStopAtShutdown server true))
(def ^:dynamic *http-port-override* nil)
(def ^:dynamic *http-port-override*
;; In dev, `lein mcp-repl` records the chosen HTTP port in `.http-port` so it
;; stays stable across reloads. `refresh` re-evaluates this def, so reading the
;; file here (rather than relying solely on an alter-var-root override that gets
;; reset) keeps the port from falling back to (env :port). Absent in prod.
(let [f (java.io.File. ".http-port")]
(when (.exists f)
(let [p (.trim ^String (slurp f))]
(when (seq p) p)))))
(mount/defstate port :start (Integer/parseInt (str (or *http-port-override* (env :port) "3000"))))

View File

@@ -35,7 +35,7 @@
default-grid-fields-schema)]))
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"

View File

@@ -7,7 +7,7 @@
[clj-time.core :as t]
[clj-time.periodic :as per]))
(defn date-range-field [{:keys [value id apply-button?]}]
(defn date-range-field [{:keys [value id]}]
[:div {:id id}
(com/field {:label "Date Range"}
[:div.space-y-4
@@ -17,7 +17,7 @@
(com/button-group-button {:size :small :value "week" :hx-trigger "click"} "Week")
(com/button-group-button {:size :small :value "month" :hx-trigger "click"} "Month")
(com/button-group-button {:size :small :value "year" :hx-trigger "click"} "Year"))]
[:div.flex.space-x-1.items-baseline.w-full.justify-start
[:div.flex.space-x-1.items-baseline.w-full.justify-start {"@change.stop" ""}
(com/date-input {:name "start-date"
:value (some-> (:start value)
(atime/unparse-local atime/normal-date))
@@ -31,9 +31,8 @@
:placeholder "Date"
:size :small
:class "shrink date-filter-input"})
(when apply-button?
(but/button- {:color :secondary
:size :small
:type "button"
"x-on:click" "$dispatch('datesApplied')"}
"Apply"))]])])
(but/button- {:color :secondary
:size :small
:type "button"
"x-on:click" "$dispatch('datesApplied')"}
"Apply")]])])

View File

@@ -56,7 +56,7 @@
[:div {:id "exact-match-id-tag"}]))
(defn filters [request]
[:form#invoice-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form#invoice-filters {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/import-table)
"hx-target" "#entity-table"

View File

@@ -53,7 +53,7 @@
[:div {:id "exact-match-id-tag"}]))
(defn filters [request]
[:form#payment-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form#payment-filters {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"

View File

@@ -29,7 +29,7 @@
default-grid-fields-schema)]))
(defn filters [params]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
:pos-cash-drawer-shift-table)
"hx-target" "#cash-drawer-shift-table"

View File

@@ -34,7 +34,7 @@
default-grid-fields-schema)]))
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
:pos-expected-deposit-table)
"hx-target" "#expected-deposit-table"

View File

@@ -29,7 +29,7 @@
[:client {:optional true :default nil} [:maybe [:entity-map {:pull [:db/id :client/name]}]]]]
default-grid-fields-schema)]))
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
:pos-refund-table)
"hx-target" "#refund-table"

View File

@@ -34,7 +34,7 @@
default-grid-fields-schema)]))
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
:pos-sales-table)
"hx-target" "#sales-table"

View File

@@ -44,7 +44,7 @@
default-grid-fields-schema)]))
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"

View File

@@ -22,7 +22,7 @@
;; always should be fast
(defn filters [request]
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
:pos-tender-table)
"hx-target" "#tender-table"

View File

@@ -316,7 +316,7 @@
:content (:bank-account/name ba)}))}))))])
(defn filters [request]
[:form#transaction-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
[:form#transaction-filters {"hx-trigger" "datesApplied, change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
"hx-get" (bidi/path-for ssr-routes/only-routes
::route/table)
"hx-target" "#entity-table"

View File

@@ -9,15 +9,29 @@
(with-open [s (ServerSocket. 0)]
(.getLocalPort s)))
(defn- mcp-repl-task [& _args]
"Start nREPL server and HTTP server on random ports.
(defn- read-port [path]
"Read a previously-recorded port from `path`, or nil if missing/unparseable."
(let [f (io/file path)]
(when (.exists f)
(try (Integer/parseInt (.trim ^String (slurp f)))
(catch Exception _ nil)))))
Writes ports to nrepl-port and .http-port files.
Connect with: clj-nrepl-eval -p $(cat nrepl-port)"
(let [nrepl-port (available-port)
http-port (available-port)]
(spit "nrepl-port" (str nrepl-port))
(spit ".http-port" (str http-port))
(defn- stable-port [path]
"Reuse the port recorded in `path` if present, otherwise pick a random
available one. Always (re)writes the file so the port stays stable for this
worktree across REPL restarts and reloads."
(let [port (or (read-port path) (available-port))]
(spit path (str port))
port))
(defn- mcp-repl-task [& _args]
"Start nREPL server and HTTP server.
Reuses the ports recorded in nrepl-port and .http-port if present (keeping
them stable per worktree), otherwise picks random available ports and records
them. Connect with: clj-nrepl-eval -p $(cat nrepl-port)"
(let [nrepl-port (stable-port "nrepl-port")
http-port (stable-port ".http-port")]
(println (format "nREPL port: %d (nrepl-port)" nrepl-port))
(println (format "HTTP port: %d (.http-port)" http-port))
(nrepl/start-server :port nrepl-port)