From 090cf0cf8eca11d704a4dc1a83684220dbb49534 Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Wed, 26 Jul 2023 12:33:08 +0200 Subject: [PATCH 1/4] Format shadow-cljs.edn with cljfmt --- examples/todomvc/shadow-cljs.edn | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/todomvc/shadow-cljs.edn b/examples/todomvc/shadow-cljs.edn index 39bb8801..23efd323 100644 --- a/examples/todomvc/shadow-cljs.edn +++ b/examples/todomvc/shadow-cljs.edn @@ -15,24 +15,24 @@ :nrepl {:port 8777} :builds - {:app - {:target :browser - :output-dir "resources/public/js" - :modules - {:todomvc - {:init-fn todomvc.core/main - :preloads [day8.re-frame-10x.preload]}} - :dev - {:compiler-options - {:infer-externs false - :closure-defines - {re-frame.trace.trace-enabled? true - day8.re-frame-10x.debug? true - day8.re-frame.tracing.trace-enabled? true} - :external-config - {:devtools/config - {:features-to-install - [:formatters :hints]}}}} - :devtools - {:http-root "resources/public" - :http-port 8280}}}} + {:app + {:target :browser + :output-dir "resources/public/js" + :modules + {:todomvc + {:init-fn todomvc.core/main + :preloads [day8.re-frame-10x.preload]}} + :dev + {:compiler-options + {:infer-externs false + :closure-defines + {re-frame.trace.trace-enabled? true + day8.re-frame-10x.debug? true + day8.re-frame.tracing.trace-enabled? true} + :external-config + {:devtools/config + {:features-to-install + [:formatters :hints]}}}} + :devtools + {:http-root "resources/public" + :http-port 8280}}}} From e000cfc795404f72bd9f2905993a2cb8475fdccc Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Wed, 26 Jul 2023 14:51:43 +0200 Subject: [PATCH 2/4] Extract a helper fn for default values --- src/day8/re_frame_10x/events.cljs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/day8/re_frame_10x/events.cljs b/src/day8/re_frame_10x/events.cljs index 1878307a..46b57790 100644 --- a/src/day8/re_frame_10x/events.cljs +++ b/src/day8/re_frame_10x/events.cljs @@ -13,6 +13,11 @@ [day8.re-frame-10x.panels.settings.events :as settings.events] [day8.re-frame-10x.panels.traces.events :as traces.events])) +(defn sortable-uuid-map [vals] + (let [entry (fn [id v i] + [id (into {:id id :sort i} v)])] + (into {} (map entry (repeatedly random-uuid) vals (range))))) + (rf/reg-event-fx ::init [(rf/inject-cofx ::local-storage/load {:key "panel-width-ratio" :or 0.35}) @@ -21,15 +26,16 @@ (rf/inject-cofx ::local-storage/load {:key "filter-items" :or []}) (rf/inject-cofx ::local-storage/load {:key "app-db-json-ml-expansions" :or #{}}) (rf/inject-cofx ::local-storage/load {:key "external-window?" :or false}) - (rf/inject-cofx ::local-storage/load {:key "external-window-dimensions" :or {:width 800 :height 800 :top 0 :left 0}}) + (rf/inject-cofx ::local-storage/load {:key "external-window-dimensions" + :or {:width 800 :height 800 :top 0 :left 0}}) (rf/inject-cofx ::local-storage/load {:key "show-epoch-traces?" :or true}) (rf/inject-cofx ::local-storage/load {:key "using-trace?" :or true}) (rf/inject-cofx ::local-storage/load {:key "ignored-events" :or {}}) (rf/inject-cofx ::local-storage/load {:key "low-level-trace" :or {:reagent true :re-frame true}}) - (rf/inject-cofx ::local-storage/load {:key "filtered-view-trace" :or (let [id1 (random-uuid) - id2 (random-uuid)] - {id1 {:id id1 :ns-str "re-com.box" :ns 're-com.box :sort 0} - id2 {:id id2 :ns-str "re-com.input-text" :ns 're-com.input-text :sort 1}})}) + (rf/inject-cofx ::local-storage/load {:key "filtered-view-trace" + :or (sortable-uuid-map + [{:ns 're-com.box :ns-str "re-com.box"} + {:ns 're-com.input-text :ns-str "re-com.input-text"}])}) (rf/inject-cofx ::local-storage/load {:key "retained-epochs" :or 25}) (rf/inject-cofx ::local-storage/load {:key "app-db-paths" :or {}}) (rf/inject-cofx ::local-storage/load {:key "app-db-follows-events?" :or true}) @@ -47,9 +53,8 @@ :shiftKey true}}}) (rf/inject-cofx ::local-storage/load {:key "log-outputs" :or [:day8.re-frame-10x.fx.log/console]}) (rf/inject-cofx ::local-storage/load {:key "log-pretty?" :or true}) - (rf/inject-cofx ::local-storage/load {:key "ns-aliases" :or - (let [id (random-uuid)] - {id {:id id :ns-full "long-namespace" :ns-alias "ln"}})}) + (rf/inject-cofx ::local-storage/load {:key "ns-aliases" + :or (sortable-uuid-map [{:ns-full "long-namespace" :ns-alias "ln"}])}) rf/unwrap] (fn [{:keys [panel-width-ratio show-panel selected-tab filter-items app-db-json-ml-expansions external-window? external-window-dimensions show-epoch-traces? using-trace? From eccc7b7b23c6516baea71b6aba9eb17f116c8e7d Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Wed, 26 Jul 2023 15:35:51 +0200 Subject: [PATCH 3/4] Provide local-storage & fallback values separately Now, it's possible to express the precedence of fallback values explicitly. In our case, we need this order of precedence: 1) stored value 2) closure-define value (for project-level configuration) 3) static fallback value The interceptor's original behavior is unchanged, other than adding two namespaced keys to cofx. --- src/day8/re_frame_10x/fx/local_storage.cljs | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/day8/re_frame_10x/fx/local_storage.cljs b/src/day8/re_frame_10x/fx/local_storage.cljs index ba766406..d3c43944 100644 --- a/src/day8/re_frame_10x/fx/local_storage.cljs +++ b/src/day8/re_frame_10x/fx/local_storage.cljs @@ -29,13 +29,10 @@ (defn load "Loads a re-frame-10x value from local storage." - ([key] - (load key nil)) - ([key not-found] - (let [value (.get storage (safe-key key))] - (if (undefined? value) - not-found - (reader/read-string value))))) + [key] + (let [value (.get storage (safe-key key))] + (when-not (undefined? value) + (reader/read-string value)))) (defn- all-keys [] (try @@ -66,7 +63,10 @@ (rf/reg-cofx ::load - (fn [coeffects {:keys [key or]}] - (assoc coeffects - (keyword key) - (load key or)))) + (fn [coeffects {storage-key :key fallback :or}] + (let [k (keyword storage-key) + v (load storage-key)] + (cond-> coeffects + :do (assoc k (or v fallback)) + v (assoc-in [::stored k] v) + fallback (assoc-in [::fallback k] fallback))))) From 8d2a68ac22be5201ad0ce0a2ffb79ac0cc35f33a Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Thu, 27 Jul 2023 16:58:12 +0200 Subject: [PATCH 4/4] Support project-level configuration for some settings https://github.com/day8/re-frame-10x/issues/379 https://github.com/day8/re-frame-10x/issues/202 --- README.md | 30 +++++++++ src/day8/re_frame_10x.cljs | 25 +++++++- src/day8/re_frame_10x/events.cljs | 87 +++++++++++++-------------- src/day8/re_frame_10x/tools/coll.cljs | 13 +++- 4 files changed, 108 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index c102ff6f..2bfc1913 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,36 @@ Reagent Versions | React Versions | re-frame-10x Artifact | Status | re-frame-10x includes an experimental code tracing feature for tracing the code in your event handlers. See [day8/re-frame-debux](https://github.com/day8/re-frame-debux) for instructions on how to set it up. +### Project configuration + +For some settings, re-frame-10x supports project-level configuration via additional [closure-defines](https://clojurescript.org/reference/compiler-options#closure-defines). This way, some default behavior of 10x can be version-controlled alongside your project. Example: + +```cljs +{:closure-defines + {re-frame.trace.trace-enabled? true + day8.re-frame.tracing.trace-enabled? true + day8.re-frame-10x.hidden-namespaces "[com.me.uninteresting re-com.box]"}} +``` + +- Settings which are already stored take precedence. Be sure to [clear your localStorage](#factory-reset) for your project-level config to take effect. + +- Keys always begin with `day8.re-frame-10x.` + +- Any value which is a collection must appear stringified, due to [limitations in the closure compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#define-type-description) + +Supported keys: + +name | description | type | example +------------------|--------------|----------------|------- +...`history-size` | how many epochs to retain | integer | `25` +...`ignored-events` | ignore events of this type | seq of keywords | `"[:init :event-B]"` +...`hidden-namespaces` | hide trace from these namespaces | seq of symbols | `"[re-com.box re-com.input-text]"` +...`time-travel?` | selecting an event reverts your app-db | boolean | `true` +...`ignored-libs` | ignore low-level trace | seq of keywords | `"[:reagent :re-frame]"` +...`ns-aliases` | display aliased keywords in data inspectors | map of symbol->symbol | `"{long-namespace ln}"` + + + ## Usage - **Make sure you have followed all of the installation instructions above.** diff --git a/src/day8/re_frame_10x.cljs b/src/day8/re_frame_10x.cljs index 0af31390..c36b4fc3 100644 --- a/src/day8/re_frame_10x.cljs +++ b/src/day8/re_frame_10x.cljs @@ -8,7 +8,9 @@ [day8.re-frame-10x.inlined-deps.spade.git-sha-93ef290.react :as spade.react] [day8.reagent.impl.batching :refer [patch-next-tick]] [day8.reagent.impl.component :refer [patch-wrap-funs patch-custom-wrapper]] + [day8.re-frame-10x.tools.coll :refer [sortable-uuid-map pred-map]] [day8.re-frame-10x.tools.datafy :as tools.datafy] + [day8.re-frame-10x.tools.reader.edn :as reader.edn] [day8.re-frame-10x.tools.shadow-dom :as tools.shadow-dom] [day8.re-frame-10x.events :as events] [day8.re-frame-10x.components.re-com :as rc] @@ -146,8 +148,29 @@ (patch-wrap-funs) (patch-next-tick)) +(goog-define history-size 25) +(goog-define ignored-events "{}") +(goog-define hidden-namespaces "[re-com.box re-com.input-text]") +(goog-define time-travel? true) +(goog-define ignored-libs "[:reagent :re-frame]") +(goog-define ns-aliases "{long-namespace ln}") + +(def project-config + (let [read reader.edn/read-string-maybe + keep-vals (remove (comp nil? second)) + view #(do {:ns % :ns-str (str %)}) + alias (fn [[k v]] {:ns-full (str k) :ns-alias (str v)})] + (->> {:debug? debug? + :retained-epochs history-size + :ignored-events (some-> ignored-events read sortable-uuid-map) + :filtered-view-trace (some->> hidden-namespaces read (map view) sortable-uuid-map) + :app-db-follows-events? time-travel? + :low-level-trace (some-> ignored-libs read (pred-map #{:re-frame :reagent})) + :ns-aliases (some->> ns-aliases read (map alias) sortable-uuid-map)} + (into {} keep-vals)))) + (defn init! [] (patch!) - (rf/dispatch-sync [::events/init {:debug? debug?}]) + (rf/dispatch-sync [::events/init project-config]) (inject!)) \ No newline at end of file diff --git a/src/day8/re_frame_10x/events.cljs b/src/day8/re_frame_10x/events.cljs index 46b57790..3d65cda7 100644 --- a/src/day8/re_frame_10x/events.cljs +++ b/src/day8/re_frame_10x/events.cljs @@ -11,12 +11,8 @@ [day8.re-frame-10x.navigation.views :as navigation.views] [day8.re-frame-10x.panels.app-db.events :as app-db.events] [day8.re-frame-10x.panels.settings.events :as settings.events] - [day8.re-frame-10x.panels.traces.events :as traces.events])) - -(defn sortable-uuid-map [vals] - (let [entry (fn [id v i] - [id (into {:id id :sort i} v)])] - (into {} (map entry (repeatedly random-uuid) vals (range))))) + [day8.re-frame-10x.panels.traces.events :as traces.events] + [day8.re-frame-10x.tools.coll :refer [sortable-uuid-map]])) (rf/reg-event-fx ::init @@ -56,45 +52,46 @@ (rf/inject-cofx ::local-storage/load {:key "ns-aliases" :or (sortable-uuid-map [{:ns-full "long-namespace" :ns-alias "ln"}])}) rf/unwrap] - (fn [{:keys [panel-width-ratio show-panel selected-tab filter-items app-db-json-ml-expansions - external-window? external-window-dimensions show-epoch-traces? using-trace? - ignored-events low-level-trace filtered-view-trace retained-epochs app-db-paths - app-db-follows-events? ambiance syntax-color-scheme categories data-path-annotations? - show-event-history open-new-inspectors? handle-keys? key-bindings log-outputs log-pretty? - ns-aliases]} - {:keys [debug?]}] - {:fx [(when using-trace? - [:dispatch [::settings.events/enable-tracing]]) - [:dispatch [::settings.events/panel-width% panel-width-ratio]] - [:dispatch [::settings.events/show-panel? show-panel]] - [:dispatch [::settings.events/selected-tab selected-tab]] - [:dispatch [::settings.events/set-ignored-events ignored-events]] - [:dispatch [::settings.events/set-filtered-view-trace filtered-view-trace]] - [:dispatch [::settings.events/set-low-level-trace low-level-trace]] - [:dispatch [::settings.events/set-number-of-retained-epochs retained-epochs]] - [:dispatch [::settings.events/app-db-follows-events? app-db-follows-events?]] - [:dispatch [::settings.events/set-ambiance ambiance]] - [:dispatch [::settings.events/set-syntax-color-scheme syntax-color-scheme]] - [:dispatch [::settings.events/debug? debug?]] - ;; Important that window dimensions are set before we open an external window. - [:dispatch [::settings.events/external-window-dimensions external-window-dimensions]] - [:dispatch [::app-db.events/set-data-path-annotations? data-path-annotations?]] - (when external-window? - [:dispatch [::navigation.events/launch-external navigation.views/mount]]) - [:dispatch [::traces.events/set-queries filter-items]] - [:dispatch [::traces.events/set-categories categories]] - [:dispatch [::traces.events/set-filter-by-selected-epoch? show-epoch-traces?]] - [:dispatch [::app-db.events/paths (into (sorted-map) app-db-paths)]] - [:dispatch [::app-db.events/set-json-ml-paths app-db-json-ml-expansions]] - [:dispatch [:global/add-unload-hook]] - [:dispatch [::app-db.events/reagent-id]] - [:dispatch [::settings.events/show-event-history? show-event-history]] - [:dispatch [::settings.events/open-new-inspectors? open-new-inspectors?]] - [:dispatch [::settings.events/handle-keys? handle-keys?]] - [:dispatch [::settings.events/key-bindings key-bindings]] - [:dispatch [::settings.events/log-outputs log-outputs]] - [:dispatch [::settings.events/log-pretty? log-pretty?]] - [:dispatch [::settings.events/ns-aliases ns-aliases]]]})) + (fn [{::local-storage/keys [stored fallback]} project-config] + (let [{:keys [panel-width-ratio show-panel selected-tab filter-items app-db-json-ml-expansions + external-window? external-window-dimensions show-epoch-traces? using-trace? + ignored-events low-level-trace filtered-view-trace retained-epochs app-db-paths + app-db-follows-events? ambiance syntax-color-scheme categories data-path-annotations? + show-event-history open-new-inspectors? handle-keys? key-bindings log-outputs log-pretty? + ns-aliases debug?]} + (merge fallback project-config stored)] + {:fx [(when using-trace? + [:dispatch [::settings.events/enable-tracing]]) + [:dispatch [::settings.events/panel-width% panel-width-ratio]] + [:dispatch [::settings.events/show-panel? show-panel]] + [:dispatch [::settings.events/selected-tab selected-tab]] + [:dispatch [::settings.events/set-ignored-events ignored-events]] + [:dispatch [::settings.events/set-filtered-view-trace filtered-view-trace]] + [:dispatch [::settings.events/set-low-level-trace low-level-trace]] + [:dispatch [::settings.events/set-number-of-retained-epochs retained-epochs]] + [:dispatch [::settings.events/app-db-follows-events? app-db-follows-events?]] + [:dispatch [::settings.events/set-ambiance ambiance]] + [:dispatch [::settings.events/set-syntax-color-scheme syntax-color-scheme]] + [:dispatch [::settings.events/debug? debug?]] + ;; Important that window dimensions are set before we open an external window. + [:dispatch [::settings.events/external-window-dimensions external-window-dimensions]] + [:dispatch [::app-db.events/set-data-path-annotations? data-path-annotations?]] + (when external-window? + [:dispatch [::navigation.events/launch-external navigation.views/mount]]) + [:dispatch [::traces.events/set-queries filter-items]] + [:dispatch [::traces.events/set-categories categories]] + [:dispatch [::traces.events/set-filter-by-selected-epoch? show-epoch-traces?]] + [:dispatch [::app-db.events/paths (into (sorted-map) app-db-paths)]] + [:dispatch [::app-db.events/set-json-ml-paths app-db-json-ml-expansions]] + [:dispatch [:global/add-unload-hook]] + [:dispatch [::app-db.events/reagent-id]] + [:dispatch [::settings.events/show-event-history? show-event-history]] + [:dispatch [::settings.events/open-new-inspectors? open-new-inspectors?]] + [:dispatch [::settings.events/handle-keys? handle-keys?]] + [:dispatch [::settings.events/key-bindings key-bindings]] + [:dispatch [::settings.events/log-outputs log-outputs]] + [:dispatch [::settings.events/log-pretty? log-pretty?]] + [:dispatch [::settings.events/ns-aliases ns-aliases]]]}))) ;; Global diff --git a/src/day8/re_frame_10x/tools/coll.cljs b/src/day8/re_frame_10x/tools/coll.cljs index 8948a0f6..48f26fa7 100644 --- a/src/day8/re_frame_10x/tools/coll.cljs +++ b/src/day8/re_frame_10x/tools/coll.cljs @@ -54,4 +54,15 @@ :else (get ret k))) m - ks)) \ No newline at end of file + ks)) + +(defn sortable-uuid-map [ms] + (let [entry (fn [id v i] + [id (into {:id id :sort i} v)])] + (into {} (map entry (repeatedly random-uuid) ms (range))))) + +(defn pred-map [ks possible-ks] + (let [ks (set ks)] + (into {} + (map #(do [% (contains? ks %)])) + possible-ks)))