From 48347bb8c543c73cc11d3540c8d7caa0b0c33ec5 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 23 Oct 2023 23:46:01 -0700 Subject: [PATCH] Uses cursors for simplicity, uses common grid bottom --- src/clj/auto_ap/cursor.clj | 9 +++ src/clj/auto_ap/ssr/admin/accounts.clj | 37 ++++------ .../auto_ap/ssr/admin/transaction_rules.clj | 68 ++++++++----------- src/clj/auto_ap/ssr/components.clj | 1 + src/clj/auto_ap/ssr/components/data_grid.clj | 24 ++++++- src/clj/auto_ap/ssr/form_cursor.clj | 13 +++- src/clj/auto_ap/ssr/hx.clj | 6 +- src/clj/auto_ap/ssr/users.clj | 30 +++----- 8 files changed, 98 insertions(+), 90 deletions(-) diff --git a/src/clj/auto_ap/cursor.clj b/src/clj/auto_ap/cursor.clj index 0ff1448d..6a7f25cc 100644 --- a/src/clj/auto_ap/cursor.clj +++ b/src/clj/auto_ap/cursor.clj @@ -125,6 +125,15 @@ [] nil)) +(defn synthetic-cursor [v prefix] + (let [internal-cursor (cursor v)] + (reify ICursor + (path [this] + (into prefix (path internal-cursor))) + (state [this] + (state internal-cursor))))) + + (defn transact! [cursor f] "Changes value beneath cursor by passing it to a single-argument function f. Old value will be passed as function argument. Function diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index c1ce0feb..ef48ae82 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -248,7 +248,8 @@ (defn client-override* [override] (com/data-grid-row (-> {:x-ref "p" :data-key "show" - :x-data (hx/json {:show (boolean (not (:new? override)))})} + :x-data (hx/json {:show (boolean (doto (not (fc/field-value (:new? override))) + println))})} hx/alpine-mount-then-appear) (fc/with-field :db/id (com/hidden {:name (fc/field-name) @@ -378,19 +379,12 @@ :id "client-override-table"} (fc/cursor-map #(client-override* %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 3 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-account-client-override-new) - :color :secondary - :hx-include "#edit-form" - :hx-vals (hiccup/raw "js:{index: countRows(\"#client-override-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New override")]))))) + + (com/data-grid-new-row {:colspan 3 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-account-client-override-new)} + "New override")))) ] [:div @@ -401,14 +395,13 @@ "Save account")])]])])) (defn new-client-override [{ {:keys [index]} :query-params}] - (let [index (or index 0) - account {:account/client-overrides (conj (into [] (repeat index {})) - {:db/id (str (java.util.UUID/randomUUID)) - :new? true})}] ;; TODO schema decode is not working - (html-response - (fc/start-form account [] - (fc/with-cursor (get-in fc/*current* [:account/client-overrides index]) - (client-override* fc/*current*)))))) + (html-response + (fc/start-form-with-prefix + [:account/client-overrides (or index 0)] + {:db/id (str (java.util.UUID/randomUUID)) + :new? true} + [] + (client-override* fc/*current*)))) (defn account-edit-dialog [request] (let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))] diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 16f7f10e..0b0060e9 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -543,31 +543,18 @@ :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) (fc/with-field :transaction-rule/accounts - (list - (com/data-grid {:headers [(com/data-grid-header {} "Account") - (com/data-grid-header {:class "w-32"} "Location") - (com/data-grid-header {:class "w-16"} "%") - (com/data-grid-header {:class "w-16"})] - :id "transaction-rule-account-table"} - (fc/cursor-map #(transaction-rule-account-row* entity %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 4 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-new-account) - :color :secondary - :hx-include "#edit-form" - :hx-ext "rename-params" - ;; TODO - :hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id" - "index" "index"}) - :hx-vals (hiccup/raw "js:{index: countRows(\"#transaction-rule-account-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New account")]))) - (com/errors {:errors (fc/field-errors)}))) + (com/data-grid {:headers [(com/data-grid-header {} "Account") + (com/data-grid-header {:class "w-32"} "Location") + (com/data-grid-header {:class "w-16"} "%") + (com/data-grid-header {:class "w-16"})] + :id "transaction-rule-account-table"} + (fc/cursor-map #(transaction-rule-account-row* entity %)) + (com/data-grid-new-row {:colspan 4 + :hx-get (bidi/path-for ssr-routes/only-routes + :admin-transaction-rule-new-account) + :index (count (fc/field-value)) + :tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})} + "New account"))) (fc/with-field :transaction-rule/transaction-approval-status (com/validated-field {:label "Approval status" @@ -578,7 +565,6 @@ :size :small :orientation :horizontal}))) - ;; TODO componentize ]] [:div [:div#form-errors (when (:errors fc/*form-errors*) @@ -593,21 +579,21 @@ ;; pull out the single field to swap (defn new-account [{{:keys [client-id index]} :query-params}] - (let [index (or index 0) ;; TODO schema decode is not working - transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] - client-id) - :transaction-rule/accounts (conj (into [] (repeat index {} )) - {:db/id (str (java.util.UUID/randomUUID)) - :transaction-rule-account/location "Shared" - :new? true})}] - (html-response - (fc/start-form transaction-rule [] - (fc/with-cursor (get-in fc/*current* [:transaction-rule/accounts index]) - (transaction-rule-account-row* - ;; TODO store a pointer to the "head " cursor for errors instead of nesting them - ;; makes it so you don't have to do this - transaction-rule - fc/*current*)))))) + (html-response + (fc/start-form-with-prefix + [:transaction-rule/accounts (or index 0)] + {:db/id (str (java.util.UUID/randomUUID)) + :transaction-rule-account/location "Shared" + :new? true} + [] + (transaction-rule-account-row* + ;; TODO store a pointer to the "head " cursor for errors instead of nesting them + ;; makes it so you don't have to do this + + {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id] + client-id)} + + fc/*current*)))) ;; TODO check to see if it should be called "Shared" or "shared" for the value diff --git a/src/clj/auto_ap/ssr/components.clj b/src/clj/auto_ap/ssr/components.clj index cee70ef2..56c410c0 100644 --- a/src/clj/auto_ap/ssr/components.clj +++ b/src/clj/auto_ap/ssr/components.clj @@ -59,6 +59,7 @@ (def data-grid-row data-grid/row-) (def data-grid-cell data-grid/cell-) (def data-grid-right-stack-cell data-grid/right-stack-cell-) +(def data-grid-new-row data-grid/new-row-) (defn link [params & children] (into [:a (update params :class str " font-medium text-blue-600 dark:text-blue-500 hover:underline ")] diff --git a/src/clj/auto_ap/ssr/components/data_grid.clj b/src/clj/auto_ap/ssr/components/data_grid.clj index caf91017..f62c7f12 100644 --- a/src/clj/auto_ap/ssr/components/data_grid.clj +++ b/src/clj/auto_ap/ssr/components/data_grid.clj @@ -3,8 +3,10 @@ [auto-ap.ssr-routes :as ssr-routes] [auto-ap.ssr.components.card :refer [content-card-]] [auto-ap.ssr.components.paginator :refer [paginator-]] + [auto-ap.ssr.components.buttons :refer [a-button-]] [bidi.bidi :as bidi] - [hiccup2.core :as hiccup])) + [hiccup2.core :as hiccup] + [auto-ap.ssr.hx :as hx])) (defn header- [params & rest] (into [:th.px-4.py-3 {:scope "col" :class (:class params) @@ -103,3 +105,23 @@ [:div {:class "htmx-indicator absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2 overflow-hidden w-full h-full"} [:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" } [:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])]) + +(defn new-row- [{:keys [index colspan tr-params] :as params} & content] + (row- + (merge {:class "new-row" + :x-data (hx/json {:newRowIndex index}) + } + tr-params) + (cell- {:colspan colspan + :class "bg-gray-100"} + [:div.flex.justify-center + (a-button- (merge + (dissoc params :index :colspan) + { + "@click" "$dispatch('newRow', {index: newRowIndex++})" + :color :secondary + :hx-trigger "newRow" + :hx-vals (hiccup/raw "js:{index: event.detail.index}") + :hx-target "closest .new-row" + :hx-swap "beforebegin"}) + content)]))) diff --git a/src/clj/auto_ap/ssr/form_cursor.clj b/src/clj/auto_ap/ssr/form_cursor.clj index 02c65ba4..536a3a2f 100644 --- a/src/clj/auto_ap/ssr/form_cursor.clj +++ b/src/clj/auto_ap/ssr/form_cursor.clj @@ -2,17 +2,26 @@ (:require [auto-ap.ssr.utils :refer [path->name2]] [auto-ap.cursor :as cursor])) +(def ^:dynamic *prefix* []) (def ^:dynamic *form-data*) (def ^:dynamic *form-errors*) (def ^:dynamic *prev-cursor* nil) (def ^:dynamic *current* nil) + + (defmacro start-form [form-data errors & rest] `(binding [*form-data* ~form-data *form-errors* (or ~errors {})] - (binding [*current* (cursor/cursor *form-data*)] + (binding [*current* (if (cursor/cursor? *form-data*) + *form-data* + (cursor/cursor *form-data*))] ~@rest))) +(defmacro start-form-with-prefix [prefix form-data errors & rest] + `(binding [*prefix* ~prefix] + (start-form ~form-data ~errors ~@rest))) + (defmacro with-cursor [cursor & rest] `(binding [*current* ~cursor] ~@rest)) @@ -24,7 +33,7 @@ (defn field-name ([] (field-name *current*)) ([cursor] - (apply path->name2 (cursor/path cursor)))) + (apply path->name2 (into (or *prefix* []) (cursor/path cursor))))) (defn field-value ([] (field-value *current*)) diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index 895d024e..0a069362 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -32,9 +32,9 @@ "x-transition:leave-end" "opacity-0")) (defn alpine-mount-then-appear [{:keys [data-key] :as params}] - (merge (-> {"x-data" (json {data-key false}) - "x-init" (format "$nextTick(() => %s=true)" (name data-key)) - "x-show" (name data-key)} + (merge (-> {:x-data (json {data-key false}) + :x-init (format "$nextTick(() => %s=true)" (name data-key)) + :x-show (name data-key)} alpine-appear alpine-disappear) (dissoc params :data-key))) diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index e225fef3..e1d90816 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -323,19 +323,11 @@ (com/data-grid-header {} )] :id "client-table"} (fc/cursor-map #(client-row* %)) - (com/data-grid-row - {:class "new-row"} - (com/data-grid-cell {:colspan 2 - :class "bg-gray-100"} - [:div.flex.justify-center - (com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes - :user-client-new) - :color :secondary - :hx-include "#edit-form" - :hx-vals (hiccup/raw "js:{index: countRows(\"#client-table\")}") - :hx-target "#edit-form .new-row" - :hx-swap "beforebegin"} - "New override")])))))] + (com/data-grid-new-row {:colspan 2 + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes + :user-client-new)} + "Assign new client"))))] [:div [:div [:div#form-errors (when (:errors fc/*form-errors*) [:span.error-content @@ -374,14 +366,10 @@ :headers {"hx-trigger" "modalopen"}))) (defn new-client [{ {:keys [index]} :query-params}] - (let [index (or index 0) - account {:user/clients (conj (into [] (repeat index {})) - {:db/id nil - :new? true})}] ;; TODO schema decode is not working - (html-response - (fc/start-form account [] - (fc/with-cursor (get-in fc/*current* [:user/clients index]) - (client-row* fc/*current*)))))) + (html-response + (fc/start-form-with-prefix [:user/clients (or index 0)] {:db/id nil + :new? true} [] + (client-row* fc/*current*)))) (def key->handler (apply-middleware-to-all-handlers