diff --git a/web/src/main/frontend/components/hiccup.cljs b/web/src/main/frontend/components/hiccup.cljs index e1d49b487a..9548453d8c 100644 --- a/web/src/main/frontend/components/hiccup.cljs +++ b/web/src/main/frontend/components/hiccup.cljs @@ -28,7 +28,8 @@ [frontend.extensions.sci :as sci] ["/frontend/utils" :as utils] [frontend.format.block :as block] - [clojure.walk :as walk])) + [clojure.walk :as walk] + [cljs-bean.core :as bean])) ;; local state (defonce *heading-children @@ -1014,9 +1015,11 @@ (rum/defcs custom-query < rum/reactive {:will-mount (fn [state] - (let [[config _options content] (:rum/args state) - query-atom (db/custom-query content)] - (assoc state :query-atom query-atom))) + (let [[config query] (:rum/args state)] + (when (and (not (sci/loaded?)) (:view query)) + (sci/load!)) + (let [query-atom (db/custom-query query)] + (assoc state :query-atom query-atom)))) :did-mount (fn [state] (when-let [query (last (:rum/args state))] (state/add-custom-query-component! query (:rum/react-component state))) @@ -1026,22 +1029,43 @@ (state/remove-custom-query-component! query) (db/remove-custom-query! (state/get-current-repo) query)) state)} - [state config options content] - (let [current-heading-uuid (:heading/uuid (:heading config)) - ;; exclude the current one, otherwise it'll loop forever - remove-headings (if current-heading-uuid [current-heading-uuid] nil) - query-result (if-let [a (:query-atom state)] - (rum/react a)) - result (if query-result - (db/custom-query-result-transform query-result remove-headings))] - [:div.custom-query.my-2 - (if (seq result) - (->hiccup result (assoc config - :custom-query? true - :group-by-page? true) - {:style {:margin-top "0.25rem" - :margin-left "0.25rem"}}) - [:div.text-sm.mt-2 "Empty"])])) + [state config {:keys [title query inputs view] :as q}] + (let [loading? (rum/react sci/*loading?)] + (if loading? + (widgets/loading "loading @borkdude/sci") + (let [current-heading-uuid (:heading/uuid (:heading config)) + ;; exclude the current one, otherwise it'll loop forever + remove-headings (if current-heading-uuid [current-heading-uuid] nil) + query-result (if-let [a (:query-atom state)] + (rum/react a)) + result (if query-result + (db/custom-query-result-transform query-result remove-headings)) + view-f (try + (sci/eval-string (pr-str view)) + (catch js/Error e + (println "Query: sci eval failed:") + (js/console.error e)))] + [:div.custom-query.my-2 + (when title + [:p [:code title]]) + (cond + (and (seq result) view-f) + (let [result (sci/call-fn view-f result)] + (util/hiccup-keywordize result)) + + (and (seq result) + (:heading/uuid (first result))) + (->hiccup result (assoc config + :custom-query? true + :group-by-page? true) + {:style {:margin-top "0.25rem" + :margin-left "0.25rem"}}) + + (seq result) ;TODO: table + (str result) + + :else + [:div.text-sm.mt-2 "Empty"])])))) (defn admonition [config type options result] @@ -1119,8 +1143,9 @@ (latex/html-export content true false) (latex/latex (str (dc/squuid)) content true false)) - ["Custom" "query" options result content] - (custom-query config options content) + ["Custom" "query" _options result content] + (let [query (reader/read-string content)] + (custom-query config query)) ["Custom" "note" options result content] (admonition config "note" options result) diff --git a/web/src/main/frontend/components/page.cljs b/web/src/main/frontend/components/page.cljs index b44c1beb77..1db0b16ae8 100644 --- a/web/src/main/frontend/components/page.cljs +++ b/web/src/main/frontend/components/page.cljs @@ -85,10 +85,9 @@ (let [queries (state/sub [:config repo :default-queries :journals])] (when (seq queries) [:div#today-queries - (for [{:keys [title query]} queries] + (for [{:keys [title] :as query} queries] [:div {:key (str "query-" title)} - (hiccup/custom-query {:start-level 2} {:query-title title} - query)])])))) + (hiccup/custom-query {:start-level 2} query)])])))) ;; A page is just a logical heading (rum/defcs page < rum/reactive diff --git a/web/src/main/frontend/db.cljs b/web/src/main/frontend/db.cljs index aef4a28530..1423c7e229 100644 --- a/web/src/main/frontend/db.cljs +++ b/web/src/main/frontend/db.cljs @@ -230,8 +230,8 @@ ;; TODO: rename :custom to :query/custom (defn remove-custom-query! - [repo query-string] - (remove-q! [repo :custom query-string])) + [repo query] + (remove-q! [repo :custom query])) (defn set-new-result! [k new-result] @@ -494,16 +494,22 @@ headings)) (defn custom-query - [query-string] - (when-not (string/blank? query-string) + [query] + (when-let [query (cond + (and (string? query) + (not (string/blank? query))) + (reader/read-string query) + + (map? query) + query + + :else + nil)] (try - (let [query (reader/read-string query-string) - [query inputs] (if (vector? (first query)) - [`~(first query) (rest query)] - [`~query nil]) + (let [{:keys [query inputs]} query inputs (map resolve-input inputs) repo (state/get-current-repo) - k [:custom query-string]] + k [:custom query]] (apply q repo k {} query inputs)) (catch js/Error e (println "Query parsing failed: ") diff --git a/web/src/main/frontend/extensions/sci.cljs b/web/src/main/frontend/extensions/sci.cljs index ec6463ef7f..be31bbdd9d 100644 --- a/web/src/main/frontend/extensions/sci.cljs +++ b/web/src/main/frontend/extensions/sci.cljs @@ -3,28 +3,44 @@ [frontend.loader :as loader] [frontend.components.widgets :as widgets] [frontend.config :as config] - [goog.object :as gobj])) + [goog.object :as gobj] + [cljs-bean.core :as bean])) (defn loaded? [] js/window.sci) (defonce *loading? (atom true)) +(defn ->js + [x] + (when (loaded?) + (js/window.sci.toJS x))) + (defn eval-string [code] - (when loaded? + (when (loaded?) (js/window.sci.evalString code))) +(defn call-fn + [f & args] + (-> (apply f (bean/->js args)) + (->js) + (bean/->clj))) + +(defn load! + [] + (loader/load + (config/asset-uri "/static/js/sci.min.js") + (fn [] + (reset! *loading? false)))) + (rum/defc eval-result < rum/reactive {:did-mount (fn [state] (if (loaded?) (reset! *loading? false) (do (reset! *loading? true) - (loader/load - (config/asset-uri "/static/js/sci.min.js") - (fn [] - (reset! *loading? false))))) + (load!))) state)} [code] (let [loading? (rum/react *loading?)] diff --git a/web/src/main/frontend/util.cljs b/web/src/main/frontend/util.cljs index 86b887981e..ecf59f6e08 100644 --- a/web/src/main/frontend/util.cljs +++ b/web/src/main/frontend/util.cljs @@ -719,3 +719,12 @@ [s] (let [tags (string/split s #",")] (->tags tags))) + +(defn hiccup-keywordize + [hiccup] + (walk/postwalk + (fn [f] + (if (and (vector? f) (string? (first f))) + (update f 0 keyword) + f)) + hiccup))