lots of progress

This commit is contained in:
2023-10-24 11:52:55 -07:00
parent 91f7e79aed
commit a8cce0377d
9 changed files with 170 additions and 155 deletions

View File

@@ -767,6 +767,14 @@
(dc/db conn) (dc/db conn)
codes)))) codes))))
(defn get-square-client-and-location [code]
(let [[client] (get-square-clients code)]
(some->> client
:client/square-locations
(filter :square-location/client-location)
seq
(conj [client]))))
(defn upsert-locations (defn upsert-locations
([] ([]
(apply de/zip (apply de/zip

View File

@@ -27,6 +27,7 @@
field-validation-error field-validation-error
form-validation-error form-validation-error
html-response html-response
main-transformer
many-entity many-entity
ref->enum-schema ref->enum-schema
ref->select-options ref->select-options
@@ -263,10 +264,7 @@
:url (bidi/path-for ssr-routes/only-routes :url (bidi/path-for ssr-routes/only-routes
:company-search) :company-search)
:value (fc/field-value) :value (fc/field-value)
:value-fn (some-fn :db/id identity) ;; TODO better hydration :content-fn #(pull-attr (dc/db conn) :client/name %)}))))
:content-fn (fn [value]
(:client/name (cond->> value
(nat-int? value) (dc/pull (dc/db conn) [:client/name]))))}))))
(fc/with-field :account-client-override/name (fc/with-field :account-client-override/name
(com/data-grid-cell (com/data-grid-cell
{} {}
@@ -298,14 +296,14 @@
:hx-target "this"} :hx-target "this"}
(com/modal (com/modal
{} {}
[:form#edit-form (-> {:hx-ext "response-targets" [:form (-> {:hx-ext "response-targets"
:hx-swap "outerHTML swap:300ms" :hx-swap "outerHTML swap:300ms"
:hx-target-400 "#form-errors .error-content"} :hx-target-400 "#form-errors .error-content"}
(assoc (if (:db/id entity) (assoc (if (:db/id entity)
:hx-put :hx-put
:hx-post) :hx-post)
(str (bidi/path-for ssr-routes/only-routes (str (bidi/path-for ssr-routes/only-routes
:admin-transaction-rule-edit-save)))) :admin-transaction-rule-edit-save))))
[:fieldset {:class "hx-disable"} [:fieldset {:class "hx-disable"}
(com/modal-card (com/modal-card
{} {}
@@ -323,7 +321,7 @@
(com/validated-field {:label "Numeric code" (com/validated-field {:label "Numeric code"
:errors (fc/field-errors)} :errors (fc/field-errors)}
(com/text-input {:name (fc/field-name) (com/text-input {:name (fc/field-name)
:value (fc/field-value) :value (fc/field-value)
:x-model "accountCode" :x-model "accountCode"
:autofocus true :autofocus true
:class "w-32"})) :class "w-32"}))
@@ -382,13 +380,13 @@
(com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid {:headers [(com/data-grid-header {} "Client")
(com/data-grid-header {} "Account name") (com/data-grid-header {} "Account name")
(com/data-grid-header {})] (com/data-grid-header {})]
:id "client-override-table"} :id "client-override-table"}
(fc/cursor-map (fc/cursor-map
#(client-override* %)) #(client-override* %))
(com/data-grid-new-row {:colspan 3 (com/data-grid-new-row {:colspan 3
:index (count (fc/field-value)) :index (count (fc/field-value))
:hx-get (bidi/path-for ssr-routes/only-routes :hx-get (bidi/path-for ssr-routes/only-routes
:admin-account-client-override-new)} :admin-account-client-override-new)}
"New override")))) "New override"))))
@@ -407,17 +405,7 @@
[] []
(client-override* fc/*current*)))) (client-override* fc/*current*))))
(defn account-dialog [{:keys [entity form-params form-errors]}] (def form-schema (mc/schema
(html-response (dialog* {:entity entity
:form-params (or (when (seq form-params)
form-params)
entity
{})
:form-errors form-errors})
:headers {"hx-trigger" "modalopen"}))
(def account-schema (mc/schema
[:map [:map
[:db/id {:optional true} [:maybe entity-id]] [:db/id {:optional true} [:maybe entity-id]]
[:account/numeric-code {:optional true} [:maybe :int]] [:account/numeric-code {:optional true} [:maybe :int]]
@@ -434,6 +422,19 @@
[:account-client-override/client entity-id] [:account-client-override/client entity-id]
[:account-client-override/name [:string {:min 2}]])]]])) [:account-client-override/name [:string {:min 2}]])]]]))
(defn account-dialog [{:keys [entity form-params form-errors]}]
(html-response (dialog* {:entity entity
:form-params (or (when (seq form-params)
form-params)
(when entity
(mc/decode form-schema entity main-transformer))
{})
:form-errors form-errors})
:headers {"hx-trigger" "modalopen"}))
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
(->> (->>
@@ -446,7 +447,7 @@
wrap-admin wrap-client-redirect-unauthenticated) wrap-admin wrap-client-redirect-unauthenticated)
:admin-account-save (-> account-save :admin-account-save (-> account-save
(wrap-entity [:form-params :db/id] default-read) (wrap-entity [:form-params :db/id] default-read)
(wrap-schema-decode :form-schema account-schema) (wrap-schema-decode :form-schema form-schema)
(wrap-nested-form-params) (wrap-nested-form-params)
(wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read)))
:admin-account-edit-dialog (-> account-dialog :admin-account-edit-dialog (-> account-dialog

View File

@@ -184,11 +184,11 @@
(defn job-start-dialog [_] (defn job-start-dialog [_]
(html-response (com/modal (html-response (com/modal
{:modal-class "max-w-4xl"} {:modal-class "max-w-4xl"}
[:form#edit-form {:hx-ext "response-targets" [:form {:hx-ext "response-targets"
:hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start
) )
:hx-swap "outerHTML swap:300ms" :hx-swap "outerHTML swap:300ms"
:hx-target-400 "#form-errors .error-content"} :hx-target-400 "#form-errors .error-content"}
[:fieldset {:class "hx-disable"} [:fieldset {:class "hx-disable"}
(com/modal-card (com/modal-card
{} {}
@@ -199,18 +199,18 @@
(com/select {:name "name" (com/select {:name "name"
:class "w-64" :class "w-64"
:options [["" ""] :options [["" ""]
["yodlee2" "Yodlee Import"] ["yodlee2" "Yodlee Import"]
["yodlee2-accounts" "Yodlee Account Import"] ["yodlee2-accounts" "Yodlee Account Import"]
["intuit" "Intuit import"] ["intuit" "Intuit import"]
["plaid" "Plaid import"] ["plaid" "Plaid import"]
["bulk-journal-import" "Bulk Journal Import"] ["bulk-journal-import" "Bulk Journal Import"]
["square2-import-job" "Square2 Import"] ["square2-import-job" "Square2 Import"]
["register-invoice-import" "Register Invoice Import "] ["register-invoice-import" "Register Invoice Import "]
["ezcater-upsert" "Upsert recent ezcater orders"] ["ezcater-upsert" "Upsert recent ezcater orders"]
["load-historical-sales" "Load Historical Square Sales"] ["load-historical-sales" "Load Historical Square Sales"]
["export-backup" "Export Backup"]] ["export-backup" "Export Backup"]]
:hx-get (bidi/path-for ssr-routes/only-routes :hx-get (bidi/path-for ssr-routes/only-routes
:admin-job-subform) :admin-job-subform)
:hx-target "#sub-form" :hx-target "#sub-form"
:hx-swap "innerHTML"})) :hx-swap "innerHTML"}))

View File

@@ -29,6 +29,7 @@
field-validation-error field-validation-error
form-validation-error form-validation-error
html-response html-response
main-transformer
many-entity many-entity
money money
percentage percentage
@@ -66,8 +67,9 @@
:url (bidi/path-for ssr-routes/only-routes :url (bidi/path-for ssr-routes/only-routes
:vendor-search) :vendor-search)
:id (str "vendor-search") :id (str "vendor-search")
:value [(:db/id (:vendor (:parsed-query-params request))) :value (:vendor (:parsed-query-params request))
(:vendor/name (:vendor (:parsed-query-params request)))]})) :value-fn :db/id
:content-fn :vendor/name}))
(com/field {:label "Note"} (com/field {:label "Note"}
(com/text-input {:name "note" (com/text-input {:name "note"
:id "note" :id "note"
@@ -330,12 +332,11 @@
:id name :id name
:x-model x-model :x-model x-model
:value value :value value
:value-fn (some-fn :db/id identity)
:content-fn (fn [value] :content-fn (fn [value]
(:account/name (d-accounts/clientize (cond->> value (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value)
(nat-int? value) (dc/pull (dc/db conn) d-accounts/default-read))
client-id)))})]) client-id)))})])
;; TODO something is making the accountId not change the location for only existing ones?
(defn- transaction-rule-account-row* (defn- transaction-rule-account-row*
[transaction-rule account] [transaction-rule account]
(com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account))) (com/data-grid-row (-> {:x-data (hx/json {:accountId (or (:db/id (fc/field-value (:transaction-rule-account/account account)))
@@ -363,8 +364,7 @@
(account-typeahead* {:value (fc/field-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 (fc/field-name) :name (fc/field-name)
:x-model "accountId" :x-model "accountId"}))))
}))))
(fc/with-field :transaction-rule-account/location (fc/with-field :transaction-rule-account/location
(com/data-grid-cell (com/data-grid-cell
{} {}
@@ -396,22 +396,21 @@
(com/data-grid-cell {:class "align-top"} (com/data-grid-cell {:class "align-top"}
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
;; TODO dialog is no longer closeable ;; TODO background jobs and company 1099
;; TODO might not need #edit-form id
(defn dialog* [{:keys [entity form-params form-errors]}] (defn dialog* [{:keys [entity form-params form-errors]}]
(fc/start-form form-params form-errors (fc/start-form form-params form-errors
(com/modal (com/modal
{:modal-class "max-w-2xl" {:modal-class "max-w-2xl"
:hx-target "this"} :hx-target "this"}
[:form#edit-form {:hx-ext "response-targets" [:form {:hx-ext "response-targets"
:hx-swap "outerHTML swap:300ms" :hx-swap "outerHTML swap:300ms"
:hx-target-400 "#form-errors .error-content" :hx-target-400 "#form-errors .error-content"
:x-trap "true" :x-trap "true"
:class "group/form" :class "group/form"
(if (:db/id entity) (if (:db/id entity)
:hx-put :hx-put
:hx-post) (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))}
(com/modal-card (com/modal-card
{} {}
[:div.flex [:div.p-2 "Transaction Rule"]] [:div.flex [:div.p-2 "Transaction Rule"]]
@@ -465,10 +464,7 @@
:url (bidi/path-for ssr-routes/only-routes :company-search) :url (bidi/path-for ssr-routes/only-routes :company-search)
:x-model "clientId" :x-model "clientId"
:value (fc/field-value) :value (fc/field-value)
:value-fn (some-fn :db/id identity) :content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))})]))
:content-fn (fn [c] (cond->> c
(nat-int? c) (dc/pull (dc/db conn) '[:client/name])
true :client/name))})]))
(fc/with-field :transaction-rule/bank-account (fc/with-field :transaction-rule/bank-account
(com/validated-field (com/validated-field
@@ -536,11 +532,9 @@
(com/typeahead-2 {:name (fc/field-name) (com/typeahead-2 {: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")
:class "w-96" :class "w-96"
:value (fc/field-value) :value (fc/field-value)
:value-fn (some-fn :db/id identity) :content-fn #(pull-attr (dc/db conn) :vendor/name %)})]))
:content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})]))
(fc/with-field :transaction-rule/accounts (fc/with-field :transaction-rule/accounts
(com/validated-field (com/validated-field
@@ -573,11 +567,6 @@
(com/validated-save-button {:errors (:errors form-errors)} "Save rule")])]))) (com/validated-save-button {:errors (:errors form-errors)} "Save rule")])])))
;; TODO Should forms have some kind of helper to render an individual field? saving
;; could generate the entire form and swap if there are errors
;; but also when you tab out it could call the same function, and just
;; pull out the single field to swap
(defn new-account [{{:keys [client-id index]} :query-params}] (defn new-account [{{:keys [client-id index]} :query-params}]
(html-response (html-response
(fc/start-form-with-prefix (fc/start-form-with-prefix
@@ -598,16 +587,14 @@
;; 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 hydrate nested types more easily. make it easy to hydrate so you don't do weird sometimes pulls ;; 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
:value value :value value
:account-location (some->> account-id :account-location (some->> account-id
(pull-attr (dc/db conn) :account/location)) (pull-attr (dc/db conn) :account/location))
:client-locations (some->> client-id :client-locations (some->> client-id
(pull-attr (dc/db conn) :client/locations))}))) (pull-attr (dc/db conn) :client/locations))})))
(defn account-typeahead [{{:keys [name value client-id] :as qp} :query-params}] (defn account-typeahead [{{:keys [name value client-id] :as qp} :query-params}]
(let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id (let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id
@@ -619,34 +606,37 @@
:value account :value account
:client-id client-id})))) :client-id client-id}))))
(def form-schema (mc/schema
[:map
[:db/id {:optional true} [:maybe entity-id]]
[:transaction-rule/client {:optional true} [:maybe entity-id]]
[:transaction-rule/description [:and regex
[:string {:min 3}]]]
[:transaction-rule/bank-account [:maybe entity-id]]
[:transaction-rule/amount-gte {:optional true} [:maybe money]]
[:transaction-rule/amount-lte {:optional true} [:maybe money]]
[:transaction-rule/dom-gte {:optional true} [:maybe :int]]
[:transaction-rule/dom-lte {:optional true} [:maybe :int]]
[:transaction-rule/vendor {:optional true} [:maybe entity-id]]
[:transaction-rule/transaction-approval-status (ref->enum-schema "transaction-approval-status")]
[:transaction-rule/accounts
(many-entity {:min 1}
[:db/id [:or entity-id temp-id]]
[:transaction-rule-account/account entity-id]
[:transaction-rule-account/location [:string {:min 1 :error/message "required"}]]
[:transaction-rule-account/percentage percentage])]]))
(defn transaction-dialog [{:keys [entity form-params form-errors]}] (defn transaction-dialog [{:keys [entity form-params form-errors]}]
(html-response (dialog* {:entity entity (html-response (dialog* {:entity entity
:form-params (or (when (seq form-params) :form-params (or (when (seq form-params)
form-params) form-params)
entity ;; TODO coerce into form params (when entity
(mc/decode form-schema entity main-transformer)) ;; TODO coerce into form params
{}) {})
:form-errors form-errors}) :form-errors form-errors})
:headers {"hx-trigger" "modalopen"})) :headers {"hx-trigger" "modalopen"}))
(def transaction-rule-schema (mc/schema
[:map
[:db/id {:optional true} [:maybe entity-id]]
[:transaction-rule/client {:optional true} [:maybe entity-id]]
[:transaction-rule/description [:and regex
[:string {:min 3}]]]
[:transaction-rule/bank-account [:maybe entity-id]]
[:transaction-rule/amount-gte {:optional true} [:maybe money]]
[:transaction-rule/amount-lte {:optional true} [:maybe money]]
[:transaction-rule/dom-gte {:optional true} [:maybe :int]]
[:transaction-rule/dom-lte {:optional true} [:maybe :int]]
[:transaction-rule/vendor {:optional true} [:maybe entity-id]]
[:transaction-rule/transaction-approval-status (ref->enum-schema "transaction-approval-status")]
[:transaction-rule/accounts
(many-entity {:min 1}
[:db/id [:or entity-id temp-id]]
[:transaction-rule-account/account entity-id]
[:transaction-rule-account/location [:string {:min 1 :error/message "required"}]]
[:transaction-rule-account/percentage percentage])]]))
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
@@ -676,10 +666,10 @@
[:maybe entity-id]]])) [:maybe entity-id]]]))
:admin-transaction-rule-save (-> transaction-rule-save :admin-transaction-rule-save (-> transaction-rule-save
(wrap-entity [:form-params :db/id] default-read) (wrap-entity [:form-params :db/id] default-read)
(wrap-schema-decode :form-schema transaction-rule-schema) (wrap-schema-decode :form-schema form-schema)
(wrap-nested-form-params) (wrap-nested-form-params)
(wrap-form-4xx-2 (-> transaction-dialog (wrap-form-4xx-2 (-> transaction-dialog
(wrap-entity [:form-params :db/id] default-read)))) (wrap-entity [:form-params :db/id] default-read))))
:admin-transaction-rule-edit-dialog (-> transaction-dialog :admin-transaction-rule-edit-dialog (-> transaction-dialog
(wrap-entity [:route-params :db/id] default-read) (wrap-entity [:route-params :db/id] default-read)
(wrap-schema-decode :route-schema [:map [:db/id entity-id]])) (wrap-schema-decode :route-schema [:map [:db/id entity-id]]))

View File

@@ -176,7 +176,7 @@
(defn validated-save-button- [{:keys [errors class] :as params} & children] (defn validated-save-button- [{:keys [errors class] :as params} & children]
(button- (-> {:color :primary :form "edit-form" (button- (-> {:color :primary
:type "submit" :class (cond-> (or class "") :type "submit" :class (cond-> (or class "")
true (hh/add-class "w-32") true (hh/add-class "w-32")
(seq errors) (hh/add-class "animate-shake"))} (seq errors) (hh/add-class "animate-shake"))}

View File

@@ -75,11 +75,11 @@ c.clearChoices();
:baseUrl (if (str/includes? (:url params) "?") :baseUrl (if (str/includes? (:url params) "?")
(str (:url params) "&q=") (str (:url params) "&q=")
(str (:url params) "?q=")) (str (:url params) "?q="))
:value {:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))} :value {:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}
:search "" :search ""
:active -1 :active -1
:elements (if ((:value-fn params first) (:value params)) :elements (if ((:value-fn params identity) (:value params))
[{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}]
[])}) [])})
:x-modelable "value.value" :x-modelable "value.value"
:x-model (:x-model params) :x-model (:x-model params)

View File

@@ -38,3 +38,15 @@
alpine-appear alpine-appear
alpine-disappear) alpine-disappear)
(dissoc params :data-key))) (dissoc params :data-key)))
(defn bind-alpine-vals [m field->alpine-field]
(assoc m "x-bind:hx-vals"
(format "JSON.stringify({%s})"
(str/join ", "
(map
(fn [[field alpine-field]]
(format "\"%s\": $data.%s" field alpine-field))
field->alpine-field)))))

View File

@@ -6,6 +6,7 @@
apply-sort-3 apply-sort-3
conn conn
merge-query merge-query
pull-attr
pull-many pull-many
query2]] query2]]
[auto-ap.query-params :as query-params] [auto-ap.query-params :as query-params]
@@ -23,6 +24,7 @@
:refer [apply-middleware-to-all-handlers :refer [apply-middleware-to-all-handlers
entity-id entity-id
html-response html-response
main-transformer
many-entity many-entity
ref->enum-schema ref->enum-schema
ref->select-options ref->select-options
@@ -256,13 +258,11 @@
(def table* (partial helper/table* grid-page)) (def table* (partial helper/table* grid-page))
(defn impersonate [request] (defn impersonate [request]
(println (:entity request))
(if (:entity request) (if (:entity request)
{:status 200 {:status 200
:headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt (:entity request) "FAKE_TOKEN") :headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt (:entity request) "FAKE_TOKEN")
(:jwt-secret env) (:jwt-secret env)
{:alg :hs512})) {:alg :hs512}))}
}
:session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN") :session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN")
:exp)}} :exp)}}
{:status 404})) {:status 404}))
@@ -279,31 +279,27 @@
:url (bidi/path-for ssr-routes/only-routes :url (bidi/path-for ssr-routes/only-routes
:company-search) :company-search)
:value (fc/field-value) :value (fc/field-value)
:value-fn :db/id
:value-fn :db/id ;; TODO better hydration :content-fn #(pull-attr (dc/db conn) :client/name (:db/id %))
:content-fn (fn [value]
(:client/name (dc/pull (dc/db conn) [:client/name]
(or (:db/id value)
value))))
:size :small}))) :size :small})))
(com/data-grid-cell {:class "align-top"} (com/data-grid-cell {:class "align-top"}
(com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x))))
;; TODO hydrate user name
(defn dialog* [{:keys [form-params form-errors entity]}] (defn dialog* [{:keys [form-params form-errors entity]}]
(fc/start-form (fc/start-form
form-params form-errors form-params form-errors
(com/modal (com/modal
{:hx-target "this"} {:hx-target "this"}
[:form#edit-form {:hx-ext "response-targets" [:form {:hx-ext "response-targets"
:hx-put (str (bidi/path-for ssr-routes/only-routes :hx-put (str (bidi/path-for ssr-routes/only-routes
:user-edit-save :user-edit-save
:request-method :put)) :request-method :put))
:hx-swap "outerHTML swap:300ms" :hx-swap "outerHTML swap:300ms"
:hx-target-400 "#form-errors .error-content" :hx-target-400 "#form-errors .error-content"
:class "w-full"} :class "w-full"}
[:fieldset {:class "hx-disable"} [:fieldset {:class "hx-disable"}
(com/modal-card (com/modal-card
{} {}
@@ -321,7 +317,7 @@
:value (some->> (fc/field-value) name) :value (some->> (fc/field-value) name)
:options (ref->select-options "user-role")}))) :options (ref->select-options "user-role")})))
(fc/with-field :user/clients (fc/with-field :user/clients
(com/validated-field {:label "Clients"} (com/validated-field {:label "Clients"}
(com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid {:headers [(com/data-grid-header {} "Client")
(com/data-grid-header {} )] (com/data-grid-header {} )]
:id "client-table"} :id "client-table"}
@@ -336,7 +332,6 @@
(com/validated-save-button {:errors (seq form-errors)} (com/validated-save-button {:errors (seq form-errors)}
"Save user")])]]))) "Save user")])]])))
;; TODO rename edit-form or make it generic
(defn user-edit-save [{:keys [form-params identity] :as request}] (defn user-edit-save [{:keys [form-params identity] :as request}]
(let [_ @(dc/transact conn [[:upsert-entity form-params]]) (let [_ @(dc/transact conn [[:upsert-entity form-params]])
user (some-> form-params :db/id (#(dc/pull (dc/db conn) default-read %)))] user (some-> form-params :db/id (#(dc/pull (dc/db conn) default-read %)))]
@@ -346,18 +341,25 @@
:headers {"hx-trigger" "modalclose" :headers {"hx-trigger" "modalclose"
"hx-retarget" (format "#user-table tr[data-id=\"%d\"]" (:db/id user))}))) "hx-retarget" (format "#user-table tr[data-id=\"%d\"]" (:db/id user))})))
(defn user-save-error [request]
;; TODO hydration
;; TODO consistency of error handling and passing, on all form examples
(html-response (dialog* {:form-params (:form-params request)
:entity (:entity request)
:form-errors (:form-errors request)})))
(defn user-edit-dialog [request] (def form-schema
(mc/schema
[:map
[:db/id entity-id]
[:user/clients {:optional true}
[:maybe
(many-entity {} [:db/id entity-id])]]
[:user/role (ref->enum-schema "user-role")]]))
(defn user-dialog [{:keys [form-params entity form-errors]}]
(html-response (html-response
(dialog* {:form-params (:entity request) (dialog* {:form-params (or (when (seq form-params)
:entity (:entity request) form-params)
:form-errors {}}) (when entity
(mc/decode form-schema entity main-transformer))
{})
:entity entity
:form-errors form-errors})
:headers {"hx-trigger" "modalopen"})) :headers {"hx-trigger" "modalopen"}))
@@ -367,14 +369,7 @@
:new? true} [] :new? true} []
(client-row* fc/*current*)))) (client-row* fc/*current*))))
(def user-form-schema
(mc/schema
[:map
[:db/id entity-id]
[:user/clients {:optional true}
[:maybe
(many-entity {} [:db/id entity-id])]]
[:user/role (ref->enum-schema "user-role")]]))
(def key->handler (def key->handler
(apply-middleware-to-all-handlers (apply-middleware-to-all-handlers
@@ -382,14 +377,14 @@
:user-table (helper/table-route grid-page) :user-table (helper/table-route grid-page)
:user-edit-save (-> user-edit-save :user-edit-save (-> user-edit-save
(wrap-entity [:form-params :db/id] default-read) (wrap-entity [:form-params :db/id] default-read)
(wrap-schema-decode :form-schema user-form-schema) (wrap-schema-decode :form-schema form-schema)
(wrap-nested-form-params) (wrap-nested-form-params)
(wrap-form-4xx-2 (wrap-entity user-save-error [:form-params :db/id] default-read))) (wrap-form-4xx-2 (wrap-entity user-dialog [:form-params :db/id] default-read)))
:user-client-new (-> new-client :user-client-new (-> new-client
(wrap-schema-decode :query-schema [:map (wrap-schema-decode :query-schema [:map
[:index {:optional true [:index {:optional true
:default 0} [nat-int? {:default 0}]]])) :default 0} [nat-int? {:default 0}]]]))
:user-edit-dialog (-> user-edit-dialog :user-edit-dialog (-> user-dialog
(wrap-entity [:route-params :db/id] default-read) (wrap-entity [:route-params :db/id] default-read)
(wrap-schema-decode (wrap-schema-decode
:route-schema (mc/schema [:map [:db/id entity-id]]))) :route-schema (mc/schema [:map [:db/id entity-id]])))

View File

@@ -97,7 +97,11 @@
:long empty->nil :long empty->nil
'nat-int? empty->nil}})) 'nat-int? empty->nil}}))
(def entity-id (mc/schema [nat-int? {:error/message "required"} ])) (def entity-id (mc/schema [nat-int? {:error/message "required"
:decode/arbitrary (fn [e]
(if (and (map? e) (:db/id e))
(:db/id e)
e))} ]))
(def temp-id (mc/schema [:string {:min 1}])) (def temp-id (mc/schema [:string {:min 1}]))
(def money (mc/schema [:double])) (def money (mc/schema [:double]))
@@ -116,15 +120,17 @@
(def map->db-id-decoder (def map->db-id-decoder
{:enter (fn [x] {:enter (fn [x]
(into [] (if (sequential? x)
(for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] x
v (into []
#_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)]
(Long/parseLong k) v
(keyword? k) #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k))
(name k) (Long/parseLong k)
:else (keyword? k)
k)))))}) (name k)
:else
k))))))})
(defn many-entity [params & keys] (defn many-entity [params & keys]
(mc/schema (mc/schema
@@ -219,7 +225,10 @@
(handler request)))) (handler request))))
(defn ref->enum-schema [n] (defn ref->enum-schema [n]
(into [:enum {:decode/string #(keyword n %)}] (into [:enum {:decode/string #(if (keyword? %)
%
(keyword n %)
)}]
(for [{:db/keys [ident]} (all-schema) (for [{:db/keys [ident]} (all-schema)
:when (= n (namespace ident))] :when (= n (namespace ident))]
ident))) ident)))