Browse Source

zotero setting page

Weihua Lu 4 years ago
parent
commit
bb62694728

+ 1 - 1
src/main/frontend/components/onboarding.cljs

@@ -237,7 +237,7 @@
         :class "text-sm p-1 ml-3"
         :on-click
         (fn []
-          (route-handler/redirect! {:to :shortcut})))
+          (route-handler/redirect! {:to :shortcut-setting})))
        (shortcut/trigger-table)
        (shortcut/shortcut-table :shortcut.category/basics)
        (shortcut/shortcut-table :shortcut.category/block-editing)

+ 18 - 1
src/main/frontend/components/settings.cljs

@@ -372,7 +372,23 @@
       :on-click
       (fn []
         (state/close-settings!)
-        (route-handler/redirect! {:to :shortcut})))]]])
+        (route-handler/redirect! {:to :shortcut-setting})))]]])
+
+(defn zotero-settings-row [t]
+  [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+   [:label.block.text-sm.font-medium.leading-5.opacity-70
+    {:for "zotero_settings"}
+    "Zotero settings"]
+   [:div.mt-1.sm:mt-0.sm:col-span-2
+    [:div
+     (ui/button
+      "Zotero settings"
+      :class "text-sm p-1"
+      :style {:margin-top "0px"}
+      :on-click
+      (fn []
+        (state/close-settings!)
+        (route-handler/redirect! {:to :zotero-setting})))]]])
 
 (defn auto-push-row [t current-repo enable-git-auto-push?]
   (when (string/starts-with? current-repo "https://")
@@ -474,6 +490,7 @@
         (enable-all-pages-public-row t enable-all-pages-public?)
         (encryption-row t enable-encryption?)
         (keyboard-shortcuts-row t)
+        (zotero-settings-row t)
         (auto-push-row t current-repo enable-git-auto-push?)]
 
        [:hr] ;; Outside of panel wrap so that it is wider

+ 151 - 62
src/main/frontend/extensions/zotero.cljs

@@ -1,18 +1,19 @@
 (ns frontend.extensions.zotero
   (:require [cljs.core.async :refer [<! >! go chan] :as a]
             [clojure.string :as str]
+            [frontend.components.svg :as svg]
             [frontend.extensions.zotero.api :as api]
-            [frontend.extensions.zotero.handler :as zotero-handler]
             [frontend.extensions.zotero.extractor :as extractor]
-            [frontend.components.svg :as svg]
+            [frontend.extensions.zotero.handler :as zotero-handler]
+            [frontend.extensions.zotero.setting :as setting]
             [frontend.state :as state]
+            [frontend.ui :as ui]
             [frontend.util :as util]
             [rum.core :as rum]))
 
 (defonce term-chan (chan))
 (defonce debounce-chan  (api/debounce term-chan 200))
 
-
 (rum/defc zotero-search-item [{:keys [data] :as item} handle-command-zotero]
   (let [type (:item-type data)
         title (:title data)
@@ -35,62 +36,150 @@
 
 (rum/defc zotero-search [handle-command-zotero]
 
-  (let [cache-api-key       (js/localStorage.getItem "zotero-api-key")
-        cache-user-id       (js/localStorage.getItem "zotero-user-id")
-        cache-api-key-empty (str/blank? cache-api-key)
-        cache-user-id-empty (str/blank? cache-user-id)
-        api-key
-        (if cache-api-key-empty
-          (js/prompt "Please enter your Zotero API key (https://www.zotero.org/settings/keys/new)")
-          cache-api-key)
-
-        user-id (if cache-user-id-empty (js/prompt "Please enter your Zotero user id (https://www.zotero.org/settings/keys)") cache-user-id)]
-
-    (when cache-api-key-empty (js/localStorage.setItem "zotero-api-key" api-key))
-
-    (when cache-user-id-empty (js/localStorage.setItem "zotero-user-id" user-id))
-
-    (let [[term set-term!]                   (rum/use-state "")
-          [search-result set-search-result!] (rum/use-state [])
-          [search-error set-search-error!]   (rum/use-state nil)
-          [is-searching set-is-searching!]   (rum/use-state false)]
-
-
-      (go
-        (let [d-term   (<! debounce-chan)]
-          (when-not (str/blank? d-term)
-            (set-is-searching! true)
-
-
-            (let [result (<! (api/query-items "journalArticle" d-term))]
-              (if (false? (:success result))
-                (set-search-error! (:body result))
-                (set-search-result! result)))
-
-            (set-is-searching! false))))
-
-      [:div.zotero-search.p-4
-       {:style {:width 600}}
-
-       [:div.flex.items-center.mb-2
-        [[:input.p-2.border.mr-2.flex-1
-          {:autoFocus   true
-           :placeholder "Search for your Zotero journal article (title, author, text, anything)"
-           :value       term :on-change (fn [e]
-                                          (go
-                                            (js/console.log "sending term-chan!!" (util/evalue e))
-                                            (>! term-chan (util/evalue e)))
-                                          (set-term! (util/evalue e)))}]
-
-         (when is-searching [:span.loader-reverse  svg/refresh])]]
-
-       [:div.h-2.text-sm.text-red-400.mb-2 (if search-error (str "Search error: " search-error) "")]
-
-       [:div
-        (map
-         (fn [item] (rum/with-key (zotero-search-item item handle-command-zotero) (:key item)))
-         search-result)]])))
-
-(rum/defc setting []
-  [:div
-   [:h1.title "Zotero setting"]])
+  (let [[term set-term!]                   (rum/use-state "")
+        [search-result set-search-result!] (rum/use-state [])
+        [search-error set-search-error!]   (rum/use-state nil)
+        [is-searching set-is-searching!]   (rum/use-state false)]
+
+
+    (go
+      (let [d-term   (<! debounce-chan)]
+        (when-not (str/blank? d-term)
+          (set-is-searching! true)
+
+
+          (let [result (<! (api/query-items "journalArticle" d-term))]
+            (if (false? (:success result))
+              (set-search-error! (:body result))
+              (set-search-result! result)))
+
+          (set-is-searching! false))))
+
+    [:div.zotero-search.p-4
+     {:style {:width 600}}
+
+     [:div.flex.items-center.mb-2
+      [[:input.p-2.border.mr-2.flex-1
+        {:autoFocus   true
+         :placeholder "Search for your Zotero journal article (title, author, text, anything)"
+         :value       term :on-change (fn [e]
+                                        (go
+                                          (js/console.log "sending term-chan!!" (util/evalue e))
+                                          (>! term-chan (util/evalue e)))
+                                        (set-term! (util/evalue e)))}]
+
+       (when is-searching [:span.loader-reverse  svg/refresh])]]
+
+     [:div.h-2.text-sm.text-red-400.mb-2 (if search-error (str "Search error: " search-error) "")]
+
+     [:div
+      (map
+       (fn [item] (rum/with-key (zotero-search-item item handle-command-zotero) (:key item)))
+       search-result)]]))
+
+
+(rum/defcs settings
+  <
+  (rum/local (setting/api-key) ::api-key)
+  rum/reactive
+  [state]
+  (let [api-key (::api-key state)]
+    [:div#zotero-settings
+     [:h1.title "Zotero settings"]
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-bg.font-medium.leading-5.opacity-70
+       {:for "zotero_api_key"}
+       "Zotero API key"]
+      [:div.mt-1.sm:mt-0.sm:col-span-2
+       [:div.max-w-lg.rounded-md
+        [:input.form-input.block
+         {:value       @api-key
+          :placeholder "Please enter your Zotero API key"
+          :on-change   (fn [e]
+                         (reset! api-key (util/evalue e))
+                         (setting/set-api-key (util/evalue e)))}]]]]
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-sm.font-medium.leading-5.opacity-70
+       {:for "zotero_type"}
+       "Zotero user or group?"]
+      [:div.mt-1.sm:mt-0.sm:col-span-2
+       [:div.max-w-lg.rounded-md
+        [:select.form-select.is-small
+         {:value     (-> (setting/setting :type) name)
+          :on-change (fn [e]
+                       (let [type (-> (util/evalue e)
+                                      (str/lower-case)
+                                      keyword)]
+                         (setting/set-setting! :type type)))}
+         (for [type (map name [:user :group])]
+           [:option {:key type :value type} (str/capitalize type)])]]]]
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-bg.font-medium.leading-5.opacity-70
+       {:for "zotero_type_id"}
+       "User or Group id"]
+      [:div.mt-1.sm:mt-0.sm:col-span-2
+       [:div.max-w-lg.rounded-md
+        [:input.form-input.block
+         {:value       (setting/setting :type-id)
+          :placeholder "User/Group id"
+          :on-change   (fn [e]
+                         (setting/set-setting! :type-id (util/evalue e)))}]]]]
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-sm.font-medium.leading-5.opacity-70
+       {:for "zotero_include_attachment_links"}
+       "Include attachment links?"]
+      [:div
+       [:div.rounded-md.sm:max-w-xs
+        (ui/toggle (setting/setting :include-attachments?)
+                   (fn [] (setting/set-setting! :include-attachments? (not (setting/setting :include-attachments?))))
+                   true)]]]
+
+     (when (setting/setting :include-attachments?)
+       [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+        [:label.block.text-bg.font-medium.leading-5.opacity-70
+         {:for "zotero_attachments_block_text"}
+         "Attachtment under block of:"]
+        [:div.mt-1.sm:mt-0.sm:col-span-2
+         [:div.max-w-lg.rounded-md
+          [:input.form-input.block
+           {:value     (setting/setting :attachments-block-text)
+            :on-change (fn [e]
+                           (setting/set-setting! :attachments-block-text (util/evalue e)))}]]]])
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-sm.font-medium.leading-5.opacity-70
+       {:for "zotero_include_notes"}
+       "Include notes?"]
+      [:div
+       [:div.rounded-md.sm:max-w-xs
+        (ui/toggle (setting/setting :include-notes?)
+                   (fn [] (setting/set-setting! :include-notes?
+                                                (not (setting/setting :include-notes?))))
+                   true)]]]
+
+     (when (setting/setting :include-notes?)
+       [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+        [:label.block.text-bg.font-medium.leading-5.opacity-70
+         {:for "zotero_notes_block_text"}
+         "Notes under block of:"]
+        [:div.mt-1.sm:mt-0.sm:col-span-2
+         [:div.max-w-lg.rounded-md
+          [:input.form-input.block
+           {:value     (setting/setting :notes-block-text)
+            :on-change (fn [e]
+                           (setting/set-setting! :notes-block-text (util/evalue e)))}]]]])
+
+     [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
+      [:label.block.text-bg.font-medium.leading-5.opacity-70
+       {:for "zotero_page_prefix"}
+       "Insert page name with prefix:"]
+      [:div.mt-1.sm:mt-0.sm:col-span-2
+       [:div.max-w-lg.rounded-md
+        [:input.form-input.block
+         {:value     (setting/setting :page-insert-prefix)
+          :on-change (fn [e]
+                         (setting/set-setting! :page-insert-prefix (util/evalue e)))}]]]]]))

+ 22 - 20
src/main/frontend/extensions/zotero/api.cljs

@@ -1,19 +1,20 @@
 (ns frontend.extensions.zotero.api
-  (:require [cljs-http.client :as http]
-            [cljs.core.async
-             :refer [go <! >! go-loop timeout close! chan alt!]]
-            [camel-snake-kebab.core :as csk]
+  (:require [camel-snake-kebab.core :as csk]
             [camel-snake-kebab.extras :as cske]
-            [frontend.util :as util]))
+            [cljs-http.client :as http]
+            [cljs.core.async
+             :refer [<! >! alt! chan close! go go-loop timeout]]
+            [frontend.extensions.zotero.setting :as setting]))
 
 (def ^:dynamic *debug* true)
 
-(def config {:api-version 3
-             :base        "https://api.zotero.org"
-             :timeout     150000
-             :api-key     "NlJI2bAuhYcQ4UgXSwHHsWRD"
-             :type        :user
-             :type-id     8237615})
+(defn config []
+  {:api-version 3
+   :base        "https://api.zotero.org"
+   :timeout     150000
+   :api-key     (setting/api-key)
+   :type        (setting/setting :type)
+   :type-id     (setting/setting :type-id)})
 
 ;; taken from https://github.com/metosin/metosin-common/blob/master/src/cljc/metosin/core/async/debounce.cljc
 (defn debounce
@@ -61,24 +62,25 @@
            response)))))
 
 (defn item [key]
-  (get* config (str "/items/" key)))
+  (get* (config) (str "/items/" key)))
 
 (defn query-items [type term]
-  (get* config (str "/items")
-        {:qmode "everything"
-         :q term
+  (js/console.log "query!!" term)
+  (get* (config) (str "/items")
+        {:qmode     "everything"
+         :q         term
          :item-type type}))
 
 (defn notes [key]
-  (get* config (str "/items/" key "/children") {:item-type "note"}))
+  (get* (config) (str "/items/" key "/children") {:item-type "note"}))
 
 (defn attachments [key]
-  (get* config (str "/items/" key "/children") {:item-type "attachment"}))
+  (get* (config) (str "/items/" key "/children") {:item-type "attachment"}))
 
 (comment
-  (get* config "/collections")
-  (get* config "/items")
-  (get* config "/items" {:item-type "journalArticle"})
+  (get* (config) "/collections")
+  (get* (config) "/items")
+  (get* (config) "/items" {:item-type "journalArticle"})
   (item "JZCIN4K5")
   (item "RFYNAQTN")
   (item "3V6N8ECQ")

+ 4 - 2
src/main/frontend/extensions/zotero/extractor.cljs

@@ -5,6 +5,7 @@
             [frontend.extensions.html-parser :as html-parser]
             [frontend.date :as date]
             [clojure.set :refer [rename-keys]]
+            [frontend.extensions.zotero.setting :as setting]
             [frontend.extensions.zotero.api :as api]))
 
 (defn item-type [item] (-> item :data :item-type))
@@ -21,14 +22,15 @@
                       (filterv (fn [s] (str/includes? s "Citation Key: ")))
                       first)]
     (when citation
-      (str "@" (str/trim (str/replace citation "Citation Key: " ""))))))
+      (str/trim (str/replace citation "Citation Key: " "")))))
 
 (defn title [item] (-> item :data :title))
 
 (defn page-name [item]
   (let [citation-key (citation-key item)
         title        (title item)]
-    (or citation-key title)))
+    (str (setting/setting :page-insert-prefix)
+         (or citation-key title))))
 
 (defn authors [item]
   (let [creators (-> item :data :creators)

+ 28 - 27
src/main/frontend/extensions/zotero/handler.cljs

@@ -1,37 +1,38 @@
 (ns frontend.extensions.zotero.handler
-  (:require [frontend.handler.page :as page-handler]
+  (:require [cljs.core.async :refer [<! go]]
+            [clojure.string :as str]
             [frontend.extensions.zotero.api :as zotero-api]
-            [cljs.core.async :refer [go <!]]
-            [frontend.util.property :as property-util]
-            [frontend.handler.editor :as editor-handler]
-            [frontend.state :as state]
-            [frontend.db :as db]
             [frontend.extensions.zotero.extractor :as extractor]
-            [clojure.string :as str]))
+            [frontend.extensions.zotero.setting :as setting]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.handler.page :as page-handler]))
 
 (defn add [page-name type key]
   (go
-    (let [api-fn   (case type
-                     :notes zotero-api/notes
-                     :attachments zotero-api/attachments)
+    (let [api-fn      (case type
+                        :notes       zotero-api/notes
+                        :attachments zotero-api/attachments)
           first-block (case type
-                        :notes "[[notes]]"
-                        :attachments "[[attachments]]")
-          items (<! (api-fn key))
-          md-notes (->> items
-                        (map extractor/extract)
-                        (remove str/blank?))]
-      (when-let [id
-                 (:block/uuid
-                  (editor-handler/api-insert-new-block!
-                   first-block
-                   {:page page-name}))]
-        (doseq [note md-notes]
-          (editor-handler/api-insert-new-block!
-           note
-           {:block-uuid id
-            :sibling?   false
-            :before?    false}))))))
+                        :notes       (setting/setting :notes-block-text)
+                        :attachments (setting/setting :attachments-block-text))
+          should-add? (case type
+                        :notes       (setting/setting :include-notes?)
+                        :attachments (setting/setting :include-attachments?))]
+      (when should-add?
+        (let [items    (<! (api-fn key))
+              md-notes (->> items
+                            (map extractor/extract)
+                            (remove str/blank?))
+              id       (:block/uuid
+                        (editor-handler/api-insert-new-block!
+                         first-block {:page page-name}))]
+          (when (and id (not-empty md-notes))
+            (doseq [note md-notes]
+              (editor-handler/api-insert-new-block!
+               note
+               {:block-uuid id
+                :sibling?   false
+                :before?    false}))))))))
 
 (defn create-zotero-page [item]
   (go

+ 31 - 0
src/main/frontend/extensions/zotero/setting.cljs

@@ -0,0 +1,31 @@
+(ns frontend.extensions.zotero.setting
+  (:require [frontend.handler.config :as config-handler]
+            [frontend.state :as state]
+            [frontend.storage :as storage]))
+
+(def default-settings
+  {:type                   :user
+   :include-attachments?   true
+   :attachments-block-text "[[attachments]]"
+   :include-notes?         true
+   :notes-block-text       "[[notes]]"
+   :page-insert-prefix     "@"})
+
+(defn api-key []
+  (storage/get :zotero/api-key))
+
+(defn set-api-key [key]
+  (storage/set :zotero/api-key key))
+
+(defn sub-zotero-config
+  []
+  (:zotero/settings (get (state/sub-config) (state/get-current-repo))))
+
+(defn set-setting! [k v]
+  (let [new-settings (assoc (sub-zotero-config) k v)]
+    (config-handler/set-config! :zotero/settings new-settings)))
+
+(defn setting [k]
+  (get (sub-zotero-config)
+       k
+       (get default-settings k)))

+ 11 - 6
src/main/frontend/routes.cljs

@@ -9,7 +9,8 @@
             [frontend.components.search :as search]
             [frontend.components.settings :as settings]
             [frontend.components.external :as external]
-            [frontend.components.shortcut :as shortcut]))
+            [frontend.components.shortcut :as shortcut]
+            [frontend.extensions.zotero :as zotero]))
 
 ;; http://localhost:3000/#?anchor=fn.1
 (def routes
@@ -57,6 +58,14 @@
     {:name :settings
      :view settings/settings}]
 
+   ["/settings/shortcut"
+    {:name :shortcut-setting
+     :view shortcut/shortcut}]
+
+   ["/settings/zotero"
+    {:name :zotero-setting
+     :view zotero/settings}]
+
    ["/import"
     {:name :import
      :view external/import-cp}]
@@ -67,8 +76,4 @@
 
    ["/plugins"
     {:name :plugins
-     :view plugins/installed-page}]
-
-   ["/helper/shortcut"
-    {:name :shortcut
-     :view shortcut/shortcut}]])
+     :view plugins/installed-page}]])

+ 5 - 0
yarn.lock

@@ -7598,6 +7598,11 @@ react-grid-layout@^0.16.6:
     react-draggable "3.x"
     react-resizable "1.x"
 
[email protected]:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.1.0.tgz#a196e33fdf1e7aaa1fda3aefbb68bdad9e82a79d"
+  integrity sha1-oZbjP98eeqof2jrvu2i9rZ6Cp50=
+
 react-icons@^2.2.7:
   version "2.2.7"
   resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-2.2.7.tgz#d7860826b258557510dac10680abea5ca23cf650"