Makes tailwind version of history page
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
htmx.defineExtension('disable-submit', {
|
htmx.defineExtension('disable-submit', {
|
||||||
onEvent: function (name, evt, data) {
|
onEvent: function (name, evt, data) {
|
||||||
|
/*
|
||||||
let elt = evt.detail.elt;
|
let elt = evt.detail.elt;
|
||||||
let result = elt.querySelectorAll('.hx-disable');
|
let result = elt.querySelectorAll('.hx-disable');
|
||||||
|
|
||||||
@@ -12,5 +13,6 @@ htmx.defineExtension('disable-submit', {
|
|||||||
result.forEach(element => element.disabled = false);
|
result.forEach(element => element.disabled = false);
|
||||||
if (elt.classList.contains('hx-disable')) elt.disabled = false;
|
if (elt.classList.contains('hx-disable')) elt.disabled = false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1228,6 +1228,10 @@ input:checked + .toggle-bg {
|
|||||||
margin-top: 1.25rem;
|
margin-top: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt-4 {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -1368,6 +1372,10 @@ input:checked + .toggle-bg {
|
|||||||
max-width: 1024px;
|
max-width: 1024px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-lg {
|
||||||
|
max-width: 32rem;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-1 {
|
.flex-1 {
|
||||||
flex: 1 1 0%;
|
flex: 1 1 0%;
|
||||||
}
|
}
|
||||||
@@ -1773,6 +1781,11 @@ input:checked + .toggle-bg {
|
|||||||
background-color: rgb(253 246 178 / var(--tw-bg-opacity));
|
background-color: rgb(253 246 178 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-red-100 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(255 205 205 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-opacity-50 {
|
.bg-opacity-50 {
|
||||||
--tw-bg-opacity: 0.5;
|
--tw-bg-opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -2520,6 +2533,11 @@ input:checked + .toggle-bg {
|
|||||||
background-color: rgb(99 49 18 / var(--tw-bg-opacity));
|
background-color: rgb(99 49 18 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(.dark .dark\:bg-red-900) {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(51 1 1 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
:is(.dark .dark\:bg-opacity-80) {
|
:is(.dark .dark\:bg-opacity-80) {
|
||||||
--tw-bg-opacity: 0.8;
|
--tw-bg-opacity: 0.8;
|
||||||
}
|
}
|
||||||
@@ -2584,6 +2602,11 @@ input:checked + .toggle-bg {
|
|||||||
color: rgb(250 202 21 / var(--tw-text-opacity));
|
color: rgb(250 202 21 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(.dark .dark\:text-red-300) {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(255 104 104 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder {
|
:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder {
|
||||||
--tw-placeholder-opacity: 1;
|
--tw-placeholder-opacity: 1;
|
||||||
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
|
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
|
||||||
@@ -2730,6 +2753,10 @@ input:checked + .toggle-bg {
|
|||||||
margin-right: 6rem;
|
margin-right: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:table-cell {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:flex-row {
|
.md\:flex-row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
@@ -2760,6 +2787,10 @@ input:checked + .toggle-bg {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:table-cell {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:hidden {
|
.lg\:hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,15 @@
|
|||||||
(:require
|
(:require
|
||||||
[auto-ap.datomic :refer [conn]]
|
[auto-ap.datomic :refer [conn]]
|
||||||
[auto-ap.logging :as alog]
|
[auto-ap.logging :as alog]
|
||||||
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
|
|
||||||
[auto-ap.ssr.ui :refer [base-page]]
|
[auto-ap.ssr.ui :refer [base-page]]
|
||||||
[auto-ap.ssr.utils :refer [html-response]]
|
[auto-ap.ssr.utils :refer [html-response]]
|
||||||
[auto-ap.time :as atime]
|
[auto-ap.time :as atime]
|
||||||
[clj-time.coerce :as coerce]
|
[clj-time.coerce :as coerce]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[datomic.api :as dc]
|
[datomic.api :as dc]
|
||||||
[hiccup2.core :as hiccup]))
|
[auto-ap.ssr.components :as com]
|
||||||
|
[auto-ap.ssr-routes :as ssr-routes]
|
||||||
|
[bidi.bidi :as bidi]))
|
||||||
|
|
||||||
(defn tx-rows->changes [history]
|
(defn tx-rows->changes [history]
|
||||||
(->> history
|
(->> history
|
||||||
@@ -25,9 +26,6 @@
|
|||||||
changes))]
|
changes))]
|
||||||
[t a changes])))))
|
[t a changes])))))
|
||||||
|
|
||||||
(def error-script
|
|
||||||
(hiccup/raw "on htmx:responseError from me set event.detail.target's innerHTML to event.detail.xhr.responseText end"))
|
|
||||||
|
|
||||||
(defn format-value [v]
|
(defn format-value [v]
|
||||||
(cond (inst? v)
|
(cond (inst? v)
|
||||||
(-> v
|
(-> v
|
||||||
@@ -40,126 +38,27 @@
|
|||||||
|
|
||||||
(and (integer? v)
|
(and (integer? v)
|
||||||
(> v 1000000))
|
(> v 1000000))
|
||||||
[:span
|
[:span
|
||||||
[:a {:hx-get (str "/admin/history/" v)
|
(com/link
|
||||||
:hx-swap "innerHTML"
|
{:href "#"
|
||||||
:hx-push-url "true"
|
:hx-get (str "/admin/history/" v)
|
||||||
:hx-target "#history-table"}
|
:hx-swap "innerHTML"
|
||||||
v]
|
:hx-push-url "true"
|
||||||
" [" [:a
|
:hx-select "#history-table"
|
||||||
{:hx-get (str "/admin/history/inspect/" v)
|
:hx-target "#history-table"}
|
||||||
:hx-swap "innerHTML"
|
v)
|
||||||
:hx-target "#inspector"
|
" ["
|
||||||
:hx-trigger "click"
|
(com/link
|
||||||
"_" error-script}
|
{:href "#"
|
||||||
"snapshot"] "]"]
|
:hx-get (str "/admin/history/inspect/" v)
|
||||||
|
:hx-swap "innerHTML"
|
||||||
|
:hx-target "#inspector"
|
||||||
|
:hx-trigger "click"}
|
||||||
|
"snapshot") "]"]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(pr-str v)))
|
(pr-str v)))
|
||||||
|
|
||||||
(defn page-template [& {:keys [table entity-id]}]
|
|
||||||
[:div
|
|
||||||
[:div.columns
|
|
||||||
[:div.column.is-4
|
|
||||||
[:form {"hx-target" "#history-table"
|
|
||||||
"hx-post" "/admin/history/search"
|
|
||||||
"hx-swap" "innerHTML"
|
|
||||||
"_" (hiccup/raw "on htmx:beforeRequest toggle @disabled on me then toggle .is-loading on <#dig/> end
|
|
||||||
on htmx:afterRequest toggle @disabled on me then toggle .is-loading on <#dig /> end")
|
|
||||||
}
|
|
||||||
[:div.field.is-grouped
|
|
||||||
[:p.control {}
|
|
||||||
[:input.input {:type "text" :name "entity-id" :placeholder "Entity id" :value entity-id}]]
|
|
||||||
[:p.control
|
|
||||||
[:button#dig.button.is-primary {}
|
|
||||||
"Dig"]]]]]]
|
|
||||||
[:div#history-table
|
|
||||||
table]])
|
|
||||||
|
|
||||||
(defn table [entity-id best-guess-entity history]
|
|
||||||
[:div [:h1.title "History for "
|
|
||||||
(str/capitalize best-guess-entity)
|
|
||||||
" "
|
|
||||||
entity-id]
|
|
||||||
[:div.columns
|
|
||||||
[:div.column.is-9
|
|
||||||
[:table.table.compact.grid {:style "width: 100%"}
|
|
||||||
[:thead
|
|
||||||
[:tr
|
|
||||||
[:td {:style "width: 14em"} "Date"]
|
|
||||||
[:td {:style "width: 14em"} "User"]
|
|
||||||
[:td {:style "width: 18em"} "Field"]
|
|
||||||
[:td "From"]
|
|
||||||
[:td "To"]]]
|
|
||||||
[:tbody
|
|
||||||
(for [[tx a c] history]
|
|
||||||
[:tr
|
|
||||||
[:td [:div [:div (some-> (:db/txInstant tx)
|
|
||||||
coerce/to-date-time
|
|
||||||
atime/localize
|
|
||||||
(atime/unparse atime/standard-time))
|
|
||||||
]
|
|
||||||
[:div.tag (:db/id tx)]]]
|
|
||||||
[:td (str (:audit/user tx))]
|
|
||||||
[:td (namespace a) ": " (name a)]
|
|
||||||
|
|
||||||
[:td
|
|
||||||
[:div.tag.is-danger.is-light
|
|
||||||
[:span
|
|
||||||
(format-value (:removed c))]]]
|
|
||||||
[:td
|
|
||||||
[:div.tag.is-primary.is-light
|
|
||||||
[:span
|
|
||||||
(format-value (:added c))]]]])]
|
|
||||||
]]
|
|
||||||
[:div.column.is-3
|
|
||||||
[:div#inspector]]]])
|
|
||||||
|
|
||||||
(defn history-search [{:keys [form-params params] :as request}]
|
|
||||||
(try
|
|
||||||
(let [entity-id (Long/parseLong (or (some-> (:entity-id form-params) not-empty)
|
|
||||||
(:entity-id params)
|
|
||||||
(get params "entity-id")
|
|
||||||
(get form-params "entity-id")))
|
|
||||||
history (->>
|
|
||||||
(dc/q '[:find ?a2 ?v (pull ?tx [:db/txInstant :audit/user :db/id]) ?ad
|
|
||||||
:in $ $$ ?i
|
|
||||||
:where
|
|
||||||
[$$ ?i ?a ?v ?tx ?ad]
|
|
||||||
[$ ?a :db/ident ?a2]]
|
|
||||||
(dc/db conn)
|
|
||||||
(dc/history (dc/db conn))
|
|
||||||
entity-id )
|
|
||||||
tx-rows->changes
|
|
||||||
(sort-by (comp :db/id first))
|
|
||||||
vec)
|
|
||||||
best-guess-entity (or (->> history
|
|
||||||
(group-by
|
|
||||||
(comp
|
|
||||||
namespace
|
|
||||||
second)
|
|
||||||
)
|
|
||||||
(map (fn [[k v]]
|
|
||||||
[k v]))
|
|
||||||
(sort-by second)
|
|
||||||
last
|
|
||||||
first)
|
|
||||||
"?")]
|
|
||||||
|
|
||||||
(if (get (:headers request) "hx-request")
|
|
||||||
(html-response
|
|
||||||
(table entity-id best-guess-entity history))
|
|
||||||
(base-page request (page-template :table (table entity-id best-guess-entity history)
|
|
||||||
:entity-id entity-id)
|
|
||||||
(admin-side-bar :admin-history))))
|
|
||||||
(catch NumberFormatException _
|
|
||||||
(html-response
|
|
||||||
[:div.notification.is-danger.is-light
|
|
||||||
"Cannot parse the entity-id " (or (:entity-id form-params)
|
|
||||||
(:entity-id params))
|
|
||||||
|
|
||||||
". It should be a number."]))))
|
|
||||||
|
|
||||||
(defn inspect [{{:keys [entity-id]} :params :as request}]
|
(defn inspect [{{:keys [entity-id]} :params :as request}]
|
||||||
(alog/info ::inspect
|
(alog/info ::inspect
|
||||||
@@ -167,34 +66,126 @@
|
|||||||
(try
|
(try
|
||||||
(let [entity-id (Long/parseLong entity-id)
|
(let [entity-id (Long/parseLong entity-id)
|
||||||
data (dc/pull (dc/db conn)
|
data (dc/pull (dc/db conn)
|
||||||
'[*]
|
'[*]
|
||||||
entity-id)]
|
entity-id)]
|
||||||
|
|
||||||
(html-response
|
(html-response
|
||||||
[:div.box {:style {:position "sticky"
|
[:section.py-3.sm:py-5.max-w-lg
|
||||||
:display "inline-block"
|
(com/card {:class "p-2"}
|
||||||
:vertical-align "top"
|
[:div {:style {:display "inline-block"}}
|
||||||
:overflow-y "auto"
|
[:h1.title "Snapshot of "
|
||||||
:max-height "100vh"
|
entity-id]
|
||||||
:top "0px"
|
[:ul
|
||||||
:bottom "0px"}}
|
(for [[k v] data]
|
||||||
[:div {:style {:display "inline-block"}}
|
[:li [:strong k] ":" (format-value v)])]])]))
|
||||||
[:h1.title "Snapshot of "
|
|
||||||
entity-id]
|
|
||||||
[:ul
|
|
||||||
(for [[k v] data]
|
|
||||||
[:li [:strong k] ":" (format-value v)]
|
|
||||||
)]]]))
|
|
||||||
(catch NumberFormatException _
|
(catch NumberFormatException _
|
||||||
(html-response
|
(html-response
|
||||||
[:div.notification.is-danger.is-light
|
[:div.notification.is-danger.is-light
|
||||||
"Cannot parse the entity-id " entity-id ". It should be a number."]))))
|
"Cannot parse the entity-id " entity-id ". It should be a number."]))))
|
||||||
|
|
||||||
(defn history [{:keys [matched-route] :as request}]
|
|
||||||
(base-page request
|
|
||||||
(page-template )
|
|
||||||
(admin-side-bar matched-route)))
|
|
||||||
|
|
||||||
|
(defn result-table [{:keys [entity-id]}]
|
||||||
|
(try
|
||||||
|
(let [history (->>
|
||||||
|
(dc/q '[:find ?a2 ?v (pull ?tx [:db/txInstant :audit/user :db/id]) ?ad
|
||||||
|
:in $ $$ ?i
|
||||||
|
:where
|
||||||
|
[$$ ?i ?a ?v ?tx ?ad]
|
||||||
|
[$ ?a :db/ident ?a2]]
|
||||||
|
(dc/db conn)
|
||||||
|
(dc/history (dc/db conn))
|
||||||
|
entity-id)
|
||||||
|
tx-rows->changes
|
||||||
|
(sort-by (comp :db/id first))
|
||||||
|
vec)
|
||||||
|
best-guess-entity (or (->> history
|
||||||
|
(group-by
|
||||||
|
(comp
|
||||||
|
namespace
|
||||||
|
second))
|
||||||
|
(map (fn [[k v]]
|
||||||
|
[k v]))
|
||||||
|
(sort-by second)
|
||||||
|
last
|
||||||
|
first)
|
||||||
|
"?")]
|
||||||
|
(com/data-grid-card {:id "history-table"
|
||||||
|
:title (format "History for %s: %d" (str/capitalize best-guess-entity) entity-id)
|
||||||
|
:route :history-table
|
||||||
|
:start 0
|
||||||
|
:per-page (count history)
|
||||||
|
:total (count history)
|
||||||
|
:subtitle nil
|
||||||
|
:action-buttons nil
|
||||||
|
:rows (for [[tx a c] history]
|
||||||
|
(com/data-grid-row
|
||||||
|
{}
|
||||||
|
(com/data-grid-cell {} [:div [:div (some-> (:db/txInstant tx)
|
||||||
|
coerce/to-date-time
|
||||||
|
atime/localize
|
||||||
|
(atime/unparse atime/standard-time))]
|
||||||
|
[:div.tag (:db/id tx)]])
|
||||||
|
(com/data-grid-cell {} (str (:audit/user tx)))
|
||||||
|
(com/data-grid-cell {} (namespace a) ": " (name a))
|
||||||
|
|
||||||
|
(com/data-grid-cell {}
|
||||||
|
(com/pill {:color :red}
|
||||||
|
(format-value (:removed c))))
|
||||||
|
(com/data-grid-cell {}
|
||||||
|
[:div.tag.is-primary.is-light
|
||||||
|
[:span
|
||||||
|
(format-value (:added c))]])))
|
||||||
|
:headers
|
||||||
|
[(com/data-grid-header {}
|
||||||
|
"Date")
|
||||||
|
(com/data-grid-header {}
|
||||||
|
"User")
|
||||||
|
(com/data-grid-header {}
|
||||||
|
"Field")
|
||||||
|
(com/data-grid-header {}
|
||||||
|
"From")
|
||||||
|
(com/data-grid-header {}
|
||||||
|
"To")]}))
|
||||||
|
(catch NumberFormatException e
|
||||||
|
(throw e))))
|
||||||
|
|
||||||
|
(defn search-box [{:keys [entity-id]}]
|
||||||
|
[:div.mt-4
|
||||||
|
[:form.flex.gap-2 {"hx-target" "#history-table"
|
||||||
|
"hx-get" (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-history)
|
||||||
|
"hx-select" "#history-table"
|
||||||
|
"hx-swap" "innerHTML"
|
||||||
|
"hx-ext" "debug"
|
||||||
|
"hx-push-url" "true"}
|
||||||
|
(com/text-input {:name "entity-id" :placeholder "Entity Id" :value entity-id
|
||||||
|
:style {:width "300px"}})
|
||||||
|
(com/button {:color :primary}
|
||||||
|
"DIG")]])
|
||||||
|
|
||||||
|
(defn history [{:keys [matched-route route-params query-params] :as request}]
|
||||||
|
(let [entity-id (or (some-> query-params (get "entity-id") Long/parseLong)
|
||||||
|
(some-> route-params (get :entity-id) Long/parseLong))]
|
||||||
|
(base-page request
|
||||||
|
(com/page {:nav (com/company-aside-nav)
|
||||||
|
:active-client (:client (:session request))
|
||||||
|
:identity (:identity request)
|
||||||
|
:app-params {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-history)
|
||||||
|
:hx-trigger "clientSelected from:body"
|
||||||
|
:hx-select "#app-contents"
|
||||||
|
:hx-swap "outerHTML swap:300ms"}}
|
||||||
|
(com/breadcrumbs {}
|
||||||
|
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin)}
|
||||||
|
"Admin"]
|
||||||
|
[:a {:href (bidi/path-for ssr-routes/only-routes
|
||||||
|
:admin-history)}
|
||||||
|
"History"])
|
||||||
|
(search-box {:entity-id entity-id})
|
||||||
|
[:div.flex.gap-4.flex-col.lg:flex-row
|
||||||
|
(if entity-id
|
||||||
|
(result-table {:entity-id entity-id})
|
||||||
|
[:div#history-table])
|
||||||
|
[:div#inspector]
|
||||||
|
])
|
||||||
|
nil)))
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
:vendor-id (:db/id (second e)))
|
:vendor-id (:db/id (second e)))
|
||||||
"?"
|
"?"
|
||||||
(url/map->query {:client-id (:db/id (first e))}))
|
(url/map->query {:client-id (:db/id (first e))}))
|
||||||
|
:hx-ext "debug"
|
||||||
:hx-target "#modal-holder"
|
:hx-target "#modal-holder"
|
||||||
:hx-swap "outerHTML"}
|
:hx-swap "outerHTML"}
|
||||||
svg/pencil)])
|
svg/pencil)])
|
||||||
@@ -183,7 +184,7 @@
|
|||||||
{:key "address"
|
{:key "address"
|
||||||
:name "Address"
|
:name "Address"
|
||||||
:sort-key "address"
|
:sort-key "address"
|
||||||
:show-starting "lg"
|
:show-starting "lg"
|
||||||
:render (fn [[_ vendor]]
|
:render (fn [[_ vendor]]
|
||||||
(if (-> vendor :vendor/address :address/street1)
|
(if (-> vendor :vendor/address :address/street1)
|
||||||
[:div
|
[:div
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
(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-)
|
||||||
|
(def main-aside-nav aside/main-aside-nav-)
|
||||||
(def content-card card/content-card-)
|
(def content-card card/content-card-)
|
||||||
(def card card/card-)
|
(def card card/card-)
|
||||||
|
|
||||||
@@ -42,9 +43,8 @@
|
|||||||
(def data-grid-cell data-grid/cell-)
|
(def data-grid-cell data-grid/cell-)
|
||||||
(def data-grid-right-stack-cell data-grid/right-stack-cell-)
|
(def data-grid-right-stack-cell data-grid/right-stack-cell-)
|
||||||
|
|
||||||
(defn link [{:keys [class href]} & children]
|
(defn link [params & children]
|
||||||
(into [:a {:href href
|
(into [:a (update params :class str " font-medium text-blue-600 dark:text-blue-500 hover:underline ")]
|
||||||
:class (str "font-medium text-blue-600 dark:text-blue-500 hover:underline " class)}]
|
|
||||||
children))
|
children))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
[:ul {:id (:id params) :class "hidden py-2 space-y-2"}
|
[:ul {:id (:id params) :class "hidden py-2 space-y-2"}
|
||||||
(for [c children]
|
(for [c children]
|
||||||
[:li
|
[:li
|
||||||
(update-in c [1 :class ] str " flex items-center p-2 pl-11 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")])])
|
(update-in c [1 1 :class ] str " flex items-center p-2 pl-11 w-full text-base font-normal text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")])])
|
||||||
|
|
||||||
(defn left-aside- [{:keys [nav page-specific]} & children]
|
(defn left-aside- [{:keys [nav page-specific]} & children]
|
||||||
[:aside {:id "left-nav", :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform -translate-x-full lg:translate-x-0", :aria-labelledby "left-nav" :aria-hidden "true"}
|
[:aside {:id "left-nav", :class "fixed top-0 left-0 pt-16 z-20 w-64 h-screen transition-transform -translate-x-full lg:translate-x-0", :aria-labelledby "left-nav" :aria-hidden "true"}
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var collapse = new Collapse($targetEl, $triggerEl, options);
|
// var collapse = new Collapse($targetEl, $triggerEl, options);
|
||||||
|
|
||||||
")]])
|
")]])
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
(ns auto-ap.ssr.components.card)
|
(ns auto-ap.ssr.components.card)
|
||||||
|
|
||||||
(defn card- [params & children]
|
(defn card- [params & children]
|
||||||
(into [:div {:class "shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white overflow-hidden"}]
|
(into [:div (update params :class str " shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white overflow-hidden")]
|
||||||
children))
|
children))
|
||||||
|
|
||||||
(defn content-card- [params & children]
|
(defn content-card- [params & children]
|
||||||
|
|||||||
@@ -46,9 +46,13 @@
|
|||||||
[:tbody]
|
[:tbody]
|
||||||
rest)])
|
rest)])
|
||||||
|
|
||||||
|
;; needed for tailwind
|
||||||
|
;; lg:table-cell md:table-cell
|
||||||
|
|
||||||
(defn data-grid-card- [{:keys [id
|
(defn data-grid-card- [{:keys [id
|
||||||
route
|
route
|
||||||
title
|
title
|
||||||
|
paginate?
|
||||||
action-buttons
|
action-buttons
|
||||||
total
|
total
|
||||||
subtitle
|
subtitle
|
||||||
@@ -60,37 +64,36 @@
|
|||||||
rows] :as params}]
|
rows] :as params}]
|
||||||
[:div {:hx-get (bidi/path-for ssr-routes/only-routes
|
[:div {:hx-get (bidi/path-for ssr-routes/only-routes
|
||||||
route
|
route
|
||||||
:request-method :get)
|
:request-method :get)
|
||||||
:hx-trigger "clientSelected from:body"
|
:hx-trigger "clientSelected from:body"
|
||||||
:hx-swap "outerHTML swap:300ms"
|
:hx-swap "outerHTML swap:300ms"
|
||||||
:id id}
|
:id id}
|
||||||
(content-card-
|
(content-card-
|
||||||
{}
|
{}
|
||||||
[:div {:class "flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
|
[:div {:class "flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
|
||||||
[:div
|
[:div
|
||||||
[:h1.text-2xl.mb-3.font-bold title]
|
[:h1.text-2xl.mb-3.font-bold title]
|
||||||
[:div {:class "flex items-center flex-1 space-x-4"}
|
[:div {:class "flex items-center flex-1 space-x-4"}
|
||||||
[:h5
|
[:h5
|
||||||
(when subtitle
|
(when subtitle
|
||||||
[:span subtitle])]]]
|
[:span subtitle])]]]
|
||||||
(into [:div {:class "flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}
|
(into [:div {:class "flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}]
|
||||||
]
|
action-buttons)]
|
||||||
action-buttons)]
|
[:div {:class "overflow-x-auto"}
|
||||||
[:div {:class "overflow-x-auto"}
|
(data-grid- {:headers headers
|
||||||
(data-grid- {:headers headers
|
:thead-params thead-params}
|
||||||
:thead-params thead-params
|
rows)]
|
||||||
}
|
|
||||||
rows
|
|
||||||
|
|
||||||
)]
|
(when (or paginate?
|
||||||
(paginator- {:start start
|
(not (nil? paginate?)))
|
||||||
:end (Math/min (+ start per-page) total)
|
(paginator- {:start start
|
||||||
:per-page per-page
|
:end (Math/min (+ start per-page) total)
|
||||||
:total total
|
:per-page per-page
|
||||||
:a-params (fn [page]
|
:total total
|
||||||
{:hx-get (str (bidi/path-for ssr-routes/only-routes
|
:a-params (fn [page]
|
||||||
route
|
{:hx-get (str (bidi/path-for ssr-routes/only-routes
|
||||||
:request-method :get)
|
route
|
||||||
"?start=" (* page per-page))
|
:request-method :get)
|
||||||
:hx-target (str "#" id)
|
"?start=" (* page per-page))
|
||||||
:hx-swap "outerHTML show:#app:top"})}))])
|
:hx-target (str "#" id)
|
||||||
|
:hx-swap "outerHTML show:#app:top"})})))])
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
[:div#app
|
[:div#app
|
||||||
(navbar- {:client active-client
|
(navbar- {:client active-client
|
||||||
:identity identity})
|
:identity identity})
|
||||||
[:div#app-contents.flex.pt-16.overflow-hidden app-params
|
[:div#app-contents.flex.pt-16.overflow-hidden (assoc app-params :hx-disinherit "*")
|
||||||
(left-aside- {:nav nav
|
(left-aside- {:nav nav
|
||||||
:page-specific page-specific})
|
:page-specific page-specific})
|
||||||
[:div#main-content {:class "relative w-full h-full lg:pl-64 overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content "
|
[:div#main-content {:class "relative w-full h-full lg:pl-64 overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content "
|
||||||
|
|||||||
@@ -2,17 +2,19 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn pill- [params & children]
|
(defn pill- [params & children]
|
||||||
(into
|
(into
|
||||||
[:span (cond-> params
|
[:span (cond-> params
|
||||||
true (update :class str " text-xs font-medium px-2 py-0.5 rounded whitespace-nowrap")
|
true (update :class str " text-xs font-medium px-2 py-0.5 rounded whitespace-nowrap")
|
||||||
|
|
||||||
(= :primary (:color params))
|
(= :primary (:color params))
|
||||||
(update :class str " bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300 ")
|
(update :class str " bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300 ")
|
||||||
|
|
||||||
(= :secondary (:color params))
|
(= :secondary (:color params))
|
||||||
(update :class str " bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300 ")
|
(update :class str " bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300 ")
|
||||||
|
|
||||||
(= :yellow (:color params))
|
(= :yellow (:color params))
|
||||||
(update :class str " bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300")
|
(update :class str " bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300")
|
||||||
)]
|
|
||||||
children))
|
(= :red (:color params))
|
||||||
|
(update :class str " bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300"))]
|
||||||
|
children))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
[:button#user-menu-button {:type "button", :class "flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600", :aria-expanded "false"
|
[:button#user-menu-button {:type "button", :class "flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600", :aria-expanded "false"
|
||||||
"_" (hiccup/raw "init call initUserDropdown()")}
|
"_" (hiccup/raw "init call initUserDropdown()")}
|
||||||
[:span {:class "sr-only"} "Open user menu"]
|
[:span {:class "sr-only"} "Open user menu"]
|
||||||
[:img {:class "w-8 h-8 rounded-full", :src (pull-attr (dc/db conn) :user/profile-image-url (:db/id identity)) :alt "user photo"}]]]
|
[:img {:class "w-8 h-8 rounded-full", :src (pull-attr (dc/db conn) :user/profile-image-url (:db/id identity)) :alt "user photo" :referrerpolicy "no-referrer"}]]]
|
||||||
[:div#user-menu {:class "z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600 mr-10"}
|
[:div#user-menu {:class "z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600 mr-10"}
|
||||||
[:div {:class "px-4 py-3", :role "none"}
|
[:div {:class "px-4 py-3", :role "none"}
|
||||||
[:p {:class "text-sm text-gray-900 dark:text-white", :role "none"} (:user/name identity)]
|
[:p {:class "text-sm text-gray-900 dark:text-white", :role "none"} (:user/name identity)]
|
||||||
|
|||||||
@@ -12,53 +12,30 @@
|
|||||||
hiccup))})
|
hiccup))})
|
||||||
|
|
||||||
(defn base-page [request contents side-bar-contents]
|
(defn base-page [request contents side-bar-contents]
|
||||||
(html-page
|
(html-page
|
||||||
[:html.has-navbar-fixed-top
|
[:html.has-navbar-fixed-top
|
||||||
[:head
|
[:head
|
||||||
[:meta {:charset "utf-8"}]
|
[:meta {:charset "utf-8"}]
|
||||||
[:meta {:http-equiv "X-UA-Compatible", :content "IE=edge"}]
|
[:meta {:http-equiv "X-UA-Compatible", :content "IE=edge"}]
|
||||||
[:meta {:name "viewport", :content "width=device-width, initial-scale=1"}]
|
[:meta {:name "viewport", :content "width=device-width, initial-scale=1"}]
|
||||||
[:title "Integreat"]
|
[:title "Integreat"]
|
||||||
[:link {:href "/css/font.min.css", :rel "stylesheet"}]
|
[:link {:href "/css/font.min.css", :rel "stylesheet"}]
|
||||||
[:link {:rel "stylesheet", :href "/css/react-datepicker.min.inc.css"}]
|
[:link {:rel "stylesheet", :href "/css/react-datepicker.min.inc.css"}]
|
||||||
[:link {:rel "stylesheet", :href "/output.css"}]
|
[:link {:rel "stylesheet", :href "/output.css"}]
|
||||||
[:script {:src "https://unpkg.com/hyperscript.org@0.9.7/dist/_hyperscript.min.js"}]
|
|
||||||
[:script {:src "https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js"}]
|
|
||||||
#_[:script {:src "https://unpkg.com/htmx.org@1.8.4"
|
|
||||||
:integrity "sha384-wg5Y/JwF7VxGk4zLsJEcAojRtlVp1FKKdGy1qN+OMtdq72WRvX/EdRdqg/LOhYeV"
|
|
||||||
:crossorigin= "anonymous"}]
|
|
||||||
[:script {:src "https://unpkg.com/htmx.org@1.9.0/dist/htmx.js"
|
|
||||||
:crossorigin= "anonymous"}]
|
|
||||||
[:script {:src "/js/htmx-disable.js"}]
|
|
||||||
[:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async" }]]
|
|
||||||
[:script {:type "text/javascript", :src "https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/autoComplete.min.js"}]
|
|
||||||
[:script {:src "https://unpkg.com/dropzone@5.9.3/dist/min/dropzone.min.js"}]
|
|
||||||
[:link {:rel "stylesheet" :href "https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" :type "text/css"}]
|
|
||||||
[:body {:hx-ext "disable-submit"
|
|
||||||
}
|
|
||||||
contents
|
|
||||||
[:script {:src "/js/flowbite.min.js"}]
|
|
||||||
[:script {:lang "text/javascript"}
|
|
||||||
(hiccup/raw "
|
|
||||||
var $targetEl = document.getElementById('left-nav');
|
|
||||||
|
|
||||||
var $triggerEl = document.getElementById('left-nav-toggle');
|
[:script {:src "https://unpkg.com/hyperscript.org@0.9.7/dist/_hyperscript.min.js"}]
|
||||||
|
[:script {:src "https://unpkg.com/@popperjs/core@2.11.8/dist/umd/popper.min.js"}]
|
||||||
var options = {
|
#_[:script {:src "https://unpkg.com/htmx.org@1.8.4"
|
||||||
onCollapse: () => {
|
:integrity "sha384-wg5Y/JwF7VxGk4zLsJEcAojRtlVp1FKKdGy1qN+OMtdq72WRvX/EdRdqg/LOhYeV"
|
||||||
document.getElementById('main-content').classList.remove('lg:pl-64')
|
:crossorigin= "anonymous"}]
|
||||||
},
|
[:script {:src "https://unpkg.com/htmx.org@1.9.0/dist/htmx.js"
|
||||||
onExpand: () => {
|
:crossorigin= "anonymous"}]
|
||||||
document.getElementById('main-content').classList.add('lg:pl-64')
|
[:script {:src "https://unpkg.com/htmx.org/dist/ext/debug.js"}]
|
||||||
},
|
[:script {:src "/js/htmx-disable.js"}]
|
||||||
onToggle: () => {
|
[:script {:type "text/javascript", :src "https://cdn.yodlee.com/fastlink/v4/initialize.js", :async "async"}]]
|
||||||
}
|
[:script {:type "text/javascript", :src "https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/autoComplete.min.js"}]
|
||||||
};
|
[:script {:src "https://unpkg.com/dropzone@5.9.3/dist/min/dropzone.min.js"}]
|
||||||
|
[:link {:rel "stylesheet" :href "https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" :type "text/css"}]
|
||||||
var collapse = new Collapse($targetEl, $triggerEl, options);
|
[:body {:hx-ext "disable-submit"}
|
||||||
|
contents
|
||||||
"
|
[:script {:src "/js/flowbite.min.js"}]]]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
)]]]))
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"admin" {"/history" {"" :admin-history
|
"admin" {"/history" {"" :admin-history
|
||||||
"/" :admin-history
|
"/" :admin-history
|
||||||
#"/search/?" :admin-history-search
|
#"/search/?" :admin-history-search
|
||||||
["/" [#"\d+" :entity-id] #"/?"] :admin-history-search
|
["/" [#"\d+" :entity-id] #"/?"] :admin-history
|
||||||
["/inspect/" [#"\d+" :entity-id] #"/?"] :admin-history-inspect}
|
["/inspect/" [#"\d+" :entity-id] #"/?"] :admin-history-inspect}
|
||||||
"/ezcater-xls" :admin-ezcater-xls}
|
"/ezcater-xls" :admin-ezcater-xls}
|
||||||
"transaction" {"/insights" {"" :transaction-insights
|
"transaction" {"/insights" {"" :transaction-insights
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: "class",
|
darkMode: "class",
|
||||||
content: ["./src/**/*.{cljs,clj}",
|
content: ["./src/**/*.{cljs,clj,cljc}",
|
||||||
"./node_modules/flowbite/**/*.js"],
|
"./node_modules/flowbite/**/*.js"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
|||||||
Reference in New Issue
Block a user