Browse Source

Merge branch 'master' into enhance/ios-native-navigation

Tienson Qin 1 week ago
parent
commit
357c8f0667

+ 1 - 1
deps/cli/src/logseq/cli/commands/append.cljs

@@ -7,7 +7,7 @@
 (defn append
   [{{:keys [api-server-token args]} :opts}]
   (let [text (string/join " " args)]
-    (-> (p/let [resp (cli-util/api-fetch api-server-token "logseq.app.append_block_in_page" [text nil nil])]
+    (-> (p/let [resp (cli-util/api-fetch api-server-token "logseq.app.append_block_in_page" [text])]
           (if (= 200 (.-status resp))
             (println "Success!")
             (cli-util/api-handle-error-response resp)))

+ 6 - 2
deps/outliner/src/logseq/outliner/op.cljs

@@ -161,8 +161,12 @@
     ;; (cljs.pprint/pprint _txs)
     (if error
       (reset! *result {:error error})
-      (ldb/transact! conn (vec (concat init-tx block-props-tx misc-tx))
-                     (merge {::sqlite-export/imported-data? true} tx-meta)))))
+      (try
+        (ldb/transact! conn (vec (concat init-tx block-props-tx misc-tx))
+                       (merge {::sqlite-export/imported-data? true} tx-meta))
+        (catch :default e
+          (js/console.error "Unexpected Import EDN error:" e)
+          (reset! *result {:error (str "Unexpected Import EDN error: " (pr-str (ex-message e)))}))))))
 
 (defn ^:large-vars/cleanup-todo apply-ops!
   [repo conn ops date-formatter opts]

+ 1 - 1
libs/src/LSPlugin.ts

@@ -657,7 +657,7 @@ export interface IEditorProxy extends Record<string, any> {
    *
    * @param srcPage - the page name or uuid
    */
-  getPageBlocksTree: (srcPage: PageIdentity) => Promise<Array<BlockEntity>>
+  getPageBlocksTree: (srcPage: PageIdentity) => Promise<Array<BlockEntity> | null>
 
   /**
    * get all page/block linked references

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

@@ -406,7 +406,7 @@
   (let [current-repo (state/sub :git/current-repo)
         theme (state/sub :ui/theme)
         accent-color (some-> (state/sub :ui/radix-color) (name))
-        editor-font (some-> (state/sub :ui/editor-font) (name))
+        editor-font (state/sub :ui/editor-font)
         system-theme? (state/sub :ui/system-theme?)
         light? (= "light" (state/sub :ui/theme))
         sidebar-open? (state/sub :ui/sidebar-open?)

+ 35 - 18
src/main/frontend/components/server.cljs

@@ -14,16 +14,16 @@
 
 (rum/defcs panel-of-tokens
   < rum/reactive
-  (rum/local nil ::tokens)
-  {:will-mount
-   (fn [s]
-     (let [*tokens (s ::tokens)]
-       (reset! *tokens (get-in @state/state [:electron/server :tokens])) s))}
+    (rum/local nil ::tokens)
+    {:will-mount
+     (fn [s]
+       (let [*tokens (s ::tokens)]
+         (reset! *tokens (get-in @state/state [:electron/server :tokens])) s))}
   [_state close-panel]
 
   (let [server-state (state/sub :electron/server)
-        *tokens      (::tokens _state)
-        changed?     (not= @*tokens (:tokens server-state))]
+        *tokens (::tokens _state)
+        changed? (not= @*tokens (:tokens server-state))]
     [:div.cp__server-tokens-panel.pt-6
      [:h2.text-3xl.-translate-y-4 "Authorization tokens"]
      ;; items
@@ -32,17 +32,25 @@
          [:div.item.py-2.flex.space-x-2.items-center
           {:key idx}
           [:input.form-input.basis-36
-           {:auto-focus  true
+           {:auto-focus true
             :placeholder "name"
-            :value       name
-            :on-change   #(let [value (.-value (.-target %))]
-                            (update-value! idx :name value))}]
+            :value name
+            :on-change #(let [value (.-value (.-target %))]
+                          (update-value! idx :name value))}]
           [:input.form-input
            {:placeholder "value"
-            :value       value
-            :on-change   #(let [value (.-value (.-target %))]
-                            (update-value! idx :value value))}]
+            :value value
+            :on-change #(let [value (.-value (.-target %))]
+                          (update-value! idx :value value))}]
 
+          [:button.px-2.opacity-50.hover:opacity-90.active:opacity-100
+           {:on-click #(let [new-token (util/unique-id)
+                             ^js input-el (some-> (.-target %) (.closest ".item") (.querySelector "input.form-input:nth-child(2)"))]
+                         (update-value! idx :value new-token)
+                         (when input-el
+                           (js/setTimeout (fn [] (.select input-el)) 64)))
+            :title "Regenerate token value"}
+           [:span.flex.items-center (ui/icon "refresh")]]
           [:button.px-2.opacity-50.hover:opacity-90.active:opacity-100
            {:on-click #(reset! *tokens (into [] (medley/remove-nth idx @*tokens)))}
            [:span.flex.items-center (ui/icon "trash-x")]]]))
@@ -134,10 +142,10 @@
          #(js/clearTimeout t))))
    [])
 
-  (let [{:keys [status error]} server-state
-        status   (keyword (util/safe-lower-case status))
+  (let [{:keys [status error mcp-enabled?]} server-state
+        status (keyword (util/safe-lower-case status))
         running? (= :running status)
-        href     (and running? (str "http://" (:host server-state) ":" (:port server-state)))]
+        href (and running? (str "http://" (:host server-state) ":" (:port server-state)))]
 
     (hooks/use-effect!
      #(when error
@@ -180,7 +188,16 @@
                                                  [:span.ml-1.text-sm.opacity-70
                                                   (if-not running?
                                                     (string/upper-case (or (:status server-state) "stopped"))
-                                                    [:a.hover:underline {:href href} href])]]
+                                                    [:span.flex.flex-col.gap-1.text-xs.font-mono
+                                                     [:a.hover:underline.flex.items-center {:href href}
+                                                      href (shui/tabler-icon "external-link" {:size 12 :class "inline-block ml-1 pt-[1px]"})]
+                                                     (when mcp-enabled?
+                                                       [:a.hover:underline.flex.items-center
+                                                        {:on-click (fn []
+                                                                     (util/copy-to-clipboard! (str href "/mcp"))
+                                                                     (notification/show! "MCP URL copied to clipboard!" :success))}
+                                                        (str href "/mcp")
+                                                        (shui/tabler-icon "copy" {:size 12 :class "inline-block ml-1 mt-[1px]"})])])]]
                                                 (for [{:keys [hr? title options icon]} items]
                                                   (cond
                                                     hr?

+ 22 - 16
src/main/frontend/components/settings.cljs

@@ -241,25 +241,31 @@
      [:div {:style {:text-align "right"}}
       (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-wide-mode))])])
 
-(defn editor-font-family-row [t font]
+(defn editor-font-family-row [t {:keys [type global]}]
   [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4
    [:label.block.text-sm.font-medium.leading-5.opacity-70
     {:for "font_family"}
     (t :settings-page/editor-font)]
-   [:div.col-span-2.flex.gap-2
-    (for [t [:default :serif :mono]
-          :let [t (name t)
-                tt (string/capitalize t)
-                active? (= font t)]]
-      (shui/button
-       {:variant :secondary
-        :class (when active? " border-primary border-[2px]")
-        :style {:width "4.4rem"}
-        :on-click #(state/set-editor-font! t)}
-       [:span.flex.flex-col
-        {:class (str "ls-font-" t)}
-        [:strong "Ag"]
-        [:small tt]]))]])
+   [:div.flex.flex-col.col-span-2
+    [:div.flex.gap-2
+     (for [t [:default :serif :mono]
+           :let [t (name t)
+                 tt (string/capitalize t)
+                 active? (= (or type "default") t)]]
+       (shui/button
+         {:variant :secondary
+          :class (when active? " border-primary border-[2px]")
+          :style {:width "4.4rem"}
+          :on-click #(state/set-editor-font! {:type t})}
+         [:span.flex.flex-col
+          {:class (str "ls-font-" t)}
+          [:strong "Ag"]
+          [:small tt]]))]
+    [:div.pt-3
+     [:label.w-full.flex.items-center.cursor-pointer
+      (shui/checkbox {:checked (boolean global)
+                      :on-checked-change #(state/set-editor-font! {:global %})})
+      [:span.pl-1.text-sm.opacity-70 "Set as global font family"]]]]])
 
 (rum/defcs switch-spell-check-row < rum/reactive
   [state t]
@@ -1356,7 +1362,7 @@
                         (when (and new-val (not (storage/get ::storage-spec/http-server-enabled)))
                           (storage/set ::storage-spec/http-server-enabled true))
                         (-> (ipc/ipc :server/set-config {:mcp-enabled? new-val})
-                            ;; Dont start server if it's not running
+                            ;; Don't start server if it's not running
                             (p/then #(when (= "running" (state/sub [:electron/server :status]))
                                        (p/let [_ (p/delay 1000)]
                                          (ipc/ipc :server/do :restart))))

+ 6 - 3
src/main/frontend/components/theme.cljs

@@ -63,9 +63,12 @@
      [accent-color])
 
     (hooks/use-effect!
-     #(some-> js/document.documentElement
-              (.setAttribute "data-font" (or editor-font "default")))
-     [editor-font])
+      (fn []
+        (when-let [{:keys [type global]} editor-font]
+          (doto js/document.documentElement
+            (.setAttribute "data-font" (or type "default"))
+            (.setAttribute "data-font-global" (boolean global)))))
+      [editor-font])
 
     (hooks/use-effect!
      #(let [doc js/document.documentElement]

+ 11 - 2
src/main/frontend/components/theme.css

@@ -16,7 +16,7 @@
   }
 }
 
-.visible-scrollbar , html.custom-scrollbar {
+.visible-scrollbar, html.custom-scrollbar {
   ::-webkit-scrollbar-thumb {
     background-color: var(--lx-gray-05, var(--ls-scrollbar-foreground-color, var(--rx-gray-05)));
   }
@@ -89,7 +89,8 @@ html[data-theme='light'] .theme-container {
   }
 }
 
-html[data-theme='dark'] .theme-container {}
+html[data-theme='dark'] .theme-container {
+}
 
 html.locked-scroll {
   overflow: hidden !important;
@@ -195,6 +196,14 @@ html[data-font='serif'] .ls-block, .ls-font-serif {
   font-family: Lyon-Text, Georgia, ui-serif, serif;
 }
 
+html[data-font='serif'][data-font-global='true'] {
+  --ls-font-family: Lyon-Text, Georgia, ui-serif, serif;
+}
+
 html[data-font='mono'] .ls-block, .ls-font-mono {
   font-family: iawriter-mono, Nitti, Menlo, Courier, monospace;
 }
+
+html[data-font='mono'][data-font-global='true'] {
+  --ls-font-family: iawriter-mono, Nitti, Menlo, Courier, monospace;
+}

+ 5 - 4
src/main/frontend/state.cljs

@@ -2287,10 +2287,11 @@ Similar to re-frame subscriptions"
   (swap! state assoc :ui/radix-color color)
   (storage/set :ui/radix-color color))
 
-(defn set-editor-font! [font]
-  (let [font (if (keyword? font) (name font) (str font))]
-    (swap! state assoc :ui/editor-font font)
-    (storage/set :ui/editor-font font)))
+(defn set-editor-font! [config]
+  (let [config' (:ui/editor-font @state)
+        config (if (map? config') (merge config' config) {})]
+    (swap! state assoc :ui/editor-font config)
+    (storage/set :ui/editor-font config)))
 
 (defn handbook-open?
   []

+ 33 - 13
src/main/frontend/worker/rtc/ws.cljs

@@ -174,24 +174,44 @@
 (defn- send&recv*
   "Return a task: send message wait to recv its response and return it.
   Throw if timeout"
-  [mws message & {:keys [timeout-ms] :or {timeout-ms 10000}}]
+  [mws message & {:keys [timeout-ms s3-get-timeout-ms]
+                  :or {timeout-ms 10000 s3-get-timeout-ms 10000}}]
   {:pre [(pos-int? timeout-ms)
          (some? (:req-id message))]}
   (m/sp
     (m/? (send mws message))
     (let [req-id (:req-id message)
-          result (m/?
-                  (m/timeout
-                   (m/reduce
-                    (fn [_ v]
-                      (when (= req-id (:req-id v))
-                        (reduced v)))
-                    (recv-flow mws))
-                   timeout-ms))]
-      (when-not result
-        (throw (ex-info (str "recv timeout (" timeout-ms "ms)") {:missionary/retry true
-                                                                 :type :rtc.exception/ws-timeout
-                                                                 :message message})))
+          ws-message-result
+          (m/?
+           (m/timeout
+            (m/reduce
+             (fn [_ v]
+               (when (= req-id (:req-id v))
+                 (reduced v)))
+             (recv-flow* mws))
+            timeout-ms
+            (ex-info (str "recv ws message timeout (" timeout-ms "ms)") {})))
+          result (if-let [s3-presign-url (:s3-presign-url ws-message-result)]
+                   (let [{:keys [status body] :as r}
+                         (m/? (m/timeout
+                               (http/get s3-presign-url {:with-credentials? false})
+                               s3-get-timeout-ms
+                               (ex-info (str "recv s3 message timeout (" s3-get-timeout-ms "ms)") {})))]
+                     (cond
+                       (instance? ExceptionInfo r) r
+
+                       (http/unexceptional-status? status)
+                       (rtc-schema/data-from-ws-coercer (js->clj (js/JSON.parse body) :keywordize-keys true))
+
+                       :else
+                       {:req-id (:req-id ws-message-result)
+                        :ex-message "get s3 object failed"
+                        :ex-data {:type :rtc.exception/get-s3-object-failed :status status :body body}}))
+                   ws-message-result)]
+      (when (instance? ExceptionInfo result)
+        (throw (ex-info (ex-message result) {:missionary/retry true
+                                             :type :rtc.exception/ws-timeout
+                                             :message message})))
       result)))
 
 (defn send&recv