Fix more bugs, move plugins.edn and add enabled

- Move plugins.edn to config/ as it is user configuration
- Add plugin-config enabled flag and moved plugin enabled
- Fixed bugs with manual install
- Refactored plugin-config component to have its own listener
- Split out shared plugin fns to a common ns - plugin-config shouldn't
  need to depend on a component like plugin-handler
- Bump rewrite-edn to include upstream fix and avoid tons of cljs
  warnings with earlier versions
- Fix react warning introduced outside this PR in ui/icon
pull/6911/head
Gabriel Horner 2022-10-10 11:46:29 -04:00
parent 784ad7cce3
commit 0c570a0300
22 changed files with 196 additions and 163 deletions

View File

@ -43,12 +43,15 @@
frontend.handler.extract extract
frontend.handler.common common-handler
frontend.handler.common.file file-common-handler
frontend.handler.common.plugin plugin-common-handler
frontend.handler.config config-handler
frontend.handler.events events
frontend.handler.global-config global-config-handler
frontend.handler.ui ui-handler
frontend.handler.notification notification
frontend.handler.page page-handler
frontend.handler.plugin plugin-handler
frontend.handler.plugin-config plugin-config-handler
frontend.handler.repo repo-handler
frontend.handler.repo-config repo-config-handler
frontend.handler.search search-handler

View File

@ -4,7 +4,9 @@
rum/rum {:mvn/version "0.12.9"}
datascript/datascript {:mvn/version "1.3.8"}
datascript-transit/datascript-transit {:mvn/version "0.3.0"}
borkdude/rewrite-edn {:mvn/version "0.1.0"}
;; TODO: bump to mvn/version when released
borkdude/rewrite-edn {:git/url "https://github.com/borkdude/rewrite-edn"
:sha "80f246139b1a43b6f2cbab329521d060ee7c1b7b"}
funcool/promesa {:mvn/version "4.0.2"}
medley/medley {:mvn/version "1.4.0"}
metosin/reitit-frontend {:mvn/version "0.3.10"}

View File

@ -1503,7 +1503,7 @@
(= name "embed")
(macro-embed-cp config arguments)
(and plugin-handler/lsp-enabled? (= name "renderer"))
(and config/lsp-enabled? (= name "renderer"))
(when-let [block-uuid (str (:block/uuid config))]
(plugins/hook-ui-slot :macro-renderer-slotted (assoc options :uuid block-uuid)))

View File

@ -75,12 +75,12 @@
:options {:on-click state/open-settings!}
:icon (ui/icon "settings")})
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
{:title (t :plugins)
:options {:on-click #(plugin-handler/goto-plugins-dashboard!)}
:icon (ui/icon "apps")})
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
{:title (t :themes)
:options {:on-click #(plugins/open-select-theme!)}
:icon (ui/icon "palette")})
@ -209,7 +209,7 @@
(when sync-enabled?
(login))
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
(plugins/hook-ui-items :toolbar))
(when (util/electron?)

View File

@ -23,7 +23,6 @@
[frontend.handler.graph :as graph-handler]
[frontend.handler.notification :as notification]
[frontend.handler.page :as page-handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.route :as route-handler]
[frontend.mixins :as mixins]
[frontend.mobile.util :as mobile-util]
@ -425,7 +424,7 @@
[:h1.title.ls-page-title (page-title page-name icon title format fmt-journal?)]])
(when (not config/publishing?)
[:div.flex.flex-row
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
(plugins/hook-ui-slot :page-head-actions-slotted nil)
(plugins/hook-ui-items :pagebar))])])
[:div

View File

@ -12,7 +12,6 @@
[frontend.util :as util]
[frontend.util.url :as url-util]
[frontend.handler.shell :as shell]
[frontend.handler.plugin :as plugin-handler]
[frontend.mobile.util :as mobile-util]
[electron.ipc :as ipc]
[frontend.config :as config]
@ -152,7 +151,7 @@
(fn []
(ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-path))}})
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
(for [[_ {:keys [label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
{:title label
:options {:on-click #(commands/exec-plugin-simple-command!

View File

@ -5,7 +5,8 @@
[frontend.context.i18n :refer [t]]
[frontend.ui :as ui]
[frontend.handler.ui :as ui-handler]
[frontend.handler.plugin-config :as plugin-config]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.common.plugin :as plugin-common-handler]
[frontend.search :as search]
[frontend.util :as util]
[frontend.mixins :as mixins]
@ -199,7 +200,7 @@
[:a.btn
{:class (util/classnames [{:disabled (or installed? installing-or-updating?)
:installing installing-or-updating?}])
:on-click #(plugin-handler/install-marketplace-plugin item)}
:on-click #(plugin-common-handler/install-marketplace-plugin item)}
(if installed?
(t :plugin/installed)
(if installing-or-updating?
@ -224,8 +225,8 @@
{:title (t :plugin/delete-alert name)
:on-confirm (fn [_ {:keys [close-fn]}]
(close-fn)
(plugin-handler/unregister-plugin id)
(plugin-config/remove-plugin id))})]
(plugin-common-handler/unregister-plugin id)
(plugin-config-handler/remove-plugin id))})]
(state/set-sub-modal! confirm-fn {:center? true}))}
(t :plugin/uninstall)]]]
@ -548,7 +549,7 @@
:options {:on-click #(state/pub-event! [:go/proxy-settings agent-opts])}}]
[{:title [:span.flex.items-center (ui/icon "arrow-down-circle") (t :plugin/install-from-file)]
:options {:on-click plugin-config/open-sync-modal}}]
:options {:on-click plugin-config-handler/open-sync-modal}}]
(when (state/developer-mode?)
[{:hr true}
@ -822,7 +823,7 @@
[:div.pt-5
(ui/button [:span "Install"]
:on-click #(do
(plugin-config/update-plugins plugins)
(plugin-config-handler/replace-plugins plugins)
(state/close-sub-modal! "ls-plugins-from-file-modal")))]]
;; all done
[:div.py-4 [:strong.text-xl "\uD83C\uDF89 All synced!"]])])

View File

@ -726,7 +726,7 @@
(let [current-repo (state/sub :git/current-repo)
;; enable-block-timestamps? (state/enable-block-timestamps?)
_installed-plugins (state/sub :plugin/installed-plugins)
plugins-of-settings (and plugin-handler/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
plugins-of-settings (and config/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
*active (::active state)]
[:div#settings.cp__settings-main

View File

@ -1,7 +1,8 @@
(ns frontend.components.theme
(:require [frontend.extensions.pdf.highlights :as pdf]
[frontend.config :as config]
[frontend.handler.plugin :refer [lsp-enabled?] :as plugin-handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.route :as route-handler]
[frontend.handler.ui :as ui-handler]
[frontend.ui :as ui]
@ -41,9 +42,12 @@
[sidebar-open? restored-sidebar? sidebar-blocks-len])
(rum/use-effect!
#(when lsp-enabled?
#(when config/lsp-enabled?
(plugin-handler/setup-install-listener!)
(plugin-handler/load-plugin-preferences))
(plugin-config-handler/setup-install-listener!)
(plugin-handler/load-plugin-preferences)
(fn []
(js/window.apis.removeAllListeners "lsp-installed")))
[])
(rum/use-effect!

View File

@ -35,16 +35,32 @@
(def API-DOMAIN "api-dev.logseq.com")
(def WS-URL "wss://ws-dev.logseq.com/file-sync?graphuuid=%s")))
;; feature flags
;; Feature flags
;; =============
(goog-define ENABLE-PLUGINS true)
(defonce enable-plugins? ENABLE-PLUGINS)
(swap! state/state assoc :plugin/enabled enable-plugins?)
;; Desktop only as other platforms requires better understanding of their
;; multi-graph workflows and optimal place for a "global" dir
(def global-config-enabled? util/electron?)
;; User level configuration for whether plugins are enabled
(defonce lsp-enabled?
(and (util/electron?)
(state/lsp-enabled?-or-theme)))
(defn plugin-config-enabled?
[]
(and lsp-enabled? (global-config-enabled?)))
;; :TODO: How to do this?
;; (defonce desktop? ^boolean goog.DESKTOP)
;; ============
(def app-name "logseq")
(def website
(if dev?
@ -289,10 +305,6 @@
(def config-default-content (rc/inline "config.edn"))
;; Desktop only as other platforms requires better understanding of their
;; multi-graph workflows and optimal place for a "global" dir
(def global-config-enabled? util/electron?)
(defonce idb-db-prefix "logseq-db/")
(defonce local-db-prefix "logseq_local_")
(defonce local-handle "handle")

View File

@ -4,7 +4,7 @@
[frontend.ui :as ui]
[frontend.config :as config]
[frontend.util :as util]
[frontend.handler.plugin :refer [lsp-enabled? hook-extensions-enhancer-by-type] :as plugin-handler]
[frontend.handler.plugin :refer [hook-extensions-enhancer-by-type] :as plugin-handler]
[promesa.core :as p]
[goog.dom :as gdom]))
@ -42,7 +42,7 @@
(config/asset-uri "/static/js/mhchem.min.js")
(fn []
(p/finally
(p/all (when-let [enhancers (and lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
(p/all (when-let [enhancers (and config/lsp-enabled? (seq (hook-extensions-enhancer-by-type :katex)))]
(for [{f :enhancer} enhancers]
(when (fn? f) (f js/window.katex)))))
(fn []

View File

@ -7,7 +7,7 @@
[frontend.extensions.pdf.utils :as pdf-utils]
[frontend.extensions.pdf.toolbar :refer [pdf-toolbar *area-dashed? *area-mode? *highlight-mode? *highlights-ctx*]]
[frontend.handler.notification :as notification]
[frontend.handler.plugin :as plugin-handler]
[frontend.config :as config]
[frontend.modules.shortcut.core :as shortcut]
[frontend.commands :as commands]
[frontend.rum :refer [use-atom]]
@ -193,7 +193,7 @@
(and id [:li.item {:data-action "del"} (t :delete)])
(when (and plugin-handler/lsp-enabled? text?)
(when (and config/lsp-enabled? text?)
(for [[_ {:keys [key label extras] :as _cmd} action pid]
(state/get-plugins-commands-with-type :highlight-context-menu-item)]
[:li.item {:key key

View File

@ -28,7 +28,7 @@
[frontend.handler.user :as user-handler]
[frontend.handler.repo-config :as repo-config-handler]
[frontend.handler.global-config :as global-config-handler]
[frontend.handler.plugin-config :as plugin-config]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.metadata :as metadata-handler]
[frontend.idb :as idb]
[frontend.mobile.util :as mobile-util]
@ -93,8 +93,7 @@
(p/do! (repo-config-handler/start {:repo repo})
(when (config/global-config-enabled?)
(global-config-handler/start {:repo repo}))
;; TODO: Is there a better place for this setup?
(plugin-config/start))
(when (config/plugin-config-enabled?) (plugin-config-handler/start)))
(p/finally
(fn []
;; install after config is restored

View File

@ -0,0 +1,27 @@
(ns frontend.handler.common.plugin
"Common plugin related fns for handlers and api"
(:require [frontend.state :as state]
[promesa.core :as p]
[electron.ipc :as ipc]))
(defn installed?
"For the given plugin id, returns boolean indicating if it is installed"
[id]
(and (contains? (:plugin/installed-plugins @state/state) (keyword id))
(get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
(defn install-marketplace-plugin
"Installs plugin given plugin map with id"
[{:keys [id] :as mft}]
(when-not (and (:plugin/installing @state/state)
(installed? id))
(p/create
(fn [resolve]
(state/set-state! :plugin/installing mft)
(ipc/ipc :installMarketPlugin mft)
(resolve id)))))
(defn unregister-plugin
"Unregister and uninstall plugin given plugin id"
[id]
(js/LSPluginCore.unregister id))

View File

@ -6,7 +6,7 @@
[clojure.walk :as walk]
[logseq.graph-parser.mldoc :as gp-mldoc]
[frontend.handler.notification :as notification]
[frontend.handler.plugin-config :as plugin-config]
[frontend.handler.common.plugin :as plugin-common-handler]
[camel-snake-kebab.core :as csk]
[frontend.state :as state]
[medley.core :as medley]
@ -17,12 +17,9 @@
[lambdaisland.glogi :as log]
[frontend.components.svg :as svg]
[frontend.context.i18n :refer [t]]
[frontend.config :as config]
[frontend.format :as format]))
(defonce lsp-enabled?
(and (util/electron?)
(state/lsp-enabled?-or-theme)))
(defn- normalize-keyword-for-json
[input]
(when input
@ -112,25 +109,10 @@
(util/fetch stats-url on-ok reject)))))
(p/resolved nil)))
(defn installed?
[id]
(and (contains? (:plugin/installed-plugins @state/state) (keyword id))
(get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
(defn install-marketplace-plugin
[{:keys [id] :as mft}]
(when-not (and (:plugin/installing @state/state)
(installed? id))
(p/create
(fn [resolve]
(state/set-state! :plugin/installing mft)
(ipc/ipc :installMarketPlugin mft)
(resolve id)))))
(defn check-or-update-marketplace-plugin
[{:keys [id] :as pkg} error-handler]
(when-not (and (:plugin/installing @state/state)
(not (installed? id)))
(not (plugin-common-handler/installed? id)))
(p/catch
(p/then
(do (state/set-state! :plugin/installing pkg)
@ -198,7 +180,7 @@
name (or title name "Untitled")]
(if only-check
(state/consume-updates-coming-plugin payload false)
(if (installed? id)
(if (plugin-common-handler/installed? id)
(when-let [^js pl (get-plugin-inst id)] ;; update
(p/then
(.reload pl)
@ -212,10 +194,6 @@
(p/then
(js/LSPluginCore.register (bean/->js {:key id :url dst}))
(fn [] (when theme (js/setTimeout #(select-a-plugin-theme id) 300))))
(plugin-config/add-or-update-plugin
(assoc payload
:version (:installed-version payload)
:name name))
(notification/show!
(str (t :plugin/installed) (t :plugins) ": " name) :success)))))
@ -252,23 +230,15 @@
(js/setTimeout #(state/set-state! :plugin/installing nil) 512)
true)]
(js/window.apis.addListener channel listener)
;; clear
(fn []
(js/window.apis.removeAllListeners channel))))
(js/window.apis.addListener channel listener)))
(defn register-plugin
[pl]
(swap! state/state update-in [:plugin/installed-plugins] assoc (keyword (:id pl)) pl))
(defn unregister-plugin
[id]
(js/LSPluginCore.unregister id))
(defn host-mounted!
[]
(and lsp-enabled? (js/LSPluginCore.hostMounted)))
(and config/lsp-enabled? (js/LSPluginCore.hostMounted)))
(defn register-plugin-slash-command
[pid [cmd actions]]
@ -469,7 +439,7 @@
(defn hook-plugin
[tag type payload plugin-id]
(when lsp-enabled?
(when config/lsp-enabled?
(try
(js-invoke js/LSPluginCore
(str "hook" (string/capitalize (name tag)))
@ -706,6 +676,6 @@
(defn setup!
"setup plugin core handler"
[callback]
(if (not lsp-enabled?)
(if (not config/lsp-enabled?)
(callback)
(init-plugins! callback)))

View File

@ -1,6 +1,7 @@
(ns frontend.handler.plugin-config
"This ns is a system component that encapsulate the global plugin.edn.
This component depends on TODO"
"This system component encapsulates the global plugin.edn and depends on the
global-config component. This component is only enabled? if both the
global-config and plugin components are enabled"
(:require [frontend.handler.global-config :as global-config-handler]
["path" :as path]
[promesa.core :as p]
@ -8,24 +9,26 @@ This component depends on TODO"
[frontend.fs :as fs]
[frontend.state :as state]
[frontend.handler.notification :as notification]
[electron.ipc :as ipc]
[frontend.handler.common.plugin :as plugin-common-handler]
[clojure.edn :as edn]
[clojure.set :as set]
[clojure.pprint :as pprint]
[malli.core :as m]
[malli.error :as me]
[frontend.schema.handler.plugin-config :as plugin-config-schema]
[cljs-bean.core :as bean]
[lambdaisland.glogi :as log]))
(defn- plugin-config-path
(defn plugin-config-path
[]
(path/join @global-config-handler/root-dir "plugins.edn"))
(path/join (global-config-handler/global-config-dir) "plugins.edn"))
(def common-plugin-keys
"Vec of plugin keys to store in plugins.edn and to compare with installed-plugins state"
(->> plugin-config-schema/Plugin rest (mapv first)))
(defn add-or-update-plugin
"Adds or updates a plugin from plugin.edn"
[{:keys [id] :as plugin}]
(p/let [content (fs/read-file "" (plugin-config-path))
updated-content (-> content
@ -37,6 +40,7 @@ This component depends on TODO"
(fs/write-file! nil "" (plugin-config-path) updated-content {:skip-compare? true})))
(defn remove-plugin
"Removes a plugin from plugin.edn"
[plugin-id]
(p/let [content (fs/read-file "" (plugin-config-path))
updated-content (-> content rewrite/parse-string (rewrite/dissoc (keyword plugin-id)) str)]
@ -54,13 +58,18 @@ This component depends on TODO"
"Given installed plugins state and plugins from plugins.edn,
returns map of plugins to install and uninstall"
[installed-plugins edn-plugins]
;; :name is removed from comparison because it isn't used for reproducible builds
;; and is just for display purposes
(let [installed-plugins-set (->> installed-plugins
vals
(map #(assoc (select-keys % common-plugin-keys)
:id (keyword (:id %))))
(map #(-> (select-keys % common-plugin-keys)
(assoc :id (keyword (:id %)))
(dissoc :name)))
set)
edn-plugins-set (->> edn-plugins
(map (fn [[k v]] (assoc v :id k)))
(map (fn [[k v]] (-> v
(assoc :id k)
(dissoc :name))))
set)]
(if (= installed-plugins-set edn-plugins-set)
{}
@ -89,34 +98,36 @@ returns map of plugins to install and uninstall"
:error)
(log/error :unexpected-error e)))))
;; TODO: Extract from handler.plugin
(defn installed?
[id]
(and (contains? (:plugin/installed-plugins @state/state) (keyword id))
(get-in @state/state [:plugin/installed-plugins (keyword id) :iir])))
(defn install-marketplace-plugin
[{:keys [id] :as mft}]
; (prn :IN {:k1 (:plugin/installing @state/state)
; :k2 (installed? id)})
;; TODO:
(when-not (and (:plugin/installing @state/state)
(installed? id))
(p/create
(fn [resolve]
(state/set-state! :plugin/installing mft)
(ipc/ipc :installMarketPlugin mft)
(resolve id)))))
(defn update-plugins
(defn replace-plugins
"Replaces current plugins given plugins to install and uninstall"
[plugins]
(log/info :uninstall-plugins (:uninstall plugins))
(doseq [plugin (:uninstall plugins)]
(js/LSPluginCore.unregister (name (:id plugin))))
(plugin-common-handler/unregister-plugin (name (:id plugin))))
(log/info :install-plugins (:install plugins))
(doseq [plugin (:install plugins)]
(install-marketplace-plugin plugin)))
(plugin-common-handler/install-marketplace-plugin plugin)))
(defn setup-install-listener!
"Sets up a listener for the lsp-installed event to update plugins.edn"
[]
(let [listener (fn listener [_ e]
(when-let [{:keys [status payload only-check]} (bean/->clj e)]
(when (and (= status "completed") (not only-check))
(let [{:keys [name title theme]} payload
;; Same defaults as plugin/setup-install-listener!
name (or title name "Untitled")]
(add-or-update-plugin
(assoc payload
:version (:installed-version payload)
;; Manual install doesn't have theme field but
;; plugin.edn requires this field
:theme (if (some? theme) theme false)
:name name))))))]
(js/window.apis.addListener "lsp-installed" listener)))
(defn start
"This component has just one reponsibility on start, to create a plugins.edn
if none exists"
[]
(create-plugin-config-file-if-not-exists))

View File

@ -14,12 +14,13 @@
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.export :as export-handler]
[frontend.handler.whiteboard :as whiteboard-handler]
[frontend.handler.plugin-config :as plugin-config]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.modules.shortcut.dicts :as dicts]
[frontend.modules.shortcut.before :as m]
[frontend.state :as state]
[frontend.util :refer [mac?] :as util]
[frontend.commands :as commands]
[frontend.config :as config]
[electron.ipc :as ipc]
[promesa.core :as p]
[clojure.data :as data]
@ -406,13 +407,13 @@
:fn plugin-handler/show-themes-modal!}
:ui/goto-plugins {:binding "t p"
:inactive (not plugin-handler/lsp-enabled?)
:inactive (not config/lsp-enabled?)
:fn plugin-handler/goto-plugins-dashboard!}
:ui/install-plugins-from-file {:binding false
:inactive (not plugin-handler/lsp-enabled?)
:inactive (not (config/plugin-config-enabled?))
;; TODO: Remove dev convenience
:fn (fn [] (plugin-config/open-sync-modal))}
:fn (fn [] (plugin-config-handler/open-sync-modal))}
:editor/toggle-open-blocks {:binding "t o"
:fn editor-handler/toggle-open!}

View File

@ -12,6 +12,7 @@
[datascript.core :as d]
[electron.ipc :as ipc]
[frontend.components.svg :as svg]
[frontend.config :as config]
[frontend.context.i18n :refer [t]]
[frontend.db-mixins :as db-mixins]
[frontend.handler.notification :as notification]
@ -32,7 +33,6 @@
[goog.object :as gobj]
[lambdaisland.glogi :as log]
[medley.core :as medley]
[frontend.config :as config]
[promesa.core :as p]
[rum.core :as rum]))
@ -361,7 +361,7 @@
style)))
(defn apply-custom-theme-effect! [theme]
(when plugin-handler/lsp-enabled?
(when config/lsp-enabled?
(when-let [custom-theme (state/sub [:ui/custom-theme (keyword theme)])]
(when-let [url (:url custom-theme)]
(js/LSPluginCore.selectTheme (bean/->js custom-theme)
@ -939,7 +939,7 @@
(when (:class opts)
(str " " (string/trim (:class opts)))))
(if extension? "tie tie" "ti ti"))}
(dissoc opts :class :extension?))]
(dissoc opts :class :extension? :font?))]
;; tabler svg react
(when-let [klass (gobj/get js/tablerIcons (str "Icon" (csk/->PascalCase class)))]

View File

@ -21,6 +21,7 @@
[frontend.handler.notification :as notification]
[frontend.handler.page :as page-handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.common.plugin :as plugin-common-handler]
[frontend.modules.outliner.core :as outliner]
[frontend.modules.outliner.tree :as outliner-tree]
[frontend.handler.command-palette :as palette-handler]
@ -776,7 +777,7 @@
(when-let [{:keys [repo id] :as mft} (bean/->clj manifest)]
(if-not (and repo id)
(throw (js/Error. "[required] :repo :id"))
(plugin-handler/install-marketplace-plugin mft)))))
(plugin-common-handler/install-marketplace-plugin mft)))))
;; db
(defn ^:export q

View File

@ -2,7 +2,7 @@
(:require [clojure.test :refer [is use-fixtures testing deftest]]
[frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]]
[frontend.test.fixtures :as fixtures]
[frontend.handler.plugin-config :as plugin-config]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.global-config :as global-config-handler]
[frontend.schema.handler.plugin-config :as plugin-config-schema]
["fs" :as fs-node]
@ -15,88 +15,81 @@
(use-fixtures :once fixtures/redef-get-fs)
(defn- create-global-config-dir
[]
(let [dir (test-helper/create-tmp-dir "config")
root-dir (path/dirname dir)]
(reset! global-config-handler/root-dir root-dir)
dir))
(defn- delete-global-config-dir
[config-dir]
(doseq [relative-file (fs-node/readdirSync config-dir)]
(fs-node/unlinkSync (path/join config-dir relative-file)))
(reset! global-config-handler/root-dir nil)
(fs-node/rmdirSync config-dir)
(fs-node/rmdirSync (path/dirname config-dir)))
(deftest-async add-or-update-plugin
(let [dir (test-helper/create-tmp-dir)
plugins-file (path/join dir "plugins.edn")
(let [dir (create-global-config-dir)
plugin-to-add {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
body (pr-str (mg/generate plugin-config-schema/Plugins-edn {:size 10}))]
(fs-node/writeFileSync plugins-file body)
(reset! global-config-handler/root-dir dir)
(fs-node/writeFileSync (plugin-config-handler/plugin-config-path) body)
(->
(p/do!
(plugin-config/add-or-update-plugin plugin-to-add)
(plugin-config-handler/add-or-update-plugin plugin-to-add)
(is (= (dissoc plugin-to-add :id)
(:foo (edn/read-string (str (fs-node/readFileSync plugins-file)))))))
(:foo (edn/read-string (str (fs-node/readFileSync (plugin-config-handler/plugin-config-path))))))))
(.finally
(fn []
(reset! global-config-handler/root-dir nil)
(fs-node/unlinkSync plugins-file)
(fs-node/rmdirSync dir))))))
(p/finally #(delete-global-config-dir dir)))))
(deftest-async remove-plugin
(let [dir (test-helper/create-tmp-dir)
plugins-file (path/join dir "plugins.edn")
(let [dir (create-global-config-dir)
;; use seed to consistently generate 5 plugins
;; if we want more randomness we could look into gen/such-that
plugins (mg/generate plugin-config-schema/Plugins-edn {:size 5 :seed 1})
some-plugin-id (first (keys plugins))]
(fs-node/writeFileSync plugins-file (pr-str plugins))
(reset! global-config-handler/root-dir dir)
(fs-node/writeFileSync (plugin-config-handler/plugin-config-path) (pr-str plugins))
(->
(p/do!
(plugin-config/remove-plugin some-plugin-id)
(plugin-config-handler/remove-plugin some-plugin-id)
(is (= nil
(get (edn/read-string (str (fs-node/readFileSync plugins-file)))
(get (edn/read-string (str (fs-node/readFileSync (plugin-config-handler/plugin-config-path))))
some-plugin-id))))
(.finally
(fn []
(reset! global-config-handler/root-dir nil)
(fs-node/unlinkSync plugins-file)
(fs-node/rmdirSync dir))))))
(p/finally #(delete-global-config-dir dir)))))
(deftest-async open-sync-modal-malformed-edn
(let [dir (test-helper/create-tmp-dir)
plugins-file (path/join dir "plugins.edn")
(let [dir (create-global-config-dir)
error-message (atom nil)]
(fs-node/writeFileSync plugins-file "{:id {}")
(reset! global-config-handler/root-dir dir)
(fs-node/writeFileSync (plugin-config-handler/plugin-config-path) "{:id {}")
(test-helper/with-reset reset
[notification/show! (fn [msg _] (reset! error-message msg))]
(->
(p/do!
(plugin-config/open-sync-modal)
(plugin-config-handler/open-sync-modal)
(is (string/starts-with? @error-message "Malformed plugins.edn")
"User sees correct notification"))
(p/finally (fn []
(reset)
(reset! global-config-handler/root-dir nil)
(fs-node/unlinkSync plugins-file)
(fs-node/rmdirSync dir)))))))
(p/finally #(delete-global-config-dir dir))))))
(deftest-async open-sync-modal-invalid-edn
(let [dir (test-helper/create-tmp-dir)
plugins-file (path/join dir "plugins.edn")
(let [dir (create-global-config-dir)
error-message (atom nil)]
;; Missing a couple plugin keys
(fs-node/writeFileSync plugins-file (pr-str {:id {:theme true :repo "user/repo"}}))
(reset! global-config-handler/root-dir dir)
(fs-node/writeFileSync (plugin-config-handler/plugin-config-path)
(pr-str {:id {:theme true :repo "user/repo"}}))
(test-helper/with-reset reset
[notification/show! (fn [msg _] (reset! error-message msg))]
(->
(p/do!
(plugin-config/open-sync-modal)
(plugin-config-handler/open-sync-modal)
(is (string/starts-with? @error-message "Invalid plugins.edn")
"User sees correct notification"))
(p/finally (fn []
(reset)
(fs-node/unlinkSync plugins-file)
(fs-node/rmdirSync dir)))))))
(p/finally #(delete-global-config-dir dir))))))
(defn- installed-plugins->edn-plugins
"Converts installed plugins state to edn.plugins format"
@ -107,26 +100,26 @@
;; install and uninstall
(deftest determine-plugins-to-change
(testing "no changes to make"
(let [plugins {:foo {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
:bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}]
(is (= {} (#'plugin-config/determine-plugins-to-change
(let [plugins {:foo {:id :foo :repo "some-user/foo" :version "v0.9.0"}
:bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}]
(is (= {} (#'plugin-config-handler/determine-plugins-to-change
plugins
(installed-plugins->edn-plugins plugins))))))
(testing "differing versions are uninstalled and installed"
(let [plugins {:bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}]
(let [plugins {:bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}]
(is (= {:uninstall [(:bar plugins)]
:install [(assoc (:bar plugins) :version "v1.0.0" :plugin-action "install")]}
(#'plugin-config/determine-plugins-to-change
(#'plugin-config-handler/determine-plugins-to-change
plugins
(installed-plugins->edn-plugins (assoc-in plugins [:bar :version] "v1.0.0")))))))
(testing "replaced plugins are uninstalled and new plugins are installed"
(let [plugins {:foo {:id :foo :name "Foo" :repo "some-user/foo" :version "v0.9.0"}
:bar {:id :bar :name "Bar" :repo "some-user/bar" :version "v0.1.0"}}
new-plugin {:id :baz :name "Baz" :repo "some-user/baz" :version "v0.5.0"}]
(let [plugins {:foo {:id :foo :repo "some-user/foo" :version "v0.9.0"}
:bar {:id :bar :repo "some-user/bar" :version "v0.1.0"}}
new-plugin {:id :baz :repo "some-user/baz" :version "v0.5.0"}]
(is (= {:uninstall [(:foo plugins)]
:install [(assoc new-plugin :plugin-action "install")]}
(#'plugin-config/determine-plugins-to-change
(#'plugin-config-handler/determine-plugins-to-change
plugins
(-> plugins (dissoc :foo) (assoc :baz new-plugin) installed-plugins->edn-plugins)))))))

View File

@ -121,8 +121,9 @@
;; only test file name parsing, don't consider title prop overriding
rename-target (:target (#'conversion-handler/calc-rename-target-impl :legacy :triple-lowbar original-body nil))]
(if rename-target
(do (prn "conversion triple-lowbar: " original-body " -> " rename-target)
(#'page-handler/compute-new-file-path path rename-target))
#_:clj-kondo/ignore
(do #_(prn "conversion triple-lowbar: " original-body " -> " rename-target)
(#'page-handler/compute-new-file-path path rename-target))
path)))
(defn- convert-graph-files-path

View File

@ -16,6 +16,8 @@
(conn/destroy-all!))
(defn load-test-files
"Given a collection of file maps, loads them into the current test-db.
This can be called in synchronous contexts as no async fns should be invoked"
[files]
(repo-handler/parse-files-and-load-to-db!
test-db
@ -24,6 +26,14 @@
{:re-render? false :verbose false :refresh? true}))
(defn create-tmp-dir
[]
(when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
(fs-node/mkdtempSync (path/join "tmp" "unit-test-")))
"Creates a temporary directory under tmp/. If a subdir is given, creates an
additional subdirectory under the newly created temp directory."
([] (create-tmp-dir nil))
([subdir]
(when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
(let [dir (fs-node/mkdtempSync (path/join "tmp" "unit-test-"))]
(if subdir
(do
(fs-node/mkdirSync (path/join dir subdir))
(path/join dir subdir))
dir))))