Last active
January 10, 2025 15:41
-
-
Save dustingetz/5f089be0e3dc66c13b2e57b4349f47ed to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns dustingetz.edn-viewer0 | |
(:require [clojure.datafy :refer [datafy]] | |
[clojure.core.protocols :refer [nav]] | |
[contrib.data :refer [unqualify]] | |
[dustingetz.easy-table :refer [TableScroll Load-css]] | |
[dustingetz.flatten-document :refer [flatten-nested]] | |
[hyperfiddle.electric3 :as e] | |
[hyperfiddle.electric3-contrib :refer [Tap]] | |
[hyperfiddle.electric-dom3 :as dom] | |
[hyperfiddle.electric-forms0 :refer [Checkbox*]] | |
[hyperfiddle.router3 :as router] | |
[hyperfiddle.rcf :refer [tests]])) | |
(defn nav-in [m path] | |
(loop [m m, path path] | |
(if-some [[p & ps] (seq path)] | |
(let [v (get m p) | |
v (if (fn? v) (v) v)] ; hyperlink == fn | |
(recur (datafy (nav m p v)) ps)) ; todo revisit | |
m))) | |
(tests | |
(nav-in {} nil) := {} | |
(nav-in {} []) := {} | |
(nav-in {:a 1} [:a]) | |
(nav {:a 1} :a 1) | |
(nav-in {:a {:b 2}} [:a :b]) := 2) | |
(e/defn ColumnPicker [cols] | |
(e/client | |
(let [state (e/for [col (e/diff-by {} cols)] | |
{col (Checkbox* true :label (unqualify col))})] | |
(reduce-kv (fn [x k v] (if v (conj x k) x)) | |
[] (apply merge (e/as-vec state)))))) | |
#?(:clj (defmulti title (fn [m] (some-> m meta :clojure.datafy/class)))) | |
#?(:clj (defmethod title :default [m] (some-> m meta :clojure.datafy/class))) | |
(e/defn DocumentRow [{:keys [path name value]}] | |
(e/client | |
(dom/td (dom/props {:style {:padding-left (some-> path count (* 15) (str "px"))}}) | |
(dom/span (dom/props {:class "dustingetz-tooltip"}) ; hover anchor | |
(dom/text (unqualify name)) ; label | |
(dom/span (dom/text (pr-str name))))) | |
(dom/td | |
(let [v-str (e/server (pr-str value))] | |
(if (e/server (fn? value)) ; fns encode hyperlinks (on the server!) | |
(router/link ['. [(conj path name)]] (dom/text "...")) | |
(dom/text v-str)))))) | |
(e/defn CollectionRow [cols ?x] | |
(e/server | |
(let [?m (datafy ?x)] ; only visible rows | |
(e/for [k cols] | |
(dom/td (some-> ?m k pr-str dom/text)))))) | |
(declare css) | |
(e/defn EntityBrowser [x ?focus-path] | |
(dom/style (dom/text css)) (Load-css "dustingetz/easy_table.css") | |
(dom/div (dom/props {:class (str "Browser dustingetz-EasyTable")}) | |
(e/server | |
(let [m (datafy x)] | |
(dom/fieldset (dom/props {:class "entity"}) | |
(let [xs! (flatten-nested m)] | |
(dom/legend (dom/text (title m))) | |
(TableScroll (count xs!) | |
(e/fn Row [i] (when-some [x (nth xs! i nil)] | |
(DocumentRow x)))))) | |
(dom/fieldset (dom/props {:class "entity-children"}) | |
(let [xs! (if (seq ?focus-path) (nav-in m (seq ?focus-path))) | |
colspec (dom/legend (dom/text (pr-str (mapv unqualify ?focus-path)) " ") | |
(ColumnPicker (some-> xs! first datafy keys))) | |
cols (e/diff-by {} colspec)] | |
(dom/props {:style {:--col-count (count colspec)}}) | |
(TableScroll (count xs!) | |
(e/fn Row [i] (e/server (when-some [x (nth xs! i nil)] | |
(CollectionRow cols x))))))))))) | |
(e/defn EdnViewer0 | |
([] (EdnViewer0 (e/server (Tap)))) ; default to clojure tap> inspector | |
([x] (e/client (router/Apply (e/Partial EntityBrowser x) [nil])))) ; x is not route-bound | |
(def css " | |
.Browser fieldset.entity { position:fixed; top:0; bottom:50%; left:0; right:0; } | |
.Browser fieldset.entity-children { position:fixed; top:50%; bottom:0; left:0; right:0; } | |
.Browser fieldset.entity table { grid-template-columns: 20em auto; } | |
.Browser fieldset.entity-children table { grid-template-columns: repeat(var(--col-count), 1fr); } | |
.Browser fieldset table td a { font-weight: 600; } | |
/* table cell tooltips */ | |
.Browser td {position: relative;} | |
.Browser .dustingetz-tooltip > span { visibility: hidden; } | |
.Browser .dustingetz-tooltip:hover > span { visibility: visible; pointer-events: none; } | |
.Browser .dustingetz-tooltip > span { | |
position: absolute; top: 20px; left: 10px; z-index: 2; /* interaction with row selection z=1 */ | |
margin-top: 4px; padding: 4px; font-size: smaller; | |
box-shadow: 0 0 .5rem gray; border: 1px whitesmoke solid; border-radius: 3px; background-color: white; }") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns dustingetz.flatten-document) | |
(defn flatten-nested ; claude generated this | |
([data] (flatten-nested data [])) | |
([data path] | |
(cond | |
(map? data) | |
(mapcat (fn [[k v]] | |
(cond | |
(map? v) | |
(cons {:path path :name k} (flatten-nested v (conj path k))) | |
; render collections of records as hyperlinks | |
(and (sequential? v) (map? (first v))) | |
[{:path path :name k :value (constantly v)}] ; lift | |
; render simple collections inline | |
(and (sequential? v) (not (map? (first v)))) | |
[{:path path :name k :value v}] | |
#_#_(nil? v) [{:path path :name k}] | |
() [{:path path :name k :value v}])) | |
data) | |
; render simple collections as indexed maps | |
(sequential? data) | |
(mapcat (fn [i v] | |
(cond | |
(or (map? v) (sequential? v)) | |
(cons {:path path :name i} | |
(flatten-nested v (conj path i))) | |
() | |
[{:path path :name i :value v}])) | |
(range) data) | |
; what else? | |
() [{:path path :value data}]))) | |
(comment | |
(def test-data | |
'{:response | |
{:Owner | |
{:DisplayName string | |
:ID string} | |
:Grants | |
{:seq-of | |
{:Grantee | |
{:DisplayName string | |
:EmailAddress string | |
:ID string | |
:Type [:one-of ["CanonicalUser" "AmazonCustomerByEmail" "Group"]] | |
:URI string} | |
:Permission [:one-of ["FULL_CONTROL" "WRITE" "WRITE_ACP" "READ" "READ_ACP"]]}}}}) | |
(flatten-nested test-data) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment