diff --git a/.gitignore b/.gitignore index b48bdec..9475c75 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,5 @@ pom.xml.asc resources/public/js/compiled figwheel-main.log* node_modules/ - +.rebel_readline_history /.idea/ diff --git a/src/pluto/playground/components/dialogs.cljs b/src/pluto/playground/components/dialogs.cljs index eadd896..1330215 100644 --- a/src/pluto/playground/components/dialogs.cljs +++ b/src/pluto/playground/components/dialogs.cljs @@ -55,11 +55,12 @@ (defview examples [] (letsubs [show? [:get :examples]] - [:> Dialog {:open show? :on-close #(re-frame/dispatch [:set :examples nil])} + [:> Dialog {:open (or show? false) :on-close #(re-frame/dispatch [:set :examples nil])} [:> DialogTitle "Extensions examples"] [:div {:style {:padding 20 :overflow :auto}} (for [item examples-data] + ^ {:key item} [example-item item])]])) (defn app-db-browser [] @@ -70,10 +71,27 @@ "Edit local app-db"] [:div {:style {:padding 20 :width "50vw" :height "80vh"}} [source/editor2 {:content (str (or m {})) - :on-change #(re-frame/dispatch [:fiddle/set-app-db nil (edn/read-string %)])}]]])) + :on-change #(re-frame/dispatch [:extension/set-app-db nil (edn/read-string %)])}]]])) -(defn dialogs [] +(defn- set-properties [id s] + (try + (re-frame/dispatch [:extension/set-properties id (edn/read-string s)]) + (catch js/Error _))) + +(defn properties-browser [selection] + (let [browse @(re-frame/subscribe [:get :browse-properties]) + m @(re-frame/subscribe [:extension/properties selection])] + [:> Dialog {:open browse :on-close #(re-frame/dispatch [:set :browse-properties false])} + [:> DialogTitle + "Edit properties"] + [:div {:style {:padding 20 :width "50vw" :height "80vh"}} + [source/editor2 {:content (str (or m {})) + :on-change #(set-properties selection %)}]]])) + + +(defn dialogs [selection] [:div [publish] [examples] - [app-db-browser]]) + [app-db-browser] + [properties-browser selection]]) diff --git a/src/pluto/playground/components/inspector.cljs b/src/pluto/playground/components/inspector.cljs index 7fed88e..b1407df 100644 --- a/src/pluto/playground/components/inspector.cljs +++ b/src/pluto/playground/components/inspector.cljs @@ -13,11 +13,10 @@ (.log js/console "trigger" query arguments)) (defn tree [ctx m] - (println m) [:div (for [[k v] (filter primitive? m)] ;; TODO only events and views? ^{:key k} [:div [:div (str k)] [:button {:on-click #(fire-event ctx m k {})} - "Fire"]])]) \ No newline at end of file + "Fire"]])]) diff --git a/src/pluto/playground/components/logs.cljs b/src/pluto/playground/components/logs.cljs index 3f51129..cf7d4b5 100644 --- a/src/pluto/playground/components/logs.cljs +++ b/src/pluto/playground/components/logs.cljs @@ -28,6 +28,7 @@ (defmethod pretty-print-data [::log/trace :event/dispatch] [{:keys [data]}] [:<> (for [event data] + ^{:key event} [reference event])]) ;; TODO unify static and runtime (log) errors @@ -42,6 +43,11 @@ [:div {:style {:max-height "100px" :overflow "auto"}} child]) +(defn- pretty-print-category [category] + (reagent/as-element + [:div {:style {:color (if (= category ::log/error) :red :blue)}} + category])) + (defn table [v] [:div [:> Table @@ -53,10 +59,10 @@ [:> TableCell "Data"]]] [:> TableBody (for [{:keys [id category type] :as m} v] - ^{:key id} + ^{:key (or id m)} [:> TableRow [:> TableCell id] - [:> TableCell category] + [:> TableCell (pretty-print-category category)] [:> TableCell type] [:> TableCell [data-wrapper diff --git a/src/pluto/playground/core.cljs b/src/pluto/playground/core.cljs index 539de39..723cfd4 100644 --- a/src/pluto/playground/core.cljs +++ b/src/pluto/playground/core.cljs @@ -1,6 +1,7 @@ (ns pluto.playground.core (:require-macros [react-native-web.views :refer [defview letsubs]]) - (:require [pluto.playground.components.source :as source] + (:require [clojure.string :as string] + [pluto.playground.components.source :as source] [pluto.playground.components.logs :as logs] pluto.playground.fx pluto.playground.subs @@ -8,6 +9,7 @@ pluto.reader.views [pluto.log :as log] [react-native-web.extensions :as rnw.extensions] + [react-native-web.hooks :as hooks] [reagent.core :as reagent] [re-frame.core :as re-frame] [re-frame.registrar :as registrar] @@ -15,6 +17,30 @@ [react-native-web.react :as react] [pluto.playground.components.dialogs :as dialogs])) + +;; Components + +(def Button (aget js/MaterialUI "Button")) + +(defn button [props label] + [:> Button props + label]) + +(def Switch (aget js/MaterialUI "Switch")) + +(defn switch [props] + [:> Switch props]) + +(def Select (aget js/MaterialUI "Select")) +(def MenuItem (aget js/MaterialUI "MenuItem")) + +(defn select [{:keys [on-change selected options]}] + [:> Select {:value (or selected "") :on-change on-change :auto-width true} + (for [{:keys [value label]} options] + ^{:key value} + [:> MenuItem {:value value} + label])]) + (def warn (js/console.warn.bind js/console)) (re-frame.loggers/set-loggers! {:warn (fn [& args] @@ -52,58 +78,75 @@ :event-fn dispatch-events :log-fn #(re-frame/dispatch [:extension/append-log %])}) -(def payload - {:name "Test Extension" - :users [{:nm "Jane"} - {:nm "Sue"}]}) - -;; TODO list all views/events/queries used (per category) -;; TODO source viewer - -(def Button (aget js/MaterialUI "Button")) - -(defn button [props label] - [:> Button props - label]) - -(def Switch (aget js/MaterialUI "Switch")) - -(defn switch [props] - [:> Switch props]) - (defn flatten-errors [m] (when (map? m) (apply concat (reduce-kv #(concat %1 (vals %3)) [] m)))) +(defn parse-extension-id [extension-selection] + (map keyword (string/split extension-selection #"/"))) + +(defn view [props data id] + ((get-in data [:views id]) props)) + +(defn selected-ui [props selection data] + (let [[type id] (parse-extension-id selection)] + (case type + :hooks (hooks/hook-in [id (get-in data [:hooks id])]) + :views [:div {:style {:display :flex :width "100%" :height "100%"}} + [:div (:content props)] + [view props data id]] + nil))) + (defview layout [] - (letsubs [logs [:extension/filtered-logs] - errors [:extension/errors]] - [:div {:style {:display :flex :flex 1}} - [dialogs/dialogs] - [:div {:style {:display :inline-block :width "calc(100% - 400px)"}} - [:div - [:div {:style {:display :flex :justify-content :flex-end :align-items :center :margin "10px"}} - [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :browse-app-db true])} - "Local app DB"]] - [source/editor {:on-change #(re-frame.core/dispatch [:extension/update-source ctx %])}]] - [:div - [:div {:style {:display :flex :justify-content :flex-end :align-items :center :margin "10px"}} - [switch {:color "primary" :on-change #(re-frame/dispatch [:extension/switch-filter-logs %2])}] - [:span {:style {:margin "10px"}} "Filter traces"] - [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:extension/clear-logs])} - "Clear logs"]]] - [:div {:style {:height "calc(40% - 50px)" :overflow :auto}} - [logs/table (or (flatten-errors errors) logs)]]] - [:div - [:div {:style {:display :flex :justify-content :flex-end :padding-right 20 :margin "10px"}} - [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :examples true])} - "Examples"] - [:div {:style {:width 10}}] - [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:extension/publish])} - "Publish"]] - [:div {:style {:border "40px solid #ddd" :border-width "20px 7px" :border-radius "40px" :margin 20}} - [react/view {:style {:width 375 :height 667}} - [:div {:id "extension" :style {:display :flex :flex 1}}]]]]])) + (letsubs [logs [:extension/filtered-logs] + errors [:extension/errors] + {:keys [views hooks] :as data} [:extension/parsed] + extension-selection [:get :extension-selection]] + (let [keys (concat (map #(str "hooks/" (name %)) (keys hooks)) + (map #(str "views/" (name %)) (keys views))) + selection (or extension-selection (first keys)) + props @(re-frame/subscribe [:extension/properties selection])] + [:div {:style {:display :flex :flex 1}} + [dialogs/dialogs selection] + [:div {:style {:display :inline-block :width "calc(100% - 400px)"}} + [:div + [:div {:style {:display :flex :justify-content :flex-end :align-items :center :margin "10px"}} + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :browse-app-db true])} + "Local app DB"]] + [source/editor {:on-change #(re-frame.core/dispatch [:extension/update-source ctx %])}]] + [:div + [:div {:style {:display :flex :justify-content :flex-end :align-items :center :margin "10px"}} + [switch {:color "primary" :on-change #(re-frame/dispatch [:extension/switch-filter-logs %2])}] + [:span {:style {:margin "10px"}} "Filter traces"] + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:extension/clear-logs])} + "Clear logs"]]] + [:div {:style {:height "calc(40% - 50px)" :overflow :auto}} + [logs/table (or (flatten-errors errors) logs)]]] + [:div + [:div {:style {:display :flex :justify-content :flex-end :padding-right 20 :margin "10px"}} + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :examples true])} + "Examples"] + [:div {:style {:width 10}}] + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:extension/publish])} + "Publish"]] + [:div {:style {:border "40px solid #ddd" :border-width "20px 7px" :border-radius "40px" :margin 20}} + [react/view {:style {:width 375 :height 667}} + [:div {:id "extension" :style {:display :flex :flex 1}} + [selected-ui props selection data]]]] + [:div {:style {:display :flex :justify-content :center :flex-direction :column :padding 10}} + [:div {:style {:display :flex :justify-content :flex-end}} + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :browse-app-db true])} + "Local app DB"]] + [:div {:style {:display :flex :justify-content :flex-end :align-items :center :margin "10px"}} + [:span {:style {:margin 10}} + "Selection"] + [select + {:on-change #(re-frame/dispatch [:set :extension-selection (.-key %2)]) + :selected selection + :options (map #(do {:value % :label %}) keys)}] + [:div {:style {:margin 10}} + [button {:color "primary" :variant "contained" :on-click #(re-frame/dispatch [:set :browse-properties true])} + "Data"]]]]]]))) (defn mount-root [] (reagent/render [layout] (.getElementById js/document "app"))) diff --git a/src/pluto/playground/fx.cljs b/src/pluto/playground/fx.cljs index 81e5848..b84569a 100644 --- a/src/pluto/playground/fx.cljs +++ b/src/pluto/playground/fx.cljs @@ -43,14 +43,10 @@ (re-frame/reg-fx :extension/parse (fn [[ctx data]] - (let [{:keys [data errors] :as m} (pluto/parse ctx data)] + (let [{:keys [data errors]} (pluto/parse ctx data)] (if errors (re-frame/dispatch [:extension/update-errors errors]) - (do - (reagent/render-component - (hooks/hook-in (first (:hooks data))) - (.getElementById js/document "extension")) - (re-frame/dispatch [:extension/update-parsed data])))))) + (re-frame/dispatch [:extension/update-parsed data]))))) (defn- update-extension-data [{:keys [db]} [_ ctx data]] @@ -151,7 +147,8 @@ (re-frame.core/reg-event-fx :fetch-extension (fn [{:keys [db]} _] - {:fetch-extension-fx nil})) + {:fetch-extension-fx nil + :dispatch [:store/clear-all]})) (re-frame.core/reg-fx :set-url-fx @@ -163,4 +160,9 @@ (fn [{db :db} [_ hash]] {:db (dissoc db :examples) :set-url-fx hash - :dispatch [:fetch-extension]})) \ No newline at end of file + :dispatch [:fetch-extension]})) + +(re-frame.core/reg-event-fx + :extension/set-properties + (fn [{:keys [db]} [_ id m]] + {:db (assoc-in db [:extensions/properties id] m)})) diff --git a/src/pluto/playground/subs.cljs b/src/pluto/playground/subs.cljs index 8777568..ebcf132 100644 --- a/src/pluto/playground/subs.cljs +++ b/src/pluto/playground/subs.cljs @@ -69,3 +69,8 @@ (re-frame/reg-sub :extension/preview preview) + +(re-frame/reg-sub + :extension/properties + (fn [db [_ id _]] + (get-in db [:extensions/properties id]))) diff --git a/src/react_native_web/events.cljs b/src/react_native_web/events.cljs index fb718c8..f47c9f6 100644 --- a/src/react_native_web/events.cljs +++ b/src/react_native_web/events.cljs @@ -57,7 +57,7 @@ :else (nil? o))) (re-frame/reg-event-fx - :fiddle/set-app-db + :extension/set-app-db (fn [{:keys [db]} [_ {id :hook-id} m]] {:db (assoc-in db [:extensions/store id] m)})) diff --git a/src/react_native_web/hooks.cljs b/src/react_native_web/hooks.cljs index 1051905..798f5fc 100644 --- a/src/react_native_web/hooks.cljs +++ b/src/react_native_web/hooks.cljs @@ -6,9 +6,9 @@ [pluto.core :as pluto] [clojure.string :as string])) -(defn settings-hook [id {:keys [view]}] +(defn settings-hook [id {:keys [view]} props] [react/view {:style {:flex 1}} - [view]]) + [view props]]) (defn message-container [preview outgoing] [react/view @@ -74,7 +74,7 @@ (defn rand-str [len] (apply str (take len (repeatedly #(char (+ (rand 26) 65)))))) -(defview chat-view [preview parameters command-id] +(defview chat-view [preview parameters command-id props] (letsubs [{:keys [messages params suggestion-id]} [:get :extension-props]] [react/view {:style {:flex 1}} [(react/scroll-view) {:style {:flex 1 :background-color :white}} @@ -82,8 +82,9 @@ (for [message messages] ^{:key (str message (rand-str 10))} [react/view - [message-container (when preview (preview (merge {:outgoing false} message))) false] - [message-container (when preview (preview (merge {:outgoing true} message))) true]])]] + (let [m (merge {:outgoing false} message props)] + [message-container (when preview (preview m)) false] + [message-container (when preview (preview m)) true])])]] (when-let [suggestion (some #(when (= suggestion-id (:id %)) (:suggestions %)) parameters)] [react/view {:style {:max-height 300}} [suggestion]]) @@ -105,13 +106,15 @@ #_[icons/icon :main-icons/arrow-up {:container-style send-message-icon :color :white}]]]]])) -(defn command-hook [id {:keys [parameters preview]}] - [chat-view preview parameters id]) +(defn command-hook [id {:keys [parameters preview]} props] + [chat-view preview parameters id props]) -(defn hook-in [[id parsed]] +(defn hook-in [[id parsed] props] (when id (let [hook-id (last (string/split (name id) #"\.")) type (pluto/hook-type id)] (case type - "chat.command" (command-hook hook-id parsed) - "wallet.settings" (settings-hook hook-id parsed))))) + "chat.command" (command-hook hook-id parsed props) + "wallet.settings" (settings-hook hook-id parsed props) + [:div + (str "Unknown hook type " type)])))) diff --git a/src/react_native_web/queries.cljs b/src/react_native_web/queries.cljs index a021682..4648f28 100644 --- a/src/react_native_web/queries.cljs +++ b/src/react_native_web/queries.cljs @@ -13,12 +13,6 @@ {:photo "?" :name "Test Name 2" :address "0x00testaddress02" :public-key "0x00testpulickey02"} {:photo "?" :name "Test Name 3" :address "0x00testaddress03" :public-key "0x00testpulickey03"}])) -:get-collectible-token -(re-frame/reg-sub - :extensions.wallet/tokens - (fn [_ [_ _ _]] - {:name "Test"})) - (defn get-token-for [network all-tokens token] {:decimals 18 :address "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"})