a lot of streamlining for validation
This commit is contained in:
@@ -31,12 +31,12 @@
|
|||||||
ref->enum-schema
|
ref->enum-schema
|
||||||
ref->select-options
|
ref->select-options
|
||||||
temp-id
|
temp-id
|
||||||
|
wrap-entity
|
||||||
wrap-form-4xx-2
|
wrap-form-4xx-2
|
||||||
wrap-schema-decode]]
|
wrap-schema-decode]]
|
||||||
[bidi.bidi :as bidi]
|
[bidi.bidi :as bidi]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[hiccup2.core :as hiccup]
|
|
||||||
[malli.core :as mc]))
|
[malli.core :as mc]))
|
||||||
|
|
||||||
(defn filters [request]
|
(defn filters [request]
|
||||||
@@ -291,16 +291,21 @@
|
|||||||
;; ensure that adding a new one results in a new row
|
;; ensure that adding a new one results in a new row
|
||||||
|
|
||||||
|
|
||||||
(defn dialog* [& {:keys [entity form-params form-errors]}]
|
(defn dialog* [{:keys [entity form-params form-errors]}]
|
||||||
(fc/start-form entity form-errors
|
(fc/start-form form-params form-errors
|
||||||
[:div {:x-data (hx/json {"accountName" (:account/name entity)
|
[:div {:x-data (hx/json {"accountName" (or (:account/name form-params) (:account/numeric-code entity))
|
||||||
"accountCode" (:account/numeric-code entity)})}
|
"accountCode" (or (:account/numeric-code form-params) (:account/numeric-code entity) )})
|
||||||
|
:hx-target "this"}
|
||||||
(com/modal
|
(com/modal
|
||||||
{}
|
{}
|
||||||
[:form#edit-form (merge {:hx-ext "response-targets"
|
[:form#edit-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"}
|
||||||
form-params)
|
(assoc (if (:db/id entity)
|
||||||
|
:hx-put
|
||||||
|
:hx-post)
|
||||||
|
(str (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-transaction-rule-edit-save))))
|
||||||
[:fieldset {:class "hx-disable"}
|
[:fieldset {:class "hx-disable"}
|
||||||
(com/modal-card
|
(com/modal-card
|
||||||
{}
|
{}
|
||||||
@@ -318,6 +323,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)
|
||||||
:x-model "accountCode"
|
:x-model "accountCode"
|
||||||
:autofocus true
|
:autofocus true
|
||||||
:class "w-32"}))
|
:class "w-32"}))
|
||||||
@@ -388,9 +394,7 @@
|
|||||||
|
|
||||||
]
|
]
|
||||||
[:div
|
[:div
|
||||||
[:div [:div#form-errors (when (:errors fc/*form-errors*)
|
(com/form-errors {:errors (:errors fc/*form-errors*)})
|
||||||
[:span.error-content
|
|
||||||
(com/errors {:errors (:errors fc/*form-errors*)})])]]
|
|
||||||
(com/validated-save-button {:errors (seq form-errors)}
|
(com/validated-save-button {:errors (seq form-errors)}
|
||||||
"Save account")])]])]))
|
"Save account")])]])]))
|
||||||
|
|
||||||
@@ -403,34 +407,15 @@
|
|||||||
[]
|
[]
|
||||||
(client-override* fc/*current*))))
|
(client-override* fc/*current*))))
|
||||||
|
|
||||||
(defn account-edit-dialog [request]
|
(defn account-dialog [{:keys [entity form-params form-errors]}]
|
||||||
(let [account (some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %)))]
|
(html-response (dialog* {:entity entity
|
||||||
(html-response (dialog* :entity account
|
:form-params (or (when (seq form-params)
|
||||||
:form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes
|
form-params)
|
||||||
:admin-account-edit-save))})
|
entity
|
||||||
:headers {"hx-trigger" "modalopen"})))
|
{})
|
||||||
|
:form-errors form-errors})
|
||||||
|
|
||||||
(defn account-new-dialog [_]
|
|
||||||
(html-response (dialog* :entity {}
|
|
||||||
:form-errors {}
|
|
||||||
:form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
|
||||||
:admin-account-new-save))})
|
|
||||||
:headers {"hx-trigger" "modalopen"}))
|
:headers {"hx-trigger" "modalopen"}))
|
||||||
|
|
||||||
(defn account-save-error [request]
|
|
||||||
;; TODO hydration
|
|
||||||
;; TODO consistency of error handling and passing, on all form examples
|
|
||||||
(let [entity (some-> request :last-form)]
|
|
||||||
(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"
|
|
||||||
"hx-reselect" "#edit-form fieldset"})))
|
|
||||||
|
|
||||||
(def account-schema (mc/schema
|
(def account-schema (mc/schema
|
||||||
[:map
|
[:map
|
||||||
@@ -439,14 +424,14 @@
|
|||||||
[:account/name [:string {:min 1}]]
|
[:account/name [:string {:min 1}]]
|
||||||
[:account/location [:maybe :string]]
|
[:account/location [:maybe :string]]
|
||||||
[:account/type (ref->enum-schema "account-type")]
|
[:account/type (ref->enum-schema "account-type")]
|
||||||
[:account/applicability (ref->enum-schema "account-applicability")]
|
[:account/applicability (ref->enum-schema "account-applicability")] ;
|
||||||
[:account/invoice-allowance (ref->enum-schema "allowance")]
|
[:account/invoice-allowance (ref->enum-schema "allowance")]
|
||||||
[:account/vendor-allowance (ref->enum-schema "allowance")]
|
[:account/vendor-allowance (ref->enum-schema "allowance")]
|
||||||
[:account/client-overrides {:optional true}
|
[:account/client-overrides {:optional true}
|
||||||
[:maybe
|
[:maybe
|
||||||
(many-entity {}
|
(many-entity {}
|
||||||
[:db/id [:or entity-id temp-id]]
|
[:db/id [:or entity-id temp-id]]
|
||||||
[:account-client-override/client [:or entity-id :string]]
|
[:account-client-override/client entity-id]
|
||||||
[:account-client-override/name [:string {:min 2}]])]]]))
|
[:account-client-override/name [:string {:min 2}]])]]]))
|
||||||
|
|
||||||
(def key->handler
|
(def key->handler
|
||||||
@@ -460,12 +445,14 @@
|
|||||||
:default 0} [nat-int? {:default 0}]]])
|
:default 0} [nat-int? {:default 0}]]])
|
||||||
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-schema-decode :form-schema account-schema)
|
(wrap-schema-decode :form-schema account-schema)
|
||||||
(wrap-nested-form-params)
|
(wrap-nested-form-params)
|
||||||
(wrap-form-4xx-2 account-save-error))
|
(wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read)))
|
||||||
:admin-account-edit-dialog (-> account-edit-dialog
|
:admin-account-edit-dialog (-> account-dialog
|
||||||
|
(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]]))
|
||||||
:admin-account-new-dialog account-new-dialog})
|
:admin-account-new-dialog account-dialog})
|
||||||
(fn [h]
|
(fn [h]
|
||||||
(-> h
|
(-> h
|
||||||
(wrap-admin)
|
(wrap-admin)
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
[auto-ap.ssr-routes :as ssr-routes]
|
[auto-ap.ssr-routes :as ssr-routes]
|
||||||
[auto-ap.ssr.company :refer [bank-account-typeahead*]]
|
[auto-ap.ssr.company :refer [bank-account-typeahead*]]
|
||||||
[auto-ap.ssr.components :as com]
|
[auto-ap.ssr.components :as com]
|
||||||
|
[auto-ap.ssr.form-cursor :as fc]
|
||||||
[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
|
||||||
@@ -31,24 +31,20 @@
|
|||||||
html-response
|
html-response
|
||||||
many-entity
|
many-entity
|
||||||
money
|
money
|
||||||
path->name2
|
|
||||||
percentage
|
percentage
|
||||||
ref->enum-schema
|
ref->enum-schema
|
||||||
ref->radio-options
|
ref->radio-options
|
||||||
regex
|
regex
|
||||||
temp-id
|
temp-id
|
||||||
|
wrap-entity
|
||||||
wrap-form-4xx-2
|
wrap-form-4xx-2
|
||||||
wrap-schema-decode]]
|
wrap-schema-decode]]
|
||||||
[auto-ap.utils :refer [dollars=]]
|
[auto-ap.utils :refer [dollars=]]
|
||||||
[bidi.bidi :as bidi]
|
[bidi.bidi :as bidi]
|
||||||
[cheshire.core :as cheshire]
|
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[hiccup2.core :as hiccup]
|
|
||||||
[iol-ion.query :refer [ident]]
|
[iol-ion.query :refer [ident]]
|
||||||
[malli.core :as mc]
|
[malli.core :as mc]))
|
||||||
[auto-ap.cursor :as cursor]
|
|
||||||
[auto-ap.ssr.hiccup-helper :as hh]))
|
|
||||||
|
|
||||||
;; TODO with dependencies, I really don't like that you have to be ultra specific in what
|
;; TODO with dependencies, I really don't like that you have to be ultra specific in what
|
||||||
;; you want to include, and generating the routes and interconnection is weird too.
|
;; you want to include, and generating the routes and interconnection is weird too.
|
||||||
@@ -401,25 +397,29 @@
|
|||||||
(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 dialog is no longer closeable
|
||||||
(defn dialog* [& {:keys [entity form-params form-errors]}]
|
;; TODO might not need #edit-form id
|
||||||
(fc/start-form entity form-errors
|
(defn dialog* [{:keys [entity 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"}
|
||||||
|
|
||||||
[:form#edit-form (merge {:hx-ext "response-targets"
|
[:form#edit-form {:hx-ext "response-targets"
|
||||||
:hx-swap "outerHTML swap:300ms"
|
:hx-swap "outerHTML swap:300ms"
|
||||||
:hx-target "#modal-holder" ;; TODO sort
|
: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)
|
||||||
form-params)
|
:hx-put
|
||||||
|
: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"]]
|
||||||
[:fieldset {:class "hx-disable"
|
[:fieldset {:class "hx-disable"
|
||||||
:hx-disinherit "hx-target" ;; TODO why disinherit
|
:hx-disinherit "hx-target" ;; TODO why disinherit
|
||||||
:x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client entity))
|
:x-data (hx/json {:clientId (or (:db/id (:transaction-rule/client form-params))
|
||||||
(:transaction-rule/client entity))})}
|
(:transaction-rule/client form-params)
|
||||||
|
(:db/id (:transaction-rule/client entity)))})}
|
||||||
|
|
||||||
[:div.space-y-1
|
[:div.space-y-1
|
||||||
(when-let [id (:db/id entity)]
|
(when-let [id (:db/id entity)]
|
||||||
@@ -486,7 +486,7 @@
|
|||||||
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name))
|
:hx-vals (format "js:{name: '%s', 'client-id': event.detail.clientId}" (fc/field-name))
|
||||||
:x-init "$watch('clientId', cid => $dispatch('changed', $data))"}]
|
:x-init "$watch('clientId', cid => $dispatch('changed', $data))"}]
|
||||||
|
|
||||||
(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 form-params))
|
||||||
:name (fc/field-name)
|
:name (fc/field-name)
|
||||||
:value (fc/field-value)})]))
|
:value (fc/field-value)})]))
|
||||||
|
|
||||||
@@ -543,18 +543,20 @@
|
|||||||
: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 %))})]))
|
||||||
|
|
||||||
(fc/with-field :transaction-rule/accounts
|
(fc/with-field :transaction-rule/accounts
|
||||||
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
(com/validated-field
|
||||||
(com/data-grid-header {:class "w-32"} "Location")
|
{:errors (fc/field-errors)}
|
||||||
(com/data-grid-header {:class "w-16"} "%")
|
(com/data-grid {:headers [(com/data-grid-header {} "Account")
|
||||||
(com/data-grid-header {:class "w-16"})]
|
(com/data-grid-header {:class "w-32"} "Location")
|
||||||
:id "transaction-rule-account-table"}
|
(com/data-grid-header {:class "w-16"} "%")
|
||||||
(fc/cursor-map #(transaction-rule-account-row* entity %))
|
(com/data-grid-header {:class "w-16"})]
|
||||||
(com/data-grid-new-row {:colspan 4
|
:id "transaction-rule-account-table"}
|
||||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
(fc/cursor-map #(transaction-rule-account-row* form-params %))
|
||||||
:admin-transaction-rule-new-account)
|
(com/data-grid-new-row {:colspan 4
|
||||||
:index (count (fc/field-value))
|
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
:tr-params (hx/bind-alpine-vals {} {:client-id "clientId"})}
|
:admin-transaction-rule-new-account)
|
||||||
"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
|
(fc/with-field :transaction-rule/transaction-approval-status
|
||||||
(com/validated-field {:label "Approval status"
|
(com/validated-field {:label "Approval status"
|
||||||
@@ -567,10 +569,8 @@
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
[:div
|
[:div
|
||||||
[:div#form-errors (when (:errors fc/*form-errors*)
|
(com/form-errors {:errors (:errors fc/*form-errors*)})
|
||||||
[:span.error-content
|
(com/validated-save-button {:errors (:errors form-errors)} "Save rule")])])))
|
||||||
(com/errors {:errors (:errors fc/*form-errors*)})])]
|
|
||||||
(com/validated-save-button {:errors form-errors} "Save rule")])])))
|
|
||||||
|
|
||||||
|
|
||||||
;; TODO Should forms have some kind of helper to render an individual field? saving
|
;; TODO Should forms have some kind of helper to render an individual field? saving
|
||||||
@@ -619,34 +619,14 @@
|
|||||||
:value account
|
:value account
|
||||||
:client-id client-id}))))
|
:client-id client-id}))))
|
||||||
|
|
||||||
(defn transaction-rule-edit-dialog [request]
|
(defn transaction-dialog [{:keys [entity form-params form-errors]}]
|
||||||
(let [entity (or
|
(html-response (dialog* {:entity entity
|
||||||
(some-> request :last-form)
|
:form-params (or (when (seq form-params)
|
||||||
(some-> request :route-params :db/id (#(dc/pull (dc/db conn) default-read %))))]
|
form-params)
|
||||||
(html-response (dialog* :entity entity
|
entity ;; TODO coerce into form params
|
||||||
:form-params {:hx-put (str (bidi/path-for ssr-routes/only-routes
|
{})
|
||||||
:admin-transaction-rule-edit-save))})
|
:form-errors form-errors})
|
||||||
:headers {"hx-trigger-after-settle" "modalopen"})))
|
:headers {"hx-trigger" "modalopen"}))
|
||||||
|
|
||||||
(defn transaction-rule-error [request]
|
|
||||||
(let [entity (some-> request :last-form)]
|
|
||||||
(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"
|
|
||||||
"hx-reselect" "#edit-form fieldset"})))
|
|
||||||
|
|
||||||
|
|
||||||
(defn transaction-rule-new-dialog [_]
|
|
||||||
(html-response (dialog* :entity {}
|
|
||||||
:form-errors {}
|
|
||||||
:form-params {:hx-post (str (bidi/path-for ssr-routes/only-routes
|
|
||||||
:admin-transaction-rule-edit-save))})
|
|
||||||
:headers {"hx-trigger-after-settle" "modalopen"}))
|
|
||||||
|
|
||||||
(def transaction-rule-schema (mc/schema
|
(def transaction-rule-schema (mc/schema
|
||||||
[:map
|
[:map
|
||||||
@@ -695,12 +675,15 @@
|
|||||||
[:value {:optional true}
|
[:value {:optional true}
|
||||||
[: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-schema-decode :form-schema transaction-rule-schema)
|
(wrap-schema-decode :form-schema transaction-rule-schema)
|
||||||
(wrap-nested-form-params)
|
(wrap-nested-form-params)
|
||||||
(wrap-form-4xx-2 transaction-rule-error))
|
(wrap-form-4xx-2 (-> transaction-dialog
|
||||||
:admin-transaction-rule-edit-dialog (-> transaction-rule-edit-dialog
|
(wrap-entity [:form-params :db/id] default-read))))
|
||||||
|
:admin-transaction-rule-edit-dialog (-> transaction-dialog
|
||||||
|
(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]]))
|
||||||
:admin-transaction-rule-new-dialog transaction-rule-new-dialog})
|
:admin-transaction-rule-new-dialog transaction-dialog})
|
||||||
(fn [h]
|
(fn [h]
|
||||||
(-> h
|
(-> h
|
||||||
(wrap-admin)
|
(wrap-admin)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
(def field inputs/field-)
|
(def field inputs/field-)
|
||||||
(def validated-field inputs/validated-field-)
|
(def validated-field inputs/validated-field-)
|
||||||
(def errors inputs/errors-)
|
(def errors inputs/errors-)
|
||||||
|
(def form-errors inputs/form-errors-)
|
||||||
|
|
||||||
(def left-aside aside/left-aside-)
|
(def left-aside aside/left-aside-)
|
||||||
(def company-aside-nav aside/company-aside-nav-)
|
(def company-aside-nav aside/company-aside-nav-)
|
||||||
|
|||||||
@@ -4,11 +4,13 @@
|
|||||||
[auto-ap.ssr.hiccup-helper :as hh]))
|
[auto-ap.ssr.hiccup-helper :as hh]))
|
||||||
|
|
||||||
(defn modal- [params & children]
|
(defn modal- [params & children]
|
||||||
[:div {:class (-> (:class params)
|
[:div (-> params
|
||||||
(or "max-w-4xl w-1/4 overflow-visible")
|
(update :class #(-> %
|
||||||
(hh/add-class "h-min"))
|
(or "max-w-4xl w-1/4 overflow-visible")
|
||||||
"@click.outside" "open=false"
|
(hh/add-class "h-min")))
|
||||||
} children])
|
|
||||||
|
(assoc "@click.outside" "open=false"))
|
||||||
|
children])
|
||||||
|
|
||||||
(defn modal-card- [params header content footer]
|
(defn modal-card- [params header content footer]
|
||||||
[:div#modal-card (update params
|
[:div#modal-card (update params
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ c.clearChoices();
|
|||||||
[:input
|
[:input
|
||||||
(-> params
|
(-> params
|
||||||
(dissoc :error?)
|
(dissoc :error?)
|
||||||
|
(assoc :type "text")
|
||||||
(update
|
(update
|
||||||
:class (fnil hh/add-class "") default-input-classes)
|
:class (fnil hh/add-class "") default-input-classes)
|
||||||
(update :class #(str % (use-size size))))])
|
(update :class #(str % (use-size size))))])
|
||||||
@@ -210,6 +211,11 @@ c.clearChoices();
|
|||||||
(when (sequential? errors)
|
(when (sequential? errors)
|
||||||
(str/join ", " (filter string? errors)))])
|
(str/join ", " (filter string? errors)))])
|
||||||
|
|
||||||
|
(defn form-errors- [{:keys [errors]}]
|
||||||
|
[:div#form-errors (when errors
|
||||||
|
[:span.error-content
|
||||||
|
(errors- {:errors errors})])])
|
||||||
|
|
||||||
(defn validated-field- [params & rest]
|
(defn validated-field- [params & rest]
|
||||||
(field- (cond-> params
|
(field- (cond-> params
|
||||||
true (dissoc :errors)
|
true (dissoc :errors)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
many-entity
|
many-entity
|
||||||
ref->enum-schema
|
ref->enum-schema
|
||||||
ref->select-options
|
ref->select-options
|
||||||
|
wrap-entity
|
||||||
wrap-form-4xx-2
|
wrap-form-4xx-2
|
||||||
wrap-schema-decode]]
|
wrap-schema-decode]]
|
||||||
[auto-ap.time :as atime]
|
[auto-ap.time :as atime]
|
||||||
@@ -34,9 +35,7 @@
|
|||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[config.core :refer [env]]
|
[config.core :refer [env]]
|
||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[hiccup2.core :as hiccup]
|
[malli.core :as mc]))
|
||||||
[malli.core :as mc]
|
|
||||||
[clj-time.format :as f]))
|
|
||||||
|
|
||||||
(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"
|
||||||
@@ -257,14 +256,17 @@
|
|||||||
(def table* (partial helper/table* grid-page))
|
(def table* (partial helper/table* grid-page))
|
||||||
|
|
||||||
(defn impersonate [request]
|
(defn impersonate [request]
|
||||||
(let [user (some-> request :params :db/id (#(dc/pull (dc/db conn) default-read %))) ]
|
(println (:entity request))
|
||||||
|
(if (:entity request)
|
||||||
{:status 200
|
{:status 200
|
||||||
:headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt user "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 user "FAKE_TOKEN")
|
:session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN")
|
||||||
:exp)}}))
|
:exp)}}
|
||||||
|
{:status 404}))
|
||||||
|
|
||||||
(defn client-row* [client]
|
(defn client-row* [client]
|
||||||
(com/data-grid-row (-> {:x-ref "p"
|
(com/data-grid-row (-> {:x-ref "p"
|
||||||
:data-key "show"
|
:data-key "show"
|
||||||
@@ -288,19 +290,20 @@
|
|||||||
(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))))
|
||||||
|
|
||||||
(defn dialog* [{:keys [entity form-params form-errors]}]
|
|
||||||
|
;; TODO hydrate user name
|
||||||
|
(defn dialog* [{:keys [form-params form-errors entity]}]
|
||||||
(fc/start-form
|
(fc/start-form
|
||||||
entity form-errors
|
form-params form-errors
|
||||||
(com/modal
|
(com/modal
|
||||||
{}
|
{:hx-target "this"}
|
||||||
[:form#edit-form (merge {:hx-ext "response-targets"
|
[:form#edit-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"}
|
||||||
form-params)
|
|
||||||
[:fieldset {:class "hx-disable"}
|
[:fieldset {:class "hx-disable"}
|
||||||
(com/modal-card
|
(com/modal-card
|
||||||
{}
|
{}
|
||||||
@@ -329,9 +332,7 @@
|
|||||||
:user-client-new)}
|
:user-client-new)}
|
||||||
"Assign new client"))))]
|
"Assign new client"))))]
|
||||||
[:div
|
[:div
|
||||||
[:div [:div#form-errors (when (:errors fc/*form-errors*)
|
(com/form-errors {:errors (:errors fc/*form-errors*)})
|
||||||
[:span.error-content
|
|
||||||
(com/errors {:errors (:errors fc/*form-errors*)})])]]
|
|
||||||
(com/validated-save-button {:errors (seq form-errors)}
|
(com/validated-save-button {:errors (seq form-errors)}
|
||||||
"Save user")])]])))
|
"Save user")])]])))
|
||||||
|
|
||||||
@@ -348,22 +349,17 @@
|
|||||||
(defn user-save-error [request]
|
(defn user-save-error [request]
|
||||||
;; TODO hydration
|
;; TODO hydration
|
||||||
;; TODO consistency of error handling and passing, on all form examples
|
;; TODO consistency of error handling and passing, on all form examples
|
||||||
(let [entity (some-> request :last-form)]
|
(html-response (dialog* {:form-params (:form-params request)
|
||||||
(html-response (dialog* {:entity entity
|
:entity (:entity request)
|
||||||
:form-errors (:form-errors request)})
|
:form-errors (:form-errors request)})))
|
||||||
:headers {"hx-retarget" "#edit-form fieldset"
|
|
||||||
"hx-reselect" "#edit-form fieldset"})))
|
|
||||||
|
|
||||||
(defn user-edit-dialog [request]
|
(defn user-edit-dialog [request]
|
||||||
(let [user (some-> request
|
(html-response
|
||||||
:route-params
|
(dialog* {:form-params (:entity request)
|
||||||
:db/id
|
:entity (:entity request)
|
||||||
(#(dc/pull (dc/db conn) default-read %)))]
|
:form-errors {}})
|
||||||
(html-response
|
|
||||||
(dialog* {:entity user
|
:headers {"hx-trigger" "modalopen"}))
|
||||||
:form-errors {}})
|
|
||||||
|
|
||||||
:headers {"hx-trigger" "modalopen"})))
|
|
||||||
|
|
||||||
(defn new-client [{ {:keys [index]} :query-params}]
|
(defn new-client [{ {:keys [index]} :query-params}]
|
||||||
(html-response
|
(html-response
|
||||||
@@ -371,28 +367,34 @@
|
|||||||
: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
|
||||||
{:users (helper/page-route grid-page)
|
{:users (helper/page-route grid-page)
|
||||||
: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-schema-decode :form-schema (mc/schema
|
(wrap-entity [:form-params :db/id] default-read)
|
||||||
[:map
|
(wrap-schema-decode :form-schema user-form-schema)
|
||||||
[:db/id entity-id]
|
|
||||||
[:user/clients {:optional true}
|
|
||||||
[:maybe
|
|
||||||
(many-entity {} [:db/id entity-id])]]
|
|
||||||
[:user/role (ref->enum-schema "user-role")]]))
|
|
||||||
(wrap-nested-form-params)
|
(wrap-nested-form-params)
|
||||||
(wrap-form-4xx-2 user-save-error))
|
(wrap-form-4xx-2 (wrap-entity user-save-error [: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-edit-dialog
|
||||||
|
(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]])))
|
||||||
:user-impersonate (-> impersonate
|
:user-impersonate (-> impersonate
|
||||||
|
(wrap-entity [:params :db/id] default-read)
|
||||||
(wrap-schema-decode
|
(wrap-schema-decode
|
||||||
:params-schema (mc/schema [:map [:db/id entity-id]])))}
|
:params-schema (mc/schema [:map [:db/id entity-id]])))}
|
||||||
(fn [h]
|
(fn [h]
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
(ns auto-ap.ssr.utils
|
(ns auto-ap.ssr.utils
|
||||||
(:require
|
(:require
|
||||||
[auto-ap.datomic :refer [all-schema]]
|
[auto-ap.datomic :refer [all-schema conn]]
|
||||||
[auto-ap.logging :as alog]
|
[auto-ap.logging :as alog]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[config.core :refer [env]]
|
[config.core :refer [env]]
|
||||||
|
[datomic.api :as dc]
|
||||||
[hiccup2.core :as hiccup]
|
[hiccup2.core :as hiccup]
|
||||||
[malli.core :as mc]
|
[malli.core :as mc]
|
||||||
[malli.error :as me]
|
[malli.error :as me]
|
||||||
[malli.transform :as mt2]
|
[malli.transform :as mt2]
|
||||||
[slingshot.slingshot :refer [throw+ try+]]
|
[slingshot.slingshot :refer [throw+ try+]]))
|
||||||
[manifold.time :as mt]))
|
|
||||||
|
|
||||||
(defn html-response [hiccup & {:keys [status headers oob] :or {status 200 headers {} oob []}}]
|
(defn html-response [hiccup & {:keys [status headers oob] :or {status 200 headers {} oob []}}]
|
||||||
{:status status
|
{:status status
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
|
|
||||||
(def entity-id (mc/schema [nat-int? {:error/message "required"} ]))
|
(def entity-id (mc/schema [nat-int? {:error/message "required"} ]))
|
||||||
|
|
||||||
(def temp-id (mc/schema :string))
|
(def temp-id (mc/schema [:string {:min 1}]))
|
||||||
(def money (mc/schema [:double]))
|
(def money (mc/schema [:double]))
|
||||||
(def percentage (mc/schema [:double {:decode/arbitrary (fn [x] (some-> x (* 0.01)))
|
(def percentage (mc/schema [:double {:decode/arbitrary (fn [x] (some-> x (* 0.01)))
|
||||||
:max 1.0
|
:max 1.0
|
||||||
@@ -292,18 +292,18 @@
|
|||||||
(: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 (:decoded e)
|
:form-params (:decoded e)
|
||||||
:field-validation-errors errors
|
:field-validation-errors errors
|
||||||
:form-errors humanized)))
|
: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 (:form e)
|
:form-params (:form e)
|
||||||
:form-errors (:form-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 (:form e)
|
:form-params (:form e)
|
||||||
:form-validation-errors (:form-validation-errors e)
|
:form-validation-errors (:form-validation-errors e)
|
||||||
:form-errors {:errors (:form-validation-errors e)}))))))
|
:form-errors {:errors (:form-validation-errors e)}))))))
|
||||||
|
|
||||||
@@ -326,3 +326,15 @@
|
|||||||
(map (fn [k]
|
(map (fn [k]
|
||||||
(str "[" (k->n k) "]"))
|
(str "[" (k->n k) "]"))
|
||||||
rest)))))
|
rest)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn wrap-entity [handler path read]
|
||||||
|
(fn wrap-entity-request [request]
|
||||||
|
(let [entity (some->>
|
||||||
|
(get-in request path)
|
||||||
|
(#(if (string? %) (Long/parseLong %) %))
|
||||||
|
(dc/pull (dc/db conn) read ))]
|
||||||
|
(handler (if entity
|
||||||
|
(assoc request
|
||||||
|
:entity entity)
|
||||||
|
request)))))
|
||||||
|
|||||||
Reference in New Issue
Block a user