uses cursors instead, much clearer experience.
This commit is contained in:
@@ -126,5 +126,6 @@ elem.dp = new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true});
|
|||||||
countRows = function(id) {
|
countRows = function(id) {
|
||||||
var table = document.querySelector(id);
|
var table = document.querySelector(id);
|
||||||
var rows = table.querySelectorAll("tbody tr");
|
var rows = table.querySelectorAll("tbody tr");
|
||||||
|
console.log("ROWS", rows.length);
|
||||||
return rows.length;
|
return rows.length;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
[auto-ap.ssr.components :as com]
|
[auto-ap.ssr.components :as com]
|
||||||
[auto-ap.ssr.grid-page-helper :as helper]
|
[auto-ap.ssr.grid-page-helper :as helper]
|
||||||
[auto-ap.ssr.hx :as hx]
|
[auto-ap.ssr.hx :as hx]
|
||||||
|
[auto-ap.ssr.form-cursor :as fc]
|
||||||
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
|
[auto-ap.ssr.nested-form-params :refer [wrap-nested-form-params]]
|
||||||
[auto-ap.ssr.svg :as svg]
|
[auto-ap.ssr.svg :as svg]
|
||||||
[auto-ap.ssr.utils
|
[auto-ap.ssr.utils
|
||||||
@@ -58,34 +59,13 @@
|
|||||||
|
|
||||||
;; TODO better generation of names?
|
;; TODO better generation of names?
|
||||||
|
|
||||||
(def ^:dynamic *errors*)
|
|
||||||
(def ^:dynamic *prev-cursor* nil)
|
|
||||||
(def ^:dynamic *cursor* nil)
|
|
||||||
|
|
||||||
(defmacro with-cursor [cursor & rest]
|
|
||||||
`(binding [*prev-cursor* (or *cursor* ~cursor)]
|
|
||||||
(binding [*cursor* ~cursor]
|
|
||||||
~@rest)))
|
|
||||||
|
|
||||||
(defn cursor-name []
|
|
||||||
(apply path->name2 (cursor/path *cursor*)))
|
|
||||||
|
|
||||||
(defn cursor-value []
|
|
||||||
@*cursor*)
|
|
||||||
|
|
||||||
(defn cursor-errors []
|
|
||||||
(:errors (get
|
|
||||||
(meta @*prev-cursor*)
|
|
||||||
(last (cursor/path *cursor*)))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn filters [request]
|
(defn filters [request]
|
||||||
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
[:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
|
||||||
"hx-get" (bidi/path-for ssr-routes/only-routes
|
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||||
:admin-transaction-rule-table)
|
:admin-transaction-rule-table)
|
||||||
"hx-target" "#transaction-rule-table"
|
"hx-target" "#transaction-rule-table"
|
||||||
"hx-indicator" "#transaction-rule-table"}
|
"hx-indicator" "#transaction-rule-table"}
|
||||||
|
|
||||||
[:fieldset.space-y-6
|
[:fieldset.space-y-6
|
||||||
(com/field {:label "Vendor"}
|
(com/field {:label "Vendor"}
|
||||||
@@ -301,7 +281,7 @@
|
|||||||
:when (and account-location (not= account-location location))]
|
:when (and account-location (not= account-location location))]
|
||||||
(field-validation-error (str "must be " account-location)
|
(field-validation-error (str "must be " account-location)
|
||||||
[:transaction-rule/accounts i :transaction-rule-account/location]
|
[:transaction-rule/accounts i :transaction-rule-account/location]
|
||||||
:form entity))
|
:form form-params))
|
||||||
|
|
||||||
total (reduce +
|
total (reduce +
|
||||||
0.0
|
0.0
|
||||||
@@ -309,14 +289,14 @@
|
|||||||
(:transaction-rule/accounts entity)))
|
(:transaction-rule/accounts entity)))
|
||||||
_ (when-not (dollars= 1.0 total)
|
_ (when-not (dollars= 1.0 total)
|
||||||
(form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total)))
|
(form-validation-error (format "Expense accounts total (%d%%) must add to 100%%" (int (* 100.0 total)))
|
||||||
:form entity))
|
:form form-params))
|
||||||
|
|
||||||
_ (when (and (:transaction-rule/bank-account entity)
|
_ (when (and (:transaction-rule/bank-account entity)
|
||||||
(not (bank-account-belongs-to-client? (:transaction-rule/bank-account entity)
|
(not (bank-account-belongs-to-client? (:transaction-rule/bank-account entity)
|
||||||
(:transaction-rule/client entity))))
|
(:transaction-rule/client entity))))
|
||||||
(field-validation-error "does not belong to client"
|
(field-validation-error "does not belong to client"
|
||||||
[:transaction-rule/bank-account]
|
[:transaction-rule/bank-account]
|
||||||
:form entity))
|
:form form-params))
|
||||||
|
|
||||||
|
|
||||||
{:keys [tempids]} (audit-transact [[:upsert-entity entity]]
|
{:keys [tempids]} (audit-transact [[:upsert-entity entity]]
|
||||||
@@ -366,13 +346,12 @@
|
|||||||
(defn- transaction-rule-account-row*
|
(defn- transaction-rule-account-row*
|
||||||
[transaction-rule account]
|
[transaction-rule account]
|
||||||
(com/data-grid-row {}
|
(com/data-grid-row {}
|
||||||
(let [account-name (with-cursor (:transaction-rule-account/account account)
|
(let [account-name (fc/field-name (:transaction-rule-account/account account))]
|
||||||
(cursor-name))]
|
|
||||||
(list
|
(list
|
||||||
(with-cursor (:db/id account)
|
(fc/with-field :db/id
|
||||||
(com/hidden {:name (cursor-name)
|
(com/hidden {:name (fc/field-name)
|
||||||
:value (cursor-value)}))
|
:value (fc/field-value)}))
|
||||||
(with-cursor (:transaction-rule-account/account account)
|
(fc/with-field :transaction-rule-account/account
|
||||||
(com/data-grid-cell {}
|
(com/data-grid-cell {}
|
||||||
[:div {:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
[:div {:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
||||||
:from "#edit-form")
|
:from "#edit-form")
|
||||||
@@ -384,11 +363,15 @@
|
|||||||
account-name "value"})
|
account-name "value"})
|
||||||
:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead))
|
:hx-get (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-account-typeahead))
|
||||||
:hx-swap "innerHTML"}
|
:hx-swap "innerHTML"}
|
||||||
(account-typeahead* {:value (cursor-value)
|
(account-typeahead* {:value (fc/field-value)
|
||||||
:client-id (:db/id (:transaction-rule/client transaction-rule))
|
:client-id (:db/id (:transaction-rule/client transaction-rule))
|
||||||
:name (cursor-name)})
|
:name (fc/field-name)})
|
||||||
(com/errors {:errors (cursor-errors)})]))
|
(println "HERE" (cursor/path fc/*current*))
|
||||||
(with-cursor (:transaction-rule-account/location account)
|
(println "DATA "fc/*form-data*)
|
||||||
|
(println "ERR" fc/*form-errors*)
|
||||||
|
(println (fc/field-errors))
|
||||||
|
(com/errors {:errors (fc/field-errors)})]))
|
||||||
|
(fc/with-field :transaction-rule-account/location
|
||||||
(com/data-grid-cell {}
|
(com/data-grid-cell {}
|
||||||
[:div [:div {:hx-trigger (hx/triggers
|
[:div [:div {:hx-trigger (hx/triggers
|
||||||
(hx/trigger-field-change :name "transaction-rule/client"
|
(hx/trigger-field-change :name "transaction-rule/client"
|
||||||
@@ -396,36 +379,36 @@
|
|||||||
(hx/trigger-field-change :name account-name
|
(hx/trigger-field-change :name account-name
|
||||||
:from "#edit-form"))
|
:from "#edit-form"))
|
||||||
:hx-include "#edit-form"
|
:hx-include "#edit-form"
|
||||||
:hx-vals (hx/vals {:name (cursor-name)})
|
:hx-vals (hx/vals {:name (fc/field-name)})
|
||||||
:hx-ext "rename-params"
|
:hx-ext "rename-params"
|
||||||
:hx-rename-params-ex (hx/json {"transaction-rule/client" "client-id"
|
:hx-rename-params-ex (hx/json {"transaction-rule/client" "client-id"
|
||||||
account-name "account-id"
|
account-name "account-id"
|
||||||
"name" "name"
|
"name" "name"
|
||||||
(cursor-name) "value"})
|
(fc/field-name) "value"})
|
||||||
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
|
:hx-get (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-location-select)
|
||||||
:hx-swap "innerHTML"}
|
:hx-swap "innerHTML"}
|
||||||
(location-select* {:name (cursor-name)
|
(location-select* {:name (fc/field-name)
|
||||||
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
|
:account-location (:account/location (cond->> (:transaction-rule-account/account @account)
|
||||||
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
|
(nat-int? (:transaction-rule-account/account @account)) (dc/pull (dc/db conn)
|
||||||
'[:account/location])))
|
'[:account/location])))
|
||||||
:client-locations (:client/locations (:transaction-rule/client transaction-rule))
|
:client-locations (:client/locations (:transaction-rule/client transaction-rule))
|
||||||
:value (cursor-value)})]
|
:value (fc/field-value)})]
|
||||||
(com/errors {:errors (cursor-errors)})]
|
(com/errors {:errors (fc/field-errors)})]
|
||||||
))
|
))
|
||||||
(with-cursor (:transaction-rule-account/percentage account)
|
(fc/with-field :transaction-rule-account/percentage
|
||||||
(com/data-grid-cell (com/money-input {:name (cursor-name)
|
(com/data-grid-cell (com/money-input {:name (fc/field-name)
|
||||||
:class "w-16"
|
:class "w-16"
|
||||||
:value (some-> (cursor-value)
|
:value (some-> (fc/field-value)
|
||||||
(* 100 )
|
(* 100 )
|
||||||
(long ))})
|
(long ))})
|
||||||
(com/errors {:errors (cursor-errors)})))))
|
(com/errors {:errors (fc/field-errors)})))))
|
||||||
(com/data-grid-cell
|
(com/data-grid-cell
|
||||||
(com/a-icon-button
|
(com/a-icon-button
|
||||||
{"_" (hiccup/raw "on click halt the event then transition the closest <tr />'s opacity to 0 then remove closest <tr />")
|
{"_" (hiccup/raw "on click halt the event then transition the closest <tr />'s opacity to 0 then remove closest <tr />")
|
||||||
:href "#"}
|
:href "#"}
|
||||||
svg/x))))
|
svg/x))))
|
||||||
|
|
||||||
(defn dialog* [& {:keys [ entity form-params]}]
|
(defn dialog* [& {:keys [ entity form-params form-errors]}]
|
||||||
(com/modal
|
(com/modal
|
||||||
{:modal-class "max-w-4xl"}
|
{:modal-class "max-w-4xl"}
|
||||||
(com/modal-card
|
(com/modal-card
|
||||||
@@ -438,100 +421,102 @@
|
|||||||
form-params)
|
form-params)
|
||||||
[:fieldset {:class "hx-disable" :hx-disinherit "hx-target"}
|
[:fieldset {:class "hx-disable" :hx-disinherit "hx-target"}
|
||||||
|
|
||||||
(with-cursor (cursor/cursor entity)
|
(fc/start-form entity form-errors
|
||||||
[:div.space-y-2
|
[:div.space-y-2
|
||||||
(when-let [id (:db/id entity)]
|
(when-let [id (:db/id entity)]
|
||||||
(com/hidden {:name "db/id"
|
(com/hidden {:name "db/id"
|
||||||
:value id}))
|
:value id}))
|
||||||
(with-cursor (:transaction-rule/client *cursor*)
|
|
||||||
|
(fc/with-field :transaction-rule/client
|
||||||
|
|
||||||
(com/validated-field
|
(com/validated-field
|
||||||
{:label "Client"
|
{:label "Client"
|
||||||
:errors (cursor-errors)}
|
:errors (fc/field-errors)}
|
||||||
[:div.w-96
|
[:div.w-96
|
||||||
(com/typeahead {:name (cursor-name)
|
(com/typeahead {:name (fc/field-name)
|
||||||
:class "w-96"
|
:class "w-96"
|
||||||
:placeholder "Search..."
|
:placeholder "Search..."
|
||||||
:url (bidi/path-for ssr-routes/only-routes :company-search)
|
:url (bidi/path-for ssr-routes/only-routes :company-search)
|
||||||
:id (str "form-client-search")
|
:id (str "form-client-search")
|
||||||
:value (cursor-value)
|
:value (fc/field-value)
|
||||||
:value-fn (some-fn :db/id identity)
|
:value-fn (some-fn :db/id identity)
|
||||||
:content-fn (fn [c] (cond->> c
|
:content-fn (fn [c] (cond->> c
|
||||||
(nat-int? c) (dc/pull (dc/db conn) '[:client/name])
|
(nat-int? c) (dc/pull (dc/db conn) '[:client/name])
|
||||||
true :client/name))})]))
|
true :client/name))})]))
|
||||||
|
|
||||||
|
|
||||||
(with-cursor (:transaction-rule/bank-account *cursor*)
|
(fc/with-field :transaction-rule/bank-account
|
||||||
(com/validated-field {:label "Bank Account"
|
(com/validated-field {:label "Bank Account"
|
||||||
:errors (cursor-errors)}
|
:errors (fc/field-errors)}
|
||||||
[:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead)
|
[:div#bank-account-spot.w-96 {:hx-get (bidi/path-for ssr-routes/only-routes :bank-account-typeahead)
|
||||||
:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
:hx-trigger (hx/trigger-field-change :name "transaction-rule/client"
|
||||||
:from "#edit-form")
|
:from "#edit-form")
|
||||||
:hx-swap "innerHTML"
|
:hx-swap "innerHTML"
|
||||||
:hx-ext "rename-params"
|
:hx-ext "rename-params"
|
||||||
:hx-include "#edit-form"
|
:hx-include "#edit-form"
|
||||||
:hx-vals (hx/vals {:name (cursor-name)})
|
:hx-vals (hx/vals {:name (fc/field-name)})
|
||||||
:hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id"
|
:hx-rename-params-ex (cheshire/generate-string {"transaction-rule/client" "client-id"
|
||||||
"name" "name"})}
|
"name" "name"})}
|
||||||
(bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity))
|
(bank-account-typeahead* {:client-id ((some-fn :db/id identity) (:transaction-rule/client entity))
|
||||||
:name (cursor-name)
|
:name (fc/field-name)
|
||||||
:value (cursor-value)})]))
|
:value (fc/field-value)})]))
|
||||||
|
|
||||||
(with-cursor (:transaction-rule/description *cursor*)
|
(fc/with-field :transaction-rule/description
|
||||||
(com/validated-field {:label "Description"
|
(com/validated-field {:label "Description"
|
||||||
:errors (cursor-errors)}
|
:errors (fc/field-errors)}
|
||||||
(com/text-input {:name (cursor-name)
|
(com/text-input {:name (fc/field-name)
|
||||||
:placeholder "HOME DEPOT"
|
:placeholder "HOME DEPOT"
|
||||||
:class "w-96"
|
:class "w-96"
|
||||||
:value (cursor-value)})))
|
:value (fc/field-value)})))
|
||||||
|
|
||||||
(com/field {:label "Amount"}
|
(com/field {:label "Amount"}
|
||||||
[:div.flex.gap-2
|
[:div.flex.gap-2
|
||||||
(with-cursor (:transaction-rule/amount-gte *cursor*)
|
(fc/with-field :transaction-rule/amount-gte
|
||||||
[:div.flex.flex-col
|
[:div.flex.flex-col
|
||||||
(com/money-input {:name (cursor-name)
|
(com/money-input {:name (fc/field-name)
|
||||||
:placeholder ">="
|
:placeholder ">="
|
||||||
:class "w-24"
|
:class "w-24"
|
||||||
:value (cursor-value)})
|
:value (fc/field-value)})
|
||||||
(com/errors {:errors (cursor-errors)})])
|
(com/errors {:errors (fc/field-errors)})])
|
||||||
(with-cursor (:transaction-rule/amount-lte *cursor*)
|
(fc/with-field :transaction-rule/amount-lte
|
||||||
[:div.flex.flex-col
|
[:div.flex.flex-col
|
||||||
(com/money-input {:name (cursor-name)
|
(com/money-input {:name (fc/field-name)
|
||||||
:placeholder "<="
|
:placeholder "<="
|
||||||
:class "w-24"
|
:class "w-24"
|
||||||
:value (cursor-value)})
|
:value (fc/field-value)})
|
||||||
(com/errors {:errors (cursor-errors)})])])
|
(com/errors {:errors (fc/field-errors)})])])
|
||||||
|
|
||||||
(com/field {:label "Day of month"}
|
(com/field {:label "Day of month"}
|
||||||
[:div.flex.gap-2
|
[:div.flex.gap-2
|
||||||
(with-cursor (:transaction-rule/dom-gte *cursor*)
|
(fc/with-field :transaction-rule/dom-gte
|
||||||
[:div.flex.flex-col
|
[:div.flex.flex-col
|
||||||
(com/int-input {:name (cursor-name)
|
(com/int-input {:name (fc/field-name)
|
||||||
:placeholder ">="
|
:placeholder ">="
|
||||||
:class "w-24"
|
:class "w-24"
|
||||||
:value (cursor-value)})
|
:value (fc/field-value)})
|
||||||
(com/errors {:errors (cursor-errors)})])
|
(com/errors {:errors (fc/field-errors)})])
|
||||||
(with-cursor (:transaction-rule/dom-lte *cursor*)
|
(fc/with-field :transaction-rule/dom-lte
|
||||||
[:div.flex.flex-col
|
[:div.flex.flex-col
|
||||||
(com/int-input {:name (cursor-name)
|
(com/int-input {:name (fc/field-name)
|
||||||
:placeholder ">="
|
:placeholder ">="
|
||||||
:class "w-24"
|
:class "w-24"
|
||||||
:value (cursor-value)})
|
:value (fc/field-value)})
|
||||||
(com/errors {:errors (cursor-errors)})])])
|
(com/errors {:errors (fc/field-errors)})])])
|
||||||
|
|
||||||
[:h2.text-lg "Outcomes"]
|
[:h2.text-lg "Outcomes"]
|
||||||
(with-cursor (:transaction-rule/vendor *cursor*)
|
(fc/with-field :transaction-rule/vendor
|
||||||
(com/validated-field {:label "Assign Vendor"
|
(com/validated-field {:label "Assign Vendor"
|
||||||
:errors (cursor-errors)}
|
:errors (fc/field-errors)}
|
||||||
[:div.w-96
|
[:div.w-96
|
||||||
(com/typeahead {:name (cursor-name)
|
(com/typeahead {:name (fc/field-name)
|
||||||
:placeholder "Search..."
|
:placeholder "Search..."
|
||||||
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
|
:url (bidi/path-for ssr-routes/only-routes :vendor-search)
|
||||||
:id (str "form-vendor-search")
|
:id (str "form-vendor-search")
|
||||||
:value (cursor-value)
|
:value (fc/field-value)
|
||||||
:value-fn (some-fn :db/id identity)
|
:value-fn (some-fn :db/id identity)
|
||||||
:content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})]))
|
:content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})]))
|
||||||
|
|
||||||
(with-cursor (:transaction-rule/accounts *cursor*)
|
(fc/with-field :transaction-rule/accounts
|
||||||
(list
|
(list
|
||||||
(com/data-grid {:headers [(com/data-grid-header {}
|
(com/data-grid {:headers [(com/data-grid-header {}
|
||||||
"Account")
|
"Account")
|
||||||
@@ -539,10 +524,11 @@
|
|||||||
(com/data-grid-header {:class "w-16"} "%")
|
(com/data-grid-header {:class "w-16"} "%")
|
||||||
(com/data-grid-header {:class "w-16"})]
|
(com/data-grid-header {:class "w-16"})]
|
||||||
:id "transaction-rule-account-table"}
|
:id "transaction-rule-account-table"}
|
||||||
(for [tra *cursor*]
|
(when @fc/*current*
|
||||||
(with-cursor tra
|
(doall (for [tra fc/*current*]
|
||||||
(transaction-rule-account-row* entity tra))))
|
(fc/with-cursor tra
|
||||||
(com/errors {:errors (cursor-errors)})))
|
(transaction-rule-account-row* entity tra))))))
|
||||||
|
(com/errors {:errors (fc/field-errors)})))
|
||||||
(com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
(com/a-button {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
:admin-transaction-rule-new-account)
|
:admin-transaction-rule-new-account)
|
||||||
:hx-include "#edit-form"
|
:hx-include "#edit-form"
|
||||||
@@ -553,36 +539,41 @@
|
|||||||
:hx-target "#transaction-rule-account-table tbody"
|
:hx-target "#transaction-rule-account-table tbody"
|
||||||
:hx-swap "beforeend"}
|
:hx-swap "beforeend"}
|
||||||
"New account")
|
"New account")
|
||||||
(with-cursor (:transaction-rule/transaction-approval-status *cursor*)
|
(fc/with-field :transaction-rule/transaction-approval-status
|
||||||
(com/radio {:options (ref->radio-options "transaction-approval-status")
|
(com/validated-field {:label "Approval status"
|
||||||
:value (cursor-value)
|
:errors (fc/field-errors)}
|
||||||
:name (cursor-name)}))
|
(com/radio {:options (ref->radio-options "transaction-approval-status")
|
||||||
|
:value (fc/field-value)
|
||||||
|
:name (fc/field-name)})))
|
||||||
|
|
||||||
[:div#form-errors [:span.error-content
|
[:div#form-errors [:span.error-content
|
||||||
(com/errors {:errors (:errors (meta entity))})]]
|
(com/errors {:errors (:errors fc/*form-errors*)})]]
|
||||||
(com/button {:color :primary :form "edit-form" :type "submit"}
|
(com/button {:color :primary :form "edit-form" :type "submit"}
|
||||||
"Save")])]]
|
"Save")])]]
|
||||||
[:div])))
|
[:div])))
|
||||||
|
|
||||||
(defn new-account [{{:keys [client-id index]} :query-params}]
|
(defn new-account [{{:keys [client-id index]} :query-params}]
|
||||||
(let [transaction-rule {:transaction-rule/client (dc/pull (dc/db conn) '[:client/name :client/locations :db/id]
|
(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)
|
client-id)
|
||||||
:transaction-rule/accounts (conj (into [] (repeat (inc index) {} ))
|
:transaction-rule/accounts (conj (into [] (repeat (inc index) {} ))
|
||||||
{:db/id (str (java.util.UUID/randomUUID))
|
{:db/id (str (java.util.UUID/randomUUID))
|
||||||
:transaction-rule-account/location "Shared"})}]
|
:transaction-rule-account/location "Shared"})}]
|
||||||
(html-response
|
(html-response
|
||||||
(with-cursor (cursor/cursor transaction-rule)
|
(fc/start-form transaction-rule []
|
||||||
(with-cursor (:transaction-rule/accounts *cursor*)
|
(fc/with-cursor (get-in fc/*current* [:transaction-rule/accounts index])
|
||||||
(with-cursor (nth *cursor* index)
|
(transaction-rule-account-row*
|
||||||
(transaction-rule-account-row*
|
;; TODO store a pointer to the "head " cursor for errors instead of nesting them
|
||||||
;; TODO store a pointer to the "head " cursor for errors instead of nesting them
|
;; makes it so you don't have to do this
|
||||||
;; makes it so you don't have to do this
|
transaction-rule
|
||||||
transaction-rule
|
fc/*current*))))))
|
||||||
*cursor*
|
|
||||||
)))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; TODO check to see if it should be called "Shared" or "shared" for the value
|
;; TODO check to see if it should be called "Shared" or "shared" for the value
|
||||||
|
;; TODO blank location is being allowed
|
||||||
|
;; TODO hydrate nested types more easily. make it easy to hydrate so you don't do weird sometimes pulls
|
||||||
|
;; TODO is it possible to make it easy to get a virtual cursor in the case of adding a new row? setting up
|
||||||
|
;; fake data doesn't feel right - maybe have a "prelude" that's dynamic
|
||||||
|
|
||||||
(defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}]
|
(defn location-select [{{:keys [name account-id client-id value] :as qp} :query-params}]
|
||||||
(html-response (location-select* {:name name
|
(html-response (location-select* {:name name
|
||||||
@@ -613,15 +604,22 @@
|
|||||||
|
|
||||||
(defn transaction-rule-error [request]
|
(defn transaction-rule-error [request]
|
||||||
(let [entity (some-> request :last-form)]
|
(let [entity (some-> request :last-form)]
|
||||||
(html-response (dialog* :entity entity)
|
(html-response (dialog* :entity entity
|
||||||
|
:form-errors (:form-errors request)
|
||||||
|
:form-params (if (:db/id entity)
|
||||||
|
{:hx-put (str (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-transaction-rule-edit-save))}
|
||||||
|
{:hx-post (str (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-transaction-rule-edit-save))}))
|
||||||
:headers {"hx-retarget" "#edit-form fieldset"
|
:headers {"hx-retarget" "#edit-form fieldset"
|
||||||
"hx-reselect" "#edit-form fieldset"})))
|
"hx-reselect" "#edit-form fieldset"})))
|
||||||
|
|
||||||
|
|
||||||
(defn account-new-dialog [_]
|
(defn transaction-rule-new-dialog [_]
|
||||||
(html-response (dialog* :account nil
|
(html-response (dialog* :entity {}
|
||||||
|
:form-errors {}
|
||||||
:form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
:form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
||||||
:admin-account-new-save))})
|
:admin-transaction-rule-edit-save))})
|
||||||
:headers {"hx-trigger" "modalOpening"}))
|
:headers {"hx-trigger" "modalOpening"}))
|
||||||
|
|
||||||
(def transaction-rule-schema (mc/schema
|
(def transaction-rule-schema (mc/schema
|
||||||
@@ -653,7 +651,8 @@
|
|||||||
(wrap-schema-decode :query-schema [:map
|
(wrap-schema-decode :query-schema [:map
|
||||||
[:client-id {:optional true}
|
[:client-id {:optional true}
|
||||||
[:maybe entity-id]]
|
[:maybe entity-id]]
|
||||||
[:index nat-int?]])
|
[:index {:optional true
|
||||||
|
:default 0} [nat-int? {:default 0}]]])
|
||||||
wrap-admin wrap-client-redirect-unauthenticated)
|
wrap-admin wrap-client-redirect-unauthenticated)
|
||||||
:admin-transaction-rule-location-select (-> location-select
|
:admin-transaction-rule-location-select (-> location-select
|
||||||
(wrap-schema-decode :query-schema [:map
|
(wrap-schema-decode :query-schema [:map
|
||||||
@@ -675,7 +674,7 @@
|
|||||||
(wrap-form-4xx-2 transaction-rule-error))
|
(wrap-form-4xx-2 transaction-rule-error))
|
||||||
:admin-transaction-rule-edit-dialog (-> transaction-rule-edit-dialog
|
:admin-transaction-rule-edit-dialog (-> transaction-rule-edit-dialog
|
||||||
(wrap-schema-decode :route-schema [:map [:db/id entity-id]]))
|
(wrap-schema-decode :route-schema [:map [:db/id entity-id]]))
|
||||||
:admin-transaction-rule-new-dialog account-new-dialog})
|
:admin-transaction-rule-new-dialog transaction-rule-new-dialog})
|
||||||
(fn [h]
|
(fn [h]
|
||||||
(-> h
|
(-> h
|
||||||
(wrap-admin)
|
(wrap-admin)
|
||||||
|
|||||||
@@ -123,7 +123,9 @@ c.clearChoices();
|
|||||||
:key (:error-key params)}))])
|
:key (:error-key params)}))])
|
||||||
|
|
||||||
(defn errors- [{:keys [errors]}]
|
(defn errors- [{:keys [errors]}]
|
||||||
[:p.mt-2.text-xs.text-red-600.dark:text-red-500.h-4 (str/join ", " errors)])
|
[:p.mt-2.text-xs.text-red-600.dark:text-red-500.h-4
|
||||||
|
(when (sequential? errors)
|
||||||
|
(str/join ", " (filter string? errors)))])
|
||||||
|
|
||||||
(defn validated-field- [params & rest]
|
(defn validated-field- [params & rest]
|
||||||
(field- (dissoc params :errors)
|
(field- (dissoc params :errors)
|
||||||
|
|||||||
38
src/clj/auto_ap/ssr/form_cursor.clj
Normal file
38
src/clj/auto_ap/ssr/form_cursor.clj
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
(ns auto-ap.ssr.form-cursor
|
||||||
|
(:require [auto-ap.ssr.utils :refer [path->name2]]
|
||||||
|
[auto-ap.cursor :as cursor]))
|
||||||
|
|
||||||
|
(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*)]
|
||||||
|
~@rest)))
|
||||||
|
|
||||||
|
(defmacro with-cursor [cursor & rest]
|
||||||
|
`(binding [*current* ~cursor]
|
||||||
|
~@rest))
|
||||||
|
|
||||||
|
(defmacro with-field [field & rest]
|
||||||
|
`(with-cursor (get *current* ~field )
|
||||||
|
~@rest))
|
||||||
|
|
||||||
|
(defn field-name
|
||||||
|
([] (field-name *current*))
|
||||||
|
([cursor]
|
||||||
|
(apply path->name2 (cursor/path cursor))))
|
||||||
|
|
||||||
|
(defn field-value []
|
||||||
|
@*current*)
|
||||||
|
|
||||||
|
(defn field-errors
|
||||||
|
([]
|
||||||
|
(field-errors *current*))
|
||||||
|
([cursor]
|
||||||
|
(get-in *form-errors* (cursor/path cursor))))
|
||||||
|
|
||||||
|
|
||||||
@@ -151,8 +151,7 @@
|
|||||||
|
|
||||||
(defn field-validation-error [m path & {:as data}]
|
(defn field-validation-error [m path & {:as data}]
|
||||||
(throw+ (ex-info m (merge data {:type :field-validation
|
(throw+ (ex-info m (merge data {:type :field-validation
|
||||||
:field-validation-errors [{:path path
|
:form-errors (assoc-in {} path [m])}))))
|
||||||
:message [m]}]}))))
|
|
||||||
|
|
||||||
(defn form-validation-error [m & {:as data}]
|
(defn form-validation-error [m & {:as data}]
|
||||||
(throw+ (ex-info m (merge data {:type :form-validation
|
(throw+ (ex-info m (merge data {:type :form-validation
|
||||||
@@ -164,7 +163,8 @@
|
|||||||
(mt2/key-transformer {:encode keyword->str :decode str->keyword})
|
(mt2/key-transformer {:encode keyword->str :decode str->keyword})
|
||||||
mt2/string-transformer
|
mt2/string-transformer
|
||||||
mt2/json-transformer
|
mt2/json-transformer
|
||||||
(mt2/transformer {:name :arbitrary})))
|
(mt2/transformer {:name :arbitrary})
|
||||||
|
mt2/default-value-transformer))
|
||||||
|
|
||||||
(defn wrap-schema-decode [handler & {:keys [form-schema query-schema route-schema params-schema]}]
|
(defn wrap-schema-decode [handler & {:keys [form-schema query-schema route-schema params-schema]}]
|
||||||
(fn [{:keys [form-params query-params params] :as request}]
|
(fn [{:keys [form-params query-params params] :as request}]
|
||||||
@@ -290,18 +290,20 @@
|
|||||||
(:errors (:explain (:error e))))]
|
(:errors (:explain (:error e))))]
|
||||||
(alog/warn ::form-4xx :errors errors)
|
(alog/warn ::form-4xx :errors errors)
|
||||||
(form-handler (assoc request
|
(form-handler (assoc request
|
||||||
:last-form (assoc-errors-into-meta (:decoded e) errors)
|
:last-form (:decoded e)
|
||||||
:field-validation-errors errors)))
|
:field-validation-errors errors
|
||||||
|
:form-errors humanized)))
|
||||||
#_(html-response [:span.error-content.text-red-500 (:message &throw-context)]
|
#_(html-response [:span.error-content.text-red-500 (:message &throw-context)]
|
||||||
:status 400))
|
:status 400))
|
||||||
(catch [:type :field-validation] e
|
(catch [:type :field-validation] e
|
||||||
(form-handler (assoc request
|
(form-handler (assoc request
|
||||||
:last-form (assoc-errors-into-meta (:form e) (:field-validation-errors e))
|
:last-form (:form e)
|
||||||
:field-validation-errors (:field-validation-errors e))))
|
:form-errors (:form-errors e))))
|
||||||
(catch [:type :form-validation] e
|
(catch [:type :form-validation] e
|
||||||
(form-handler (assoc request
|
(form-handler (assoc request
|
||||||
:last-form (with-meta (:form e) {:errors (:form-validation-errors e)})
|
:last-form (:form e)
|
||||||
:form-validation-errors (:form-validation-errors e)))))))
|
:form-validation-errors (:form-validation-errors e)
|
||||||
|
:form-errors {:errors (:form-validation-errors e)}))))))
|
||||||
|
|
||||||
|
|
||||||
(defn apply-middleware-to-all-handlers [key->handler f]
|
(defn apply-middleware-to-all-handlers [key->handler f]
|
||||||
|
|||||||
Reference in New Issue
Block a user