Просмотр исходного кода

feat(marketplace): download updates with one click

charlie 4 лет назад
Родитель
Сommit
de1ea231e3

+ 4 - 3
src/electron/electron/plugin.cljs

@@ -39,7 +39,8 @@
            zipball
            (api "zipball"))
          asset)
-       version])
+       version
+       (:body res)])
 
     (fn [^js e]
       (emit :lsp-installed {:status :error :payload e})
@@ -130,7 +131,7 @@
             (fn [resolve _reject]
               ;;(reset! *installing-or-updating item)
               ;; get releases
-              (-> (p/let [[asset latest-version] (fetch-latest-release-asset item)
+              (-> (p/let [[asset latest-version notes] (fetch-latest-release-asset item)
 
                           _ (debug "[Release Asset] #" latest-version " =>" (:url asset))
 
@@ -160,7 +161,7 @@
                           {:status     :completed
                            :only-check only-check
                            :payload    (if only-check
-                                         (assoc item :latest-version latest-version)
+                                         (assoc item :latest-version latest-version :latest-notes notes)
                                          (assoc item :zip dl-url :dst dest))})
 
                     (resolve nil))

+ 72 - 2
src/main/frontend/components/plugins.cljs

@@ -576,6 +576,69 @@
                 (and updating (= (keyword (:id updating)) pid))
                 true nil (get coming-updates pid))) (:id item)))]])))
 
+(rum/defcs waiting-coming-updates
+  < rum/reactive
+    {:will-mount (fn [s] (state/reset-unchecked-update) s)}
+  [_s]
+  (let [_ (state/sub :plugin/updates-coming)
+        downloading? (state/sub :plugin/updates-downloading?)
+        unchecked (state/sub :plugin/updates-unchecked)
+        updates (state/all-available-coming-updates)]
+
+    [:div.cp__plugins-waiting-updates
+     [:h1.mb-4.text-2xl.p-1 (util/format "Found %s updates" (util/safe-parse-int (count updates)))]
+
+     (if (seq updates)
+       ;; lists
+       [:ul
+        {:class (when downloading? "downloading")}
+        (for [it updates
+              :let [k (str "lsp-it-" (:id it))
+                    c? (not (contains? unchecked (:id it)))
+                    notes (util/trim-safe (:latest-notes it))]]
+          [:li.flex.items-center
+           {:key   k
+            :class (when c? "checked")}
+
+           [:label.flex-1
+            {:for k}
+            (ui/checkbox {:id        k
+                          :checked   c?
+                          :on-change (fn [^js e]
+                                       (when-not downloading?
+                                         (state/set-unchecked-update (:id it) (not (util/echecked? e)))))})
+            [:strong.px-3 (:title it)
+             [:sup (str (:version it) " 👉 " (:latest-version it))]]]
+
+           [:div.px-4
+            (when-not (string/blank? notes)
+              (ui/tippy
+                {:html [:p notes]}
+                [:span.opacity-30.hover:opacity-80 (ui/icon "info-circle")]))]])]
+
+       ;; all done
+       [:div.py-4 [:strong.text-4xl "\uD83C\uDF89 All updated!"]])
+
+     ;; actions
+     (when (seq updates)
+       [:div.pt-5
+        (ui/button
+          (if downloading?
+            [:span (ui/loading " Downloading...")]
+            [:span "Update all of selected"])
+
+          :on-click
+          #(when-not downloading?
+             (state/set-state! :plugin/updates-downloading? true)
+             (plugin-handler/check-or-update-marketplace-plugin
+               (assoc (state/get-next-selected-coming-update) :only-check false)
+               (fn [^js e] (notification/show! e :error))))
+
+          :disabled
+          (or downloading?
+              (and (not (empty? unchecked))
+                   (= (count unchecked) (count updates)))))])]))
+
 (defn open-select-theme!
   []
   (state/set-sub-modal! installed-themes))
@@ -677,5 +740,12 @@
 (defn open-plugins-modal!
   []
   (state/set-modal!
-    (fn [close!]
-      (plugins-page))))
+    (fn [_close!]
+      (plugins-page))))
+
+(defn open-waiting-updates-modal!
+  []
+  (state/set-sub-modal!
+    (fn [_close!]
+      (waiting-coming-updates))
+    {:center? true}))

+ 21 - 0
src/main/frontend/components/plugins.css

@@ -425,6 +425,27 @@
 
   &-details {
   }
+
+  &-waiting-updates {
+    margin: -15px;
+
+    > ul {
+      li {
+        user-select: none;
+        justify-content: space-between;
+        opacity: .9;
+
+        sup {
+          padding-left: 8px;
+          font-weight: 400;
+        }
+
+        &:hover, &.checked {
+          opacity: 1;
+        }
+      }
+    }
+  }
 }
 
 .cp__themes {

+ 20 - 5
src/main/frontend/handler/events.cljs

@@ -211,6 +211,10 @@
 (defmethod handle :go/plugins [_]
   (plugin/open-plugins-modal!))
 
+(defmethod handle :go/plugins-waiting-lists [_]
+  (plugin/open-waiting-updates-modal!))
+
+
 (defmethod handle :redirect-to-home [_]
   (page-handler/create-today-journal!))
 
@@ -241,11 +245,22 @@
       (str "Checked: " (:title coming))
       :success))
 
-  ;; try to start consume pending item
-  (when-let [n (second (first (:plugin/updates-pending @state/state)))]
-    (plugin-handler/check-or-update-marketplace-plugin
-      (assoc n :only-check true)
-      (fn [^js e] (js/console.error "[Check Err]" n e)))))
+  (if (and updated? (:plugin/updates-downloading? @state/state))
+    ;; try to start consume downloading item
+    (if-let [n (state/get-next-selected-coming-update)]
+      (plugin-handler/check-or-update-marketplace-plugin
+        (assoc n :only-check false)
+        (fn [^js e] (js/console.error "[Download Err]" n e)))
+      (state/set-state! :plugin/updates-downloading? false))
+
+    ;; try to start consume pending item
+    (if-let [n (second (first (:plugin/updates-pending @state/state)))]
+      (plugin-handler/check-or-update-marketplace-plugin
+        (assoc n :only-check true)
+        (fn [^js e] (js/console.error "[Check Err]" n e)))
+      ;; try to open waiting updates list
+      (when (and pending? (seq (state/all-available-coming-updates)))
+        (plugin/open-waiting-updates-modal!)))))
 
 (defn run!
   []

+ 2 - 0
src/main/frontend/handler/plugin.cljs

@@ -159,6 +159,8 @@
 
                          (if (and only-check updates-pending?)
                            (state/consume-updates-coming-plugin payload false)
+
+                           ;; TODO: consume failed download updates?
                            (notifications/show!
                              (str
                                (if (= :error type) "[Install Error]" "")

+ 212 - 188
src/main/frontend/state.cljs

@@ -21,193 +21,195 @@
             [cljs.cache :as cache]))
 
 (defonce state
-  (let [document-mode? (or (storage/get :document/mode?) false)
-        current-graph (let [graph (storage/get :git/current-repo)]
-                        (when graph (ipc/ipc "setCurrentGraph" graph))
-                        graph)]
-    (atom
-     {:route-match nil
-      :today nil
-      :system/events (async/chan 100)
-      :db/batch-txs (async/chan 100)
-      :file/writes (async/chan 100)
-      :notification/show? false
-      :notification/content nil
-      :repo/cloning? false
-      :repo/loading-files? {}
-      :repo/importing-to-db? nil
-      :repo/sync-status {}
-      :repo/changed-files nil
-      :nfs/user-granted? {}
-      :nfs/refreshing? nil
-      :instrument/disabled? (storage/get "instrument-disabled")
-      ;; TODO: how to detect the network reliably?
-      :network/online? true
-      :indexeddb/support? true
-      :me nil
-      :git/current-repo current-graph
-      :git/status {}
-      :format/loading {}
-      :draw? false
-      :db/restoring? nil
-
-      :journals-length 2
-
-      :search/q ""
-      :search/mode :global
-      :search/result nil
-      :search/graph-filters []
-
-      ;; modals
-      :modal/label                           ""
-      :modal/show?                           false
-      :modal/panel-content                   nil
-      :modal/fullscreen?                     false
-      :modal/close-btn?                      nil
-      :modal/subsets                         []
-
-      ;; right sidebar
-      :ui/fullscreen? false
-      :ui/settings-open? false
-      :ui/sidebar-open? false
-      :ui/left-sidebar-open? (boolean (storage/get "ls-left-sidebar-open?"))
-      :ui/theme (or (storage/get :ui/theme) (if (mobile/is-native-platform?) "light" "dark"))
-      :ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
-      :ui/wide-mode? false
-      ;; :show-all, :hide-block-body, :hide-block-children
-      :ui/cycle-collapse :show-all
-
-      ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
-      ;; 1. right sidebar
-      ;; 2. zoom-in view
-      ;; 3. queries
-      ;; 4. references
-      ;; graph => {:block-id bool}
-      :ui/collapsed-blocks {}
-      :ui/sidebar-collapsed-blocks {}
-      :ui/root-component nil
-      :ui/file-component nil
-      :ui/custom-query-components {}
-      :ui/show-recent? false
-      :ui/command-palette-open? false
-      :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
-                              false)
-      ;; remember scroll positions of visited paths
-      :ui/paths-scroll-positions {}
-      :ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
-                              false
-                              true)
-      :ui/visual-viewport-pending? false
-      :ui/visual-viewport-state nil
-
-      :document/mode? document-mode?
-
-      :github/contents {}
-      :config {}
-      :block/component-editing-mode? false
-      :editor/draw-mode? false
-      :editor/show-page-search? false
-      :editor/show-page-search-hashtag? false
-      :editor/show-date-picker? false
-      ;; With label or other data
-      :editor/show-input nil
-      :editor/show-zotero false
-      :editor/last-saved-cursor nil
-      :editor/editing? nil
-      :editor/last-edit-block-input-id nil
-      :editor/last-edit-block-id nil
-      :editor/in-composition? false
-      :editor/content {}
-      :editor/block nil
-      :editor/block-dom-id nil
-      :editor/set-timestamp-block nil
-      :editor/last-input-time nil
-      :editor/pos nil
-      :editor/document-mode? document-mode?
-      :editor/args nil
-      :editor/on-paste? false
-      :editor/last-key-code nil
-
-      :db/last-transact-time {}
-      :db/last-persist-transact-ids {}
-      ;; whether database is persisted
-      :db/persisted? {}
-      :db/latest-txs (or (storage/get-transit :db/latest-txs) {})
-      :cursor-range nil
-
-      :selection/mode false
-      :selection/blocks []
-      :selection/start-block nil
-      ;; either :up or :down, defaults to down
-      ;; used to determine selection direction when two or more blocks are selected
-      :selection/direction :down
-      :custom-context-menu/show? false
-      :custom-context-menu/links nil
-
-      ;; pages or blocks in the right sidebar
-      ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
-      :sidebar/blocks '()
-
-      :preferred-language (storage/get :preferred-language)
-
-      ;; electron
-      :electron/auto-updater-downloaded false
-      :electron/updater-pending? false
-      :electron/updater {}
-      :electron/user-cfgs nil
-
-      ;; plugin
-      :plugin/enabled   (and (util/electron?)
-                             ;; true false :theme-only
-                             ((fnil identity true) (storage/get :lsp-core-enabled)))
-      :plugin/indicator-text        nil
-      :plugin/installed-plugins     {}
-      :plugin/installed-themes      []
-      :plugin/installed-commands    {}
-      :plugin/installed-ui-items    {}
-      :plugin/simple-commands       {}
-      :plugin/selected-theme        nil
-      :plugin/selected-unpacked-pkg nil
-      :plugin/marketplace-pkgs      nil
-      :plugin/marketplace-stats     nil
-      :plugin/installing            nil
-      :plugin/active-readme         nil
-      :plugin/updates-pending       {}
-      :plugin/updates-coming        {}
-
-      ;; pdf
-      :pdf/current                  nil
-      :pdf/ref-highlight            nil
-
-      ;; all notification contents as k-v pairs
-      :notification/contents {}
-      :graph/syncing? false
-
-      ;; copied blocks
-      :copy/blocks {:copy/content nil :copy/block-tree nil}
-
-      :copy/export-block-text-indent-style  (or (storage/get :copy/export-block-text-indent-style)
-                                                "dashes")
-      :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
-                                                 #{})
-      :date-picker/date nil
-
-      :youtube/players {}
-
-      ;; command palette
-      :command-palette/commands []
-
-      :view/components {}
-
-      :debug/write-acks {}
-
-      :encryption/graph-parsing? false
-
-      :favorites/dragging nil
-
-      :srs/mode? false
-
-      :srs/cards-due-count nil})))
+         (let [document-mode? (or (storage/get :document/mode?) false)
+               current-graph (let [graph (storage/get :git/current-repo)]
+                               (when graph (ipc/ipc "setCurrentGraph" graph))
+                               graph)]
+           (atom
+             {:route-match                           nil
+              :today                                 nil
+              :system/events                         (async/chan 100)
+              :db/batch-txs                          (async/chan 100)
+              :file/writes                           (async/chan 100)
+              :notification/show?                    false
+              :notification/content                  nil
+              :repo/cloning?                         false
+              :repo/loading-files?                   {}
+              :repo/importing-to-db?                 nil
+              :repo/sync-status                      {}
+              :repo/changed-files                    nil
+              :nfs/user-granted?                     {}
+              :nfs/refreshing?                       nil
+              :instrument/disabled?                  (storage/get "instrument-disabled")
+              ;; TODO: how to detect the network reliably?
+              :network/online?                       true
+              :indexeddb/support?                    true
+              :me                                    nil
+              :git/current-repo                      current-graph
+              :git/status                            {}
+              :format/loading                        {}
+              :draw?                                 false
+              :db/restoring?                         nil
+
+              :journals-length                       2
+
+              :search/q                              ""
+              :search/mode                           :global
+              :search/result                         nil
+              :search/graph-filters                  []
+
+              ;; modals
+              :modal/label                           ""
+              :modal/show?                           false
+              :modal/panel-content                   nil
+              :modal/fullscreen?                     false
+              :modal/close-btn?                      nil
+              :modal/subsets                         []
+
+              ;; right sidebar
+              :ui/fullscreen?                        false
+              :ui/settings-open?                     false
+              :ui/sidebar-open?                      false
+              :ui/left-sidebar-open?                 (boolean (storage/get "ls-left-sidebar-open?"))
+              :ui/theme                              (or (storage/get :ui/theme) (if (mobile/is-native-platform?) "light" "dark"))
+              :ui/system-theme?                      ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
+              :ui/wide-mode?                         false
+              ;; :show-all, :hide-block-body, :hide-block-children
+              :ui/cycle-collapse                     :show-all
+
+              ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
+              ;; 1. right sidebar
+              ;; 2. zoom-in view
+              ;; 3. queries
+              ;; 4. references
+              ;; graph => {:block-id bool}
+              :ui/collapsed-blocks                   {}
+              :ui/sidebar-collapsed-blocks           {}
+              :ui/root-component                     nil
+              :ui/file-component                     nil
+              :ui/custom-query-components            {}
+              :ui/show-recent?                       false
+              :ui/command-palette-open?              false
+              :ui/developer-mode?                    (or (= (storage/get "developer-mode") "true")
+                                                         false)
+              ;; remember scroll positions of visited paths
+              :ui/paths-scroll-positions             {}
+              :ui/shortcut-tooltip?                  (if (false? (storage/get :ui/shortcut-tooltip?))
+                                                       false
+                                                       true)
+              :ui/visual-viewport-pending?           false
+              :ui/visual-viewport-state              nil
+
+              :document/mode?                        document-mode?
+
+              :github/contents                       {}
+              :config                                {}
+              :block/component-editing-mode?         false
+              :editor/draw-mode?                     false
+              :editor/show-page-search?              false
+              :editor/show-page-search-hashtag?      false
+              :editor/show-date-picker?              false
+              ;; With label or other data
+              :editor/show-input                     nil
+              :editor/show-zotero                    false
+              :editor/last-saved-cursor              nil
+              :editor/editing?                       nil
+              :editor/last-edit-block-input-id       nil
+              :editor/last-edit-block-id             nil
+              :editor/in-composition?                false
+              :editor/content                        {}
+              :editor/block                          nil
+              :editor/block-dom-id                   nil
+              :editor/set-timestamp-block            nil
+              :editor/last-input-time                nil
+              :editor/pos                            nil
+              :editor/document-mode?                 document-mode?
+              :editor/args                           nil
+              :editor/on-paste?                      false
+              :editor/last-key-code                  nil
+
+              :db/last-transact-time                 {}
+              :db/last-persist-transact-ids          {}
+              ;; whether database is persisted
+              :db/persisted?                         {}
+              :db/latest-txs                         (or (storage/get-transit :db/latest-txs) {})
+              :cursor-range                          nil
+
+              :selection/mode                        false
+              :selection/blocks                      []
+              :selection/start-block                 nil
+              ;; either :up or :down, defaults to down
+              ;; used to determine selection direction when two or more blocks are selected
+              :selection/direction                   :down
+              :custom-context-menu/show?             false
+              :custom-context-menu/links             nil
+
+              ;; pages or blocks in the right sidebar
+              ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
+              :sidebar/blocks                        '()
+
+              :preferred-language                    (storage/get :preferred-language)
+
+              ;; electron
+              :electron/auto-updater-downloaded      false
+              :electron/updater-pending?             false
+              :electron/updater                      {}
+              :electron/user-cfgs                    nil
+
+              ;; plugin
+              :plugin/enabled                        (and (util/electron?)
+                                                          ;; true false :theme-only
+                                                          ((fnil identity true) (storage/get :lsp-core-enabled)))
+              :plugin/indicator-text                 nil
+              :plugin/installed-plugins              {}
+              :plugin/installed-themes               []
+              :plugin/installed-commands             {}
+              :plugin/installed-ui-items             {}
+              :plugin/simple-commands                {}
+              :plugin/selected-theme                 nil
+              :plugin/selected-unpacked-pkg          nil
+              :plugin/marketplace-pkgs               nil
+              :plugin/marketplace-stats              nil
+              :plugin/installing                     nil
+              :plugin/active-readme                  nil
+              :plugin/updates-pending                {}
+              :plugin/updates-coming                 {}
+              :plugin/updates-downloading?           false
+              :plugin/updates-unchecked              #{}
+
+              ;; pdf
+              :pdf/current                           nil
+              :pdf/ref-highlight                     nil
+
+              ;; all notification contents as k-v pairs
+              :notification/contents                 {}
+              :graph/syncing?                        false
+
+              ;; copied blocks
+              :copy/blocks                           {:copy/content nil :copy/block-tree nil}
+
+              :copy/export-block-text-indent-style   (or (storage/get :copy/export-block-text-indent-style)
+                                                         "dashes")
+              :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
+                                                         #{})
+              :date-picker/date                      nil
+
+              :youtube/players                       {}
+
+              ;; command palette
+              :command-palette/commands              []
+
+              :view/components                       {}
+
+              :debug/write-acks                      {}
+
+              :encryption/graph-parsing?             false
+
+              :favorites/dragging                    nil
+
+              :srs/mode?                             false
+
+              :srs/cards-due-count                   nil})))
 
 ;; block uuid -> {content(String) -> ast}
 (def blocks-ast-cache (atom (cache/lru-cache-factory {} :threshold 5000)))
@@ -1704,7 +1706,7 @@
 (defn consume-updates-coming-plugin
   [payload updated?]
   (when-let [id (keyword (:id payload))]
-    (let [pending? (seq (:plugin/updates-pending @state))]
+    (let [pending? (boolean (seq (:plugin/updates-pending @state)))]
       (swap! state update :plugin/updates-pending dissoc id)
       (if updated?
         (swap! state update :plugin/updates-coming dissoc id)
@@ -1720,6 +1722,28 @@
   (when-let [pkg (and id (get (:plugin/updates-coming @state) (keyword id)))]
     (coming-update-new-version? pkg)))
 
+(defn all-available-coming-updates
+  []
+  (when-let [updates (vals (:plugin/updates-coming @state))]
+    (filterv #(coming-update-new-version? %) updates)))
+
+(defn get-next-selected-coming-update
+  []
+  (when-let [updates (all-available-coming-updates)]
+    (let [unchecked (:plugin/updates-unchecked @state)]
+      (first
+        (if (seq unchecked)
+          (filter #(not (contains? unchecked (:id %))) updates)
+          updates)))))
+
+(defn set-unchecked-update
+  [id unchecked?]
+  (swap! state update :plugin/updates-unchecked (if unchecked? conj disj) id))
+
+(defn reset-unchecked-update
+  []
+  (swap! state assoc :plugin/updates-unchecked #{}))
+
 (defn sub-right-sidebar-blocks
   []
   (when-let [current-repo (get-current-repo)]

+ 1 - 0
src/main/frontend/ui.css

@@ -181,6 +181,7 @@ html.is-mobile {
 
   &:disabled {
     opacity: 0.5;
+    cursor: not-allowed;
   }
 
   &:hover {