diff --git a/src/clj/auto_ap/square/core3.clj b/src/clj/auto_ap/square/core3.clj index d9c1e916..55cdf61a 100644 --- a/src/clj/auto_ap/square/core3.clj +++ b/src/clj/auto_ap/square/core3.clj @@ -767,6 +767,14 @@ (dc/db conn) 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 ([] (apply de/zip diff --git a/src/clj/auto_ap/ssr/admin/accounts.clj b/src/clj/auto_ap/ssr/admin/accounts.clj index 755b5460..3e95993e 100644 --- a/src/clj/auto_ap/ssr/admin/accounts.clj +++ b/src/clj/auto_ap/ssr/admin/accounts.clj @@ -27,6 +27,7 @@ field-validation-error form-validation-error html-response + main-transformer many-entity ref->enum-schema ref->select-options @@ -263,10 +264,7 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :value (fc/field-value) - :value-fn (some-fn :db/id identity) ;; TODO better hydration - :content-fn (fn [value] - (:client/name (cond->> value - (nat-int? value) (dc/pull (dc/db conn) [:client/name]))))})))) + :content-fn #(pull-attr (dc/db conn) :client/name %)})))) (fc/with-field :account-client-override/name (com/data-grid-cell {} @@ -298,14 +296,14 @@ :hx-target "this"} (com/modal {} - [:form#edit-form (-> {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} - (assoc (if (:db/id entity) - :hx-put - :hx-post) - (str (bidi/path-for ssr-routes/only-routes - :admin-transaction-rule-edit-save)))) + [:form (-> {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} + (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"} (com/modal-card {} @@ -323,7 +321,7 @@ (com/validated-field {:label "Numeric code" :errors (fc/field-errors)} (com/text-input {:name (fc/field-name) - :value (fc/field-value) + :value (fc/field-value) :x-model "accountCode" :autofocus true :class "w-32"})) @@ -382,13 +380,13 @@ (com/data-grid {:headers [(com/data-grid-header {} "Client") (com/data-grid-header {} "Account name") (com/data-grid-header {})] - :id "client-override-table"} + :id "client-override-table"} (fc/cursor-map #(client-override* %)) (com/data-grid-new-row {:colspan 3 - :index (count (fc/field-value)) - :hx-get (bidi/path-for ssr-routes/only-routes + :index (count (fc/field-value)) + :hx-get (bidi/path-for ssr-routes/only-routes :admin-account-client-override-new)} "New override")))) @@ -407,17 +405,7 @@ [] (client-override* fc/*current*)))) -(defn account-dialog [{:keys [entity form-params form-errors]}] - (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 +(def form-schema (mc/schema [:map [:db/id {:optional true} [:maybe entity-id]] [:account/numeric-code {:optional true} [:maybe :int]] @@ -434,6 +422,19 @@ [:account-client-override/client entity-id] [: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 (apply-middleware-to-all-handlers (->> @@ -446,7 +447,7 @@ wrap-admin wrap-client-redirect-unauthenticated) :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 form-schema) (wrap-nested-form-params) (wrap-form-4xx-2 (wrap-entity account-dialog [:form-params :db/id] default-read))) :admin-account-edit-dialog (-> account-dialog diff --git a/src/clj/auto_ap/ssr/admin/background_jobs.clj b/src/clj/auto_ap/ssr/admin/background_jobs.clj index d468010f..58f4bb47 100644 --- a/src/clj/auto_ap/ssr/admin/background_jobs.clj +++ b/src/clj/auto_ap/ssr/admin/background_jobs.clj @@ -184,11 +184,11 @@ (defn job-start-dialog [_] (html-response (com/modal {:modal-class "max-w-4xl"} - [:form#edit-form {:hx-ext "response-targets" - :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start - ) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content"} + [:form {:hx-ext "response-targets" + :hx-post (bidi/path-for ssr-routes/only-routes :admin-job-start + ) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content"} [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -199,18 +199,18 @@ (com/select {:name "name" :class "w-64" :options [["" ""] - ["yodlee2" "Yodlee Import"] - ["yodlee2-accounts" "Yodlee Account Import"] - ["intuit" "Intuit import"] - ["plaid" "Plaid import"] - ["bulk-journal-import" "Bulk Journal Import"] - ["square2-import-job" "Square2 Import"] - ["register-invoice-import" "Register Invoice Import "] - ["ezcater-upsert" "Upsert recent ezcater orders"] - ["load-historical-sales" "Load Historical Square Sales"] - ["export-backup" "Export Backup"]] + ["yodlee2" "Yodlee Import"] + ["yodlee2-accounts" "Yodlee Account Import"] + ["intuit" "Intuit import"] + ["plaid" "Plaid import"] + ["bulk-journal-import" "Bulk Journal Import"] + ["square2-import-job" "Square2 Import"] + ["register-invoice-import" "Register Invoice Import "] + ["ezcater-upsert" "Upsert recent ezcater orders"] + ["load-historical-sales" "Load Historical Square Sales"] + ["export-backup" "Export Backup"]] :hx-get (bidi/path-for ssr-routes/only-routes - :admin-job-subform) + :admin-job-subform) :hx-target "#sub-form" :hx-swap "innerHTML"})) diff --git a/src/clj/auto_ap/ssr/admin/transaction_rules.clj b/src/clj/auto_ap/ssr/admin/transaction_rules.clj index 841c2160..383a2f18 100644 --- a/src/clj/auto_ap/ssr/admin/transaction_rules.clj +++ b/src/clj/auto_ap/ssr/admin/transaction_rules.clj @@ -29,6 +29,7 @@ field-validation-error form-validation-error html-response + main-transformer many-entity money percentage @@ -66,8 +67,9 @@ :url (bidi/path-for ssr-routes/only-routes :vendor-search) :id (str "vendor-search") - :value [(:db/id (:vendor (:parsed-query-params request))) - (:vendor/name (:vendor (:parsed-query-params request)))]})) + :value (:vendor (:parsed-query-params request)) + :value-fn :db/id + :content-fn :vendor/name})) (com/field {:label "Note"} (com/text-input {:name "note" :id "note" @@ -330,12 +332,11 @@ :id name :x-model x-model :value value - :value-fn (some-fn :db/id identity) :content-fn (fn [value] - (:account/name (d-accounts/clientize (cond->> value - (nat-int? value) (dc/pull (dc/db conn) d-accounts/default-read)) + (:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read value) client-id)))})]) +;; TODO something is making the accountId not change the location for only existing ones? (defn- transaction-rule-account-row* [transaction-rule 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) :client-id (:db/id (:transaction-rule/client transaction-rule)) :name (fc/field-name) - :x-model "accountId" - })))) + :x-model "accountId"})))) (fc/with-field :transaction-rule-account/location (com/data-grid-cell {} @@ -396,22 +396,21 @@ (com/data-grid-cell {:class "align-top"} (com/a-icon-button {"@click.prevent.stop" "show=false; setTimeout(() => $refs.p.remove(), 500)"} svg/x)))) -;; TODO dialog is no longer closeable -;; TODO might not need #edit-form id +;; TODO background jobs and company 1099 (defn dialog* [{:keys [entity form-params form-errors]}] (fc/start-form form-params form-errors (com/modal {:modal-class "max-w-2xl" :hx-target "this"} - [:form#edit-form {:hx-ext "response-targets" - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :x-trap "true" - :class "group/form" - (if (:db/id entity) - :hx-put - :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} + [:form {:hx-ext "response-targets" + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :x-trap "true" + :class "group/form" + (if (:db/id entity) + :hx-put + :hx-post) (str (bidi/path-for ssr-routes/only-routes :admin-transaction-rule-edit-save))} (com/modal-card {} [:div.flex [:div.p-2 "Transaction Rule"]] @@ -465,10 +464,7 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :x-model "clientId" :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (fn [c] (cond->> c - (nat-int? c) (dc/pull (dc/db conn) '[:client/name]) - true :client/name))})])) + :content-fn (fn [c] (pull-attr (dc/db conn) :client/name c))})])) (fc/with-field :transaction-rule/bank-account (com/validated-field @@ -536,11 +532,9 @@ (com/typeahead-2 {:name (fc/field-name) :placeholder "Search..." :url (bidi/path-for ssr-routes/only-routes :vendor-search) - :id (str "form-vendor-search") :class "w-96" :value (fc/field-value) - :value-fn (some-fn :db/id identity) - :content-fn (some-fn :vendor/name #(pull-attr (dc/db conn) :vendor/name %))})])) + :content-fn #(pull-attr (dc/db conn) :vendor/name %)})])) (fc/with-field :transaction-rule/accounts (com/validated-field @@ -573,11 +567,6 @@ (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}] (html-response (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 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}] (html-response (location-select* {:name name :value value :account-location (some->> account-id - (pull-attr (dc/db conn) :account/location)) + (pull-attr (dc/db conn) :account/location)) :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}] (let [account (some->> value (dc/pull (dc/db conn) [:account/name :db/id @@ -619,34 +606,37 @@ :value account :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]}] (html-response (dialog* {:entity entity :form-params (or (when (seq 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}) :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 (apply-middleware-to-all-handlers @@ -676,10 +666,10 @@ [:maybe entity-id]]])) :admin-transaction-rule-save (-> transaction-rule-save (wrap-entity [:form-params :db/id] default-read) - (wrap-schema-decode :form-schema transaction-rule-schema) - (wrap-nested-form-params) - (wrap-form-4xx-2 (-> transaction-dialog - (wrap-entity [:form-params :db/id] default-read)))) + (wrap-schema-decode :form-schema form-schema) + (wrap-nested-form-params) + (wrap-form-4xx-2 (-> transaction-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]])) diff --git a/src/clj/auto_ap/ssr/components/buttons.clj b/src/clj/auto_ap/ssr/components/buttons.clj index 9df54b67..d23281d7 100644 --- a/src/clj/auto_ap/ssr/components/buttons.clj +++ b/src/clj/auto_ap/ssr/components/buttons.clj @@ -176,7 +176,7 @@ (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 "") true (hh/add-class "w-32") (seq errors) (hh/add-class "animate-shake"))} diff --git a/src/clj/auto_ap/ssr/components/inputs.clj b/src/clj/auto_ap/ssr/components/inputs.clj index 02251640..c42f82ed 100644 --- a/src/clj/auto_ap/ssr/components/inputs.clj +++ b/src/clj/auto_ap/ssr/components/inputs.clj @@ -75,11 +75,11 @@ c.clearChoices(); :baseUrl (if (str/includes? (:url params) "?") (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 "" :active -1 - :elements (if ((:value-fn params first) (:value params)) - [{:value ((:value-fn params first) (:value params)) :label ((:content-fn params second) (:value params))}] + :elements (if ((:value-fn params identity) (:value params)) + [{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}] [])}) :x-modelable "value.value" :x-model (:x-model params) diff --git a/src/clj/auto_ap/ssr/hx.clj b/src/clj/auto_ap/ssr/hx.clj index 0a069362..370e27b3 100644 --- a/src/clj/auto_ap/ssr/hx.clj +++ b/src/clj/auto_ap/ssr/hx.clj @@ -38,3 +38,15 @@ alpine-appear alpine-disappear) (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))))) + diff --git a/src/clj/auto_ap/ssr/users.clj b/src/clj/auto_ap/ssr/users.clj index 26f90161..3040f057 100644 --- a/src/clj/auto_ap/ssr/users.clj +++ b/src/clj/auto_ap/ssr/users.clj @@ -6,6 +6,7 @@ apply-sort-3 conn merge-query + pull-attr pull-many query2]] [auto-ap.query-params :as query-params] @@ -23,6 +24,7 @@ :refer [apply-middleware-to-all-handlers entity-id html-response + main-transformer many-entity ref->enum-schema ref->select-options @@ -256,13 +258,11 @@ (def table* (partial helper/table* grid-page)) (defn impersonate [request] - (println (:entity request)) (if (:entity request) {:status 200 :headers {"hx-redirect" (str "/?jwt=" (jwt/sign (auth/user->jwt (:entity request) "FAKE_TOKEN") (:jwt-secret env) - {:alg :hs512})) - } + {:alg :hs512}))} :session {:identity (dissoc (auth/user->jwt (:entity request) "FAKE_TOKEN") :exp)}} {:status 404})) @@ -279,31 +279,27 @@ :url (bidi/path-for ssr-routes/only-routes :company-search) :value (fc/field-value) + :value-fn :db/id - :value-fn :db/id ;; TODO better hydration - :content-fn (fn [value] - (:client/name (dc/pull (dc/db conn) [:client/name] - (or (:db/id value) - value)))) + :content-fn #(pull-attr (dc/db conn) :client/name (:db/id %)) :size :small}))) (com/data-grid-cell {:class "align-top"} (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]}] (fc/start-form form-params form-errors (com/modal {:hx-target "this"} - [:form#edit-form {:hx-ext "response-targets" - :hx-put (str (bidi/path-for ssr-routes/only-routes - :user-edit-save - :request-method :put)) - :hx-swap "outerHTML swap:300ms" - :hx-target-400 "#form-errors .error-content" - :class "w-full"} + [:form {:hx-ext "response-targets" + :hx-put (str (bidi/path-for ssr-routes/only-routes + :user-edit-save + :request-method :put)) + :hx-swap "outerHTML swap:300ms" + :hx-target-400 "#form-errors .error-content" + :class "w-full"} [:fieldset {:class "hx-disable"} (com/modal-card {} @@ -321,7 +317,7 @@ :value (some->> (fc/field-value) name) :options (ref->select-options "user-role")}))) (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-header {} )] :id "client-table"} @@ -336,7 +332,6 @@ (com/validated-save-button {:errors (seq form-errors)} "Save user")])]]))) -;; TODO rename edit-form or make it generic (defn user-edit-save [{:keys [form-params identity] :as request}] (let [_ @(dc/transact conn [[:upsert-entity form-params]]) user (some-> form-params :db/id (#(dc/pull (dc/db conn) default-read %)))] @@ -346,18 +341,25 @@ :headers {"hx-trigger" "modalclose" "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 - (dialog* {:form-params (:entity request) - :entity (:entity request) - :form-errors {}}) + (dialog* {:form-params (or (when (seq form-params) + form-params) + (when entity + (mc/decode form-schema entity main-transformer)) + {}) + :entity entity + :form-errors form-errors}) :headers {"hx-trigger" "modalopen"})) @@ -367,14 +369,7 @@ :new? true} [] (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 (apply-middleware-to-all-handlers @@ -382,14 +377,14 @@ :user-table (helper/table-route grid-page) :user-edit-save (-> user-edit-save (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-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 (wrap-schema-decode :query-schema [:map [:index {:optional true :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-schema-decode :route-schema (mc/schema [:map [:db/id entity-id]]))) diff --git a/src/clj/auto_ap/ssr/utils.clj b/src/clj/auto_ap/ssr/utils.clj index 6cbdfa0f..ca664017 100644 --- a/src/clj/auto_ap/ssr/utils.clj +++ b/src/clj/auto_ap/ssr/utils.clj @@ -97,7 +97,11 @@ :long 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 money (mc/schema [:double])) @@ -116,15 +120,17 @@ (def map->db-id-decoder {:enter (fn [x] - (into [] - (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] - v - #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) - (Long/parseLong k) - (keyword? k) - (name k) - :else - k)))))}) + (if (sequential? x) + x + (into [] + (for [[k v] (sort-by (comp #(Long/parseLong %) name first) x)] + v + #_(assoc v :db/id (cond (and (string? k) (re-find #"^\d+$" k)) + (Long/parseLong k) + (keyword? k) + (name k) + :else + k))))))}) (defn many-entity [params & keys] (mc/schema @@ -219,7 +225,10 @@ (handler request)))) (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) :when (= n (namespace ident))] ident)))