mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 14:14:55 +00:00
chore: remove nfs support
Assets will be stored in IndexedDB through memory fs on web.
This commit is contained in:
@@ -467,11 +467,9 @@
|
||||
[state config title href metadata full_text]
|
||||
(let [src (::src state)
|
||||
repo (state/get-current-repo)
|
||||
granted? (state/sub [:nfs/user-granted? repo])
|
||||
href (config/get-local-asset-absolute-path href)
|
||||
db-based? (config/db-based-graph? repo)]
|
||||
(when (and (or db-based?
|
||||
granted?
|
||||
(util/electron?)
|
||||
(mobile-util/native-platform?))
|
||||
(nil? @src))
|
||||
|
||||
@@ -262,17 +262,17 @@
|
||||
:shortcut :go/home})
|
||||
|
||||
(when enable-journals?
|
||||
(sidebar-item
|
||||
{:class "journals-nav"
|
||||
:active (and (not srs-open?)
|
||||
(or (= route-name :all-journals) (= route-name :home)))
|
||||
:title (t :left-side-bar/journals)
|
||||
:on-click-handler (fn [e]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(route-handler/sidebar-journals!)
|
||||
(route-handler/go-to-journals!)))
|
||||
:icon "calendar"
|
||||
:shortcut :go/journals}))))
|
||||
(sidebar-item
|
||||
{:class "journals-nav"
|
||||
:active (and (not srs-open?)
|
||||
(or (= route-name :all-journals) (= route-name :home)))
|
||||
:title (t :left-side-bar/journals)
|
||||
:on-click-handler (fn [e]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(route-handler/sidebar-journals!)
|
||||
(route-handler/go-to-journals!)))
|
||||
:icon "calendar"
|
||||
:shortcut :go/journals}))))
|
||||
|
||||
(for [nav checked-navs]
|
||||
(cond
|
||||
@@ -955,7 +955,6 @@
|
||||
(state/set-state! :editor/latest-shortcut nil)))))
|
||||
[state route-match main-content']
|
||||
(let [current-repo (state/sub :git/current-repo)
|
||||
granted? (state/sub [:nfs/user-granted? (state/get-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))
|
||||
@@ -992,7 +991,7 @@
|
||||
:route route-match
|
||||
:current-repo current-repo
|
||||
:edit? edit?
|
||||
:nfs-granted? granted?
|
||||
|
||||
:db-restoring? db-restoring?
|
||||
:sidebar-open? sidebar-open?
|
||||
:settings-open? settings-open?
|
||||
@@ -1067,7 +1066,6 @@
|
||||
(plugins/custom-js-installer
|
||||
{:t t
|
||||
:current-repo current-repo
|
||||
:nfs-granted? granted?
|
||||
:db-restoring? db-restoring?})
|
||||
(app-context-menu-observer)
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
[frontend.components.onboarding.quick-tour :as quick-tour]
|
||||
[frontend.components.page :as page]
|
||||
[frontend.config :as config]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.fs.sync :as fs-sync]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.file-sync :refer [*beta-unavailable?] :as file-sync-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.page :as page-handler]
|
||||
|
||||
@@ -586,13 +586,13 @@
|
||||
(when (and develop-mode? (util/electron?) (not market?))
|
||||
[:div
|
||||
(ui/tooltip
|
||||
(ui/button
|
||||
(t :plugin/load-unpacked)
|
||||
{:icon "upload"
|
||||
:intent "link"
|
||||
:class "load-unpacked"
|
||||
:on-click plugin-handler/load-unpacked-plugin})
|
||||
[:div (t :plugin/unpacked-tips)])
|
||||
(ui/button
|
||||
(t :plugin/load-unpacked)
|
||||
{:icon "upload"
|
||||
:intent "link"
|
||||
:class "load-unpacked"
|
||||
:on-click plugin-handler/load-unpacked-plugin})
|
||||
[:div (t :plugin/unpacked-tips)])
|
||||
|
||||
(when (util/electron?)
|
||||
(unpacked-plugin-loader selected-unpacked-pkg))])]
|
||||
@@ -1524,13 +1524,13 @@
|
||||
(bean/->clj (.-settingsSchema pl)) pl)))]]]]))
|
||||
|
||||
(rum/defc custom-js-installer
|
||||
[{:keys [t current-repo db-restoring? nfs-granted?]}]
|
||||
[{:keys [t current-repo db-restoring?]}]
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(when (and (not db-restoring?)
|
||||
(or (not util/nfs?) nfs-granted?))
|
||||
(not util/nfs?))
|
||||
(ui-handler/exec-js-if-exists-&-allowed! t)))
|
||||
[current-repo db-restoring? nfs-granted?])
|
||||
[current-repo db-restoring?])
|
||||
nil)
|
||||
|
||||
(rum/defc perf-tip-content
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[frontend.db :as db]
|
||||
[frontend.handler.db-based.rtc :as rtc-handler]
|
||||
[frontend.handler.db-based.rtc-flows :as rtc-flows]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.file-sync :as file-sync]
|
||||
[frontend.handler.graph :as graph]
|
||||
[frontend.handler.notification :as notification]
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
(defonce *once-theme-loaded? (volatile! false))
|
||||
|
||||
(rum/defc ^:large-vars/cleanup-todo container < rum/static
|
||||
[{:keys [route theme accent-color editor-font on-click current-repo nfs-granted? db-restoring?
|
||||
[{:keys [route theme accent-color editor-font on-click current-repo db-restoring?
|
||||
settings-open? sidebar-open? system-theme? sidebar-blocks-len onboarding-state preferred-language]} child]
|
||||
(let [mounted-fn (use-mounted)
|
||||
[restored-sidebar? set-restored-sidebar?] (rum/use-state false)]
|
||||
@@ -103,9 +103,9 @@
|
||||
#(let [db-restored? (false? db-restoring?)]
|
||||
(if db-restoring?
|
||||
(util/set-title! (t :loading))
|
||||
(when (or nfs-granted? db-restored?)
|
||||
(when db-restored?
|
||||
(route-handler/update-page-title! route))))
|
||||
[nfs-granted? db-restoring? route])
|
||||
[db-restoring? route])
|
||||
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
(ns frontend.extensions.excalidraw
|
||||
(:require [clojure.string :as string]
|
||||
;; NOTE: Always use production build of excalidraw
|
||||
(:require ;; NOTE: Always use production build of excalidraw
|
||||
;; See-also: https://github.com/excalidraw/excalidraw/pull/3330
|
||||
["@excalidraw/excalidraw/dist/excalidraw.production.min" :refer [Excalidraw serializeAsJSON]]
|
||||
[frontend.config :as config]
|
||||
[frontend.db :as db]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.draw :as draw]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
[frontend.rum :as r]
|
||||
[frontend.state :as state]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.util :as util]
|
||||
[goog.object :as gobj]
|
||||
[goog.functions :refer [debounce]]
|
||||
[rum.core :as rum]
|
||||
[frontend.mobile.util :as mobile-util]))
|
||||
["@excalidraw/excalidraw/dist/excalidraw.production.min" :refer [Excalidraw serializeAsJSON]]
|
||||
[clojure.string :as string]
|
||||
[frontend.config :as config]
|
||||
[frontend.db :as db]
|
||||
[frontend.handler.draw :as draw]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.rum :as r]
|
||||
[frontend.state :as state]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.util :as util]
|
||||
[goog.functions :refer [debounce]]
|
||||
[goog.object :as gobj]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(def excalidraw (r/adapt-class Excalidraw))
|
||||
|
||||
@@ -99,8 +99,8 @@
|
||||
[:div.draw-wrap
|
||||
{:ref ref
|
||||
:on-pointer-down (fn [e]
|
||||
(util/stop e)
|
||||
(state/set-block-component-editing-mode! true))
|
||||
(util/stop e)
|
||||
(state/set-block-component-editing-mode! true))
|
||||
:on-blur #(state/set-block-component-editing-mode! false)
|
||||
:style {:width @*draw-width
|
||||
:height (if wide-mode? 650 500)}}
|
||||
@@ -162,11 +162,8 @@
|
||||
|
||||
(rum/defc draw < rum/reactive
|
||||
[option]
|
||||
(let [repo (state/get-current-repo)
|
||||
granted? (state/sub [:nfs/user-granted? repo])]
|
||||
;; Web granted
|
||||
(let [repo (state/get-current-repo)]
|
||||
(when-not (and (config/local-file-based-graph? repo)
|
||||
(not granted?)
|
||||
(not (util/electron?))
|
||||
(not (mobile-util/native-platform?)))
|
||||
(draw-container option))))
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[frontend.config :as config]
|
||||
[frontend.fs.capacitor-fs :as capacitor-fs]
|
||||
[frontend.fs.memory-fs :as memory-fs]
|
||||
[frontend.fs.nfs :as nfs]
|
||||
[frontend.fs.node :as node]
|
||||
[frontend.fs.protocol :as protocol]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
@@ -18,7 +17,6 @@
|
||||
[logseq.common.util :as common-util]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defonce nfs-backend (nfs/->Nfs))
|
||||
(defonce memory-backend (memory-fs/->MemoryFs))
|
||||
(defonce node-backend (node/->Node))
|
||||
(defonce mobile-backend (capacitor-fs/->Capacitorfs))
|
||||
@@ -31,10 +29,7 @@
|
||||
node-backend
|
||||
|
||||
(mobile-util/native-platform?)
|
||||
mobile-backend
|
||||
|
||||
:else
|
||||
nfs-backend))
|
||||
mobile-backend))
|
||||
|
||||
(defn get-fs
|
||||
[dir & {:keys [repo rpath]}]
|
||||
@@ -62,11 +57,8 @@
|
||||
(and (util/electron?) (not bfs-local?))
|
||||
node-backend
|
||||
|
||||
(mobile-util/native-platform?)
|
||||
mobile-backend
|
||||
|
||||
:else
|
||||
nfs-backend)))
|
||||
mobile-backend)))
|
||||
|
||||
(defn mkdir!
|
||||
[dir]
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
(ns frontend.fs.nfs
|
||||
"Browser File System API based fs implementation.
|
||||
|
||||
Rationale:
|
||||
- nfs-file-handles-cache stores all file & directory handle
|
||||
- idb stores top-level directory handle
|
||||
- readdir/get-files is called by re-index and initial watcher to init all handles"
|
||||
(:require [frontend.fs.protocol :as protocol]
|
||||
[frontend.util :as util]
|
||||
[clojure.string :as string]
|
||||
[frontend.idb :as idb]
|
||||
[promesa.core :as p]
|
||||
[lambdaisland.glogi :as log]
|
||||
[goog.object :as gobj]
|
||||
[frontend.db :as db]
|
||||
[frontend.config :as config]
|
||||
[frontend.state :as state]
|
||||
[frontend.handler.notification :as notification]
|
||||
["/frontend/utils" :as utils]
|
||||
[logseq.common.util :as common-util]
|
||||
[logseq.common.path :as path]))
|
||||
|
||||
;; Cache the file handles in the memory so that
|
||||
;; the browser will not keep asking permissions.
|
||||
(defonce nfs-file-handles-cache (atom {}))
|
||||
|
||||
(defn- get-nfs-file-handle
|
||||
[handle-path]
|
||||
(get @nfs-file-handles-cache handle-path))
|
||||
|
||||
(defn add-nfs-file-handle!
|
||||
[handle-path handle]
|
||||
(prn ::DEBUG "add-nfs-file-handle!" handle-path)
|
||||
(swap! nfs-file-handles-cache assoc handle-path handle))
|
||||
|
||||
(defn remove-nfs-file-handle!
|
||||
[handle-path]
|
||||
(swap! nfs-file-handles-cache dissoc handle-path))
|
||||
|
||||
(defn- nfs-saved-handler
|
||||
[repo path file]
|
||||
(when-let [last-modified (gobj/get file "lastModified")]
|
||||
;; TODO: extract
|
||||
(let [path (if (= \/ (first path))
|
||||
(subs path 1)
|
||||
path)]
|
||||
;; Bad code
|
||||
(db/set-file-last-modified-at! repo path last-modified))))
|
||||
|
||||
(defn- verify-handle-permission
|
||||
[handle read-write?]
|
||||
(utils/verifyPermission handle read-write?))
|
||||
|
||||
(defn verify-permission
|
||||
[repo read-write?]
|
||||
(let [repo (or repo (state/get-current-repo))
|
||||
repo-dir (config/get-repo-dir repo)
|
||||
handle-path (str "handle/" repo-dir)
|
||||
handle (get-nfs-file-handle handle-path)]
|
||||
(p/then
|
||||
(utils/verifyPermission handle read-write?)
|
||||
(fn []
|
||||
(state/set-state! [:nfs/user-granted? repo] true)
|
||||
true))))
|
||||
|
||||
(defn check-directory-permission!
|
||||
[repo]
|
||||
(when (config/local-file-based-graph? repo)
|
||||
(p/let [repo-dir (config/get-repo-dir repo)
|
||||
handle-path (str "handle/" repo-dir)
|
||||
handle (idb/get-item handle-path)]
|
||||
(when handle
|
||||
(add-nfs-file-handle! handle-path handle)
|
||||
(verify-permission repo true)))))
|
||||
|
||||
(defn- contents-matched?
|
||||
[disk-content db-content]
|
||||
(when (and (string? disk-content) (string? db-content))
|
||||
(= (string/trim disk-content) (string/trim db-content))))
|
||||
|
||||
(defn- await-permission-granted
|
||||
"Guard against File System Access API permission, avoiding early access before granted"
|
||||
[repo]
|
||||
(if (state/nfs-user-granted? repo)
|
||||
(p/resolved true)
|
||||
(js/Promise. (fn [resolve reject]
|
||||
(let [timer (atom nil)
|
||||
timer' (js/setInterval (fn []
|
||||
(when (state/nfs-user-granted? repo)
|
||||
(js/clearInterval @timer)
|
||||
(resolve true)))
|
||||
1000)
|
||||
_ (reset! timer timer')]
|
||||
(js/setTimeout (fn []
|
||||
(js/clearInterval timer)
|
||||
(reject false))
|
||||
100000))))))
|
||||
|
||||
(defn await-get-nfs-file-handle
|
||||
"for accessing File handle outside, ensuring user granted."
|
||||
[repo handle-path]
|
||||
(p/let [_ (await-permission-granted repo)]
|
||||
(get-nfs-file-handle handle-path)))
|
||||
|
||||
(defn- readdir-and-reload-all-handles
|
||||
"Return list of filenames"
|
||||
[root-dir root-handle]
|
||||
(p/let [files (utils/getFiles root-handle
|
||||
true
|
||||
(fn [path entry]
|
||||
(let [handle-path (str "handle/" path)]
|
||||
;; Same for all handles here, even for directories and ignored directories(for backing up)
|
||||
;; FileSystemDirectoryHandle or FileSystemFileHandle
|
||||
(when-not (string/includes? path "/.")
|
||||
(add-nfs-file-handle! handle-path entry)))))]
|
||||
(->> files
|
||||
(remove (fn [file]
|
||||
(let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
|
||||
ext (util/get-file-ext rpath)]
|
||||
(or (string/blank? rpath)
|
||||
(string/starts-with? rpath ".")
|
||||
(string/starts-with? rpath "logseq/bak")
|
||||
; (string/starts-with? rpath "logseq/version-files")
|
||||
(not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
|
||||
(map (fn [file]
|
||||
(-> (.-webkitRelativePath file)
|
||||
common-util/path-normalize))))))
|
||||
|
||||
|
||||
(defn- get-files-and-reload-all-handles
|
||||
"Return list of file objects"
|
||||
[root-dir root-handle]
|
||||
(p/let [files (utils/getFiles root-handle
|
||||
true
|
||||
(fn [path entry]
|
||||
(let [handle-path (str "handle/" path)]
|
||||
;; Same for all handles here, even for directories and ignored directories(for backing up)
|
||||
;; FileSystemDirectoryHandle or FileSystemFileHandle
|
||||
(when-not (string/includes? path "/.")
|
||||
(add-nfs-file-handle! handle-path entry)))))]
|
||||
(p/all (->> files
|
||||
(remove (fn [file]
|
||||
(let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
|
||||
ext (util/get-file-ext rpath)]
|
||||
(or (string/blank? rpath)
|
||||
(string/starts-with? rpath ".")
|
||||
(string/starts-with? rpath "logseq/bak")
|
||||
(string/starts-with? rpath "logseq/version-files")
|
||||
(not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
|
||||
;; Read out using .text, Promise<string>
|
||||
(map (fn [file]
|
||||
(p/let [content (.text file)]
|
||||
{:name (.-name file)
|
||||
:path (-> (.-webkitRelativePath file)
|
||||
common-util/path-normalize)
|
||||
:mtime (.-lastModified file)
|
||||
:size (.-size file)
|
||||
:type (.-kind (.-handle file))
|
||||
:content content
|
||||
:file/file file})))))))
|
||||
|
||||
(defrecord ^:large-vars/cleanup-todo Nfs []
|
||||
protocol/Fs
|
||||
(mkdir! [_this dir]
|
||||
(let [dir (path/path-normalize dir)
|
||||
parent-dir (path/parent dir)
|
||||
|
||||
parent-handle-path (str "handle/" parent-dir)]
|
||||
(-> (p/let [parent-handle (or (get-nfs-file-handle parent-handle-path)
|
||||
(idb/get-item parent-handle-path))
|
||||
_ (when parent-handle (verify-handle-permission parent-handle true))]
|
||||
(when parent-handle
|
||||
(p/let [new-dir-name (path/filename dir)
|
||||
new-handle (.getDirectoryHandle ^js parent-handle new-dir-name
|
||||
#js {:create true})
|
||||
handle-path (str "handle/" dir)
|
||||
_ (idb/set-item! handle-path new-handle)]
|
||||
(add-nfs-file-handle! handle-path new-handle)
|
||||
(println "dir created: " dir))))
|
||||
(p/catch (fn [error]
|
||||
(js/console.debug "mkdir error: " error ", dir: " dir)
|
||||
(throw error))))))
|
||||
|
||||
(mkdir-recur! [this dir]
|
||||
(protocol/mkdir! this dir))
|
||||
|
||||
(readdir [_this dir]
|
||||
;; This method is only used for repo-dir and version-files dir
|
||||
;; There's no Logseq Sync support for nfs. So assume dir is always a repo dir.
|
||||
(p/let [repo-url (str "logseq_local_" dir)
|
||||
_ (await-permission-granted repo-url)
|
||||
handle-path (str "handle/" dir)
|
||||
handle (or (get-nfs-file-handle handle-path)
|
||||
(idb/get-item handle-path))
|
||||
_ (when handle
|
||||
(verify-handle-permission handle true))
|
||||
fpaths (if (string/includes? dir "/")
|
||||
(js/console.error "ERROR: unimpl")
|
||||
(readdir-and-reload-all-handles dir handle))]
|
||||
fpaths))
|
||||
|
||||
(unlink! [this repo fpath _opts]
|
||||
(let [repo-dir (config/get-repo-dir repo)
|
||||
filename (path/filename fpath)
|
||||
handle-path (str "handle/" fpath)
|
||||
recycle-dir (path/path-join repo-dir config/app-name config/recycle-dir)]
|
||||
(->
|
||||
(p/let [_ (protocol/mkdir! this recycle-dir)
|
||||
handle (get-nfs-file-handle handle-path)
|
||||
file (.getFile handle)
|
||||
content (.text file)
|
||||
|
||||
bak-handle (get-nfs-file-handle (str "handle/" recycle-dir))
|
||||
bak-filename (-> (path/relative-path repo-dir fpath)
|
||||
(string/replace "/" "_")
|
||||
(string/replace "\\" "_"))
|
||||
file-handle (.getFileHandle ^js bak-handle bak-filename #js {:create true})
|
||||
_ (utils/writeFile file-handle content)
|
||||
|
||||
parent-dir (path/parent fpath)
|
||||
parent-handle (get-nfs-file-handle (str "handle/" parent-dir))
|
||||
_ (when parent-handle
|
||||
(.removeEntry ^js parent-handle filename))]
|
||||
(idb/remove-item! handle-path)
|
||||
(remove-nfs-file-handle! handle-path))
|
||||
(p/catch (fn [error]
|
||||
(log/error :unlink/path {:path fpath
|
||||
:error error}))))))
|
||||
|
||||
(rmdir! [_this _dir]
|
||||
nil)
|
||||
|
||||
(read-file [_this dir path _options]
|
||||
(p/let [fpath (path/path-join dir path)
|
||||
handle-path (str "handle/" fpath)]
|
||||
(p/let [handle (or (get-nfs-file-handle handle-path)
|
||||
(idb/get-item handle-path))
|
||||
local-file (and handle (.getFile handle))]
|
||||
(and local-file (.text local-file)))))
|
||||
|
||||
(write-file! [_this repo dir path content opts]
|
||||
;; TODO: file backup handling
|
||||
(let [fpath (path/path-join dir path)
|
||||
ext (util/get-file-ext path)
|
||||
file-handle-path (str "handle/" fpath)]
|
||||
(p/let [file-handle (get-nfs-file-handle file-handle-path)]
|
||||
(if file-handle
|
||||
;; file exist
|
||||
(p/let [local-file (.getFile file-handle)
|
||||
disk-content (.text local-file)
|
||||
db-content (db/get-file repo path)
|
||||
contents-matched?' (contents-matched? disk-content db-content)]
|
||||
(if (and
|
||||
(not (string/blank? db-content))
|
||||
(not (:skip-compare? opts))
|
||||
(not contents-matched?')
|
||||
(not (contains? #{"excalidraw" "edn" "css"} ext))
|
||||
(not (string/includes? path "/.recycle/")))
|
||||
(state/pub-event! [:file/not-matched-from-disk path disk-content content])
|
||||
(p/let [_ (verify-permission repo true)
|
||||
_ (utils/writeFile file-handle content)
|
||||
file (.getFile file-handle)]
|
||||
(when file
|
||||
(db/set-file-content! repo path content)
|
||||
(nfs-saved-handler repo path file)))))
|
||||
;; file no-exist, write via parent dir handle
|
||||
(p/let [basename (path/filename fpath)
|
||||
parent-dir (path/parent fpath)
|
||||
parent-dir-handle-path (str "handle/" parent-dir)
|
||||
parent-dir-handle (get-nfs-file-handle parent-dir-handle-path)]
|
||||
|
||||
(if parent-dir-handle
|
||||
;; create from directory handle
|
||||
(p/let [file-handle (.getFileHandle ^js parent-dir-handle basename #js {:create true})
|
||||
_ (add-nfs-file-handle! file-handle-path file-handle)
|
||||
file (.getFile file-handle)
|
||||
text (.text file)]
|
||||
(if (string/blank? text)
|
||||
(p/let [;; _ (idb/set-item! file-handle-path file-handle)
|
||||
_ (utils/writeFile file-handle content)
|
||||
file (.getFile file-handle)]
|
||||
(when file
|
||||
(nfs-saved-handler repo path file)))
|
||||
(do
|
||||
(notification/show! (str "The file " path " already exists, please append the content if you need it.\n Unsaved content: \n" content)
|
||||
:warning
|
||||
false)
|
||||
(state/pub-event! [:file/alter repo path text]))))
|
||||
|
||||
;; TODO(andelf): Create parent directory and write
|
||||
;; Normally directory are created layer by layer. So it's safe to leave this unimplemented.
|
||||
(js/console.error "TODO: can not create directory hierarchy")))))))
|
||||
|
||||
(rename! [this repo old-path new-path]
|
||||
(p/let [repo-dir (config/get-repo-dir repo)
|
||||
old-rpath (path/relative-path repo-dir old-path)
|
||||
new-rpath (path/relative-path repo-dir new-path)
|
||||
old-content (protocol/read-file this repo-dir old-rpath nil)
|
||||
_ (protocol/write-file! this repo repo-dir new-rpath old-content nil)
|
||||
_ (protocol/unlink! this repo old-path nil)]))
|
||||
|
||||
(stat [_this fpath]
|
||||
(if-let [handle (get-nfs-file-handle (str "handle/" fpath))]
|
||||
(p/let [_ (verify-handle-permission handle true)
|
||||
file (.getFile handle)]
|
||||
(let [get-attr #(gobj/get file %)]
|
||||
{:last-modified-at (get-attr "lastModified")
|
||||
:size (get-attr "size")
|
||||
:path fpath
|
||||
:type (get-attr "type")}))
|
||||
(p/rejected "File not exists")))
|
||||
|
||||
(open-dir [_this _dir]
|
||||
(p/let [files (utils/openDirectory #js {:recursive true
|
||||
:mode "readwrite"}
|
||||
(fn [path entry]
|
||||
(let [handle-path (str "handle/" path)]
|
||||
;; Same all handles here, even for directories and ignored directories(for backing up)
|
||||
;; FileSystemDirectoryHandle or FileSystemFileHandle
|
||||
(when-not (string/includes? path "/.")
|
||||
(add-nfs-file-handle! handle-path entry)))))
|
||||
dir-handle (first files) ;; FileSystemDirectoryHandle
|
||||
dir-name (.-name dir-handle)
|
||||
files (->> (next files)
|
||||
(remove (fn [file]
|
||||
(let [rpath (.-webkitRelativePath file) ;
|
||||
; (string/replace-first (.-webkitRelativePath file) (str dir-name "/") "")
|
||||
ext (util/get-file-ext rpath)]
|
||||
(or (string/blank? rpath)
|
||||
(string/starts-with? rpath ".")
|
||||
(string/starts-with? rpath "logseq/bak")
|
||||
(string/starts-with? rpath "logseq/version-files")
|
||||
(not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
|
||||
;; Read out using .text, Promise<string>
|
||||
(map (fn [file]
|
||||
(js/console.log "handle" file)
|
||||
(p/let [content (.text file)]
|
||||
;; path content size mtime
|
||||
{:name (.-name file)
|
||||
:path (-> (.-webkitRelativePath file)
|
||||
common-util/path-normalize)
|
||||
:mtime (.-lastModified file)
|
||||
:size (.-size file)
|
||||
:type (.-kind (.-handle file))
|
||||
:content content
|
||||
;; expose the following, they are used by the file system
|
||||
:file/file file}))))
|
||||
files (p/all files)]
|
||||
(add-nfs-file-handle! (str "handle/" dir-name) dir-handle)
|
||||
(idb/set-item! (str "handle/" dir-name) dir-handle)
|
||||
{:path dir-name
|
||||
:files files}))
|
||||
|
||||
(get-files [_this dir]
|
||||
(when (string/includes? dir "/")
|
||||
(js/console.error "BUG: get-files(nfs) only accepts repo-dir"))
|
||||
(p/let [handle-path (str "handle/" dir)
|
||||
handle (get-nfs-file-handle handle-path)
|
||||
files (get-files-and-reload-all-handles dir handle)]
|
||||
files))
|
||||
|
||||
(watch-dir! [_this _dir _options]
|
||||
nil)
|
||||
|
||||
(unwatch-dir! [_this _dir]
|
||||
nil))
|
||||
@@ -92,8 +92,6 @@
|
||||
(fn []
|
||||
(js/console.log "db restored, setting up repo hooks")
|
||||
|
||||
(state/pub-event! [:modal/nfs-ask-permission])
|
||||
|
||||
(page-handler/init-commands!)
|
||||
|
||||
(watch-for-date!)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[frontend.common.thread-api :as thread-api :refer [def-thread-api]]
|
||||
[frontend.config :as config]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.fs.nfs :as nfs]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
@@ -187,21 +186,7 @@
|
||||
(config/db-based-graph? (state/get-current-repo)) ; memory fs
|
||||
(p/let [binary (fs/read-file repo-dir path {})
|
||||
blob (js/Blob. (array binary) (clj->js {:type "image"}))]
|
||||
(when blob (js/URL.createObjectURL blob)))
|
||||
|
||||
:else ;; nfs
|
||||
(let [handle-path (str "handle/" full-path)
|
||||
cached-url (get @*assets-url-cache (keyword handle-path))]
|
||||
(if cached-url
|
||||
(p/resolved cached-url)
|
||||
;; Loading File from handle cache
|
||||
;; Use await file handle, to ensure all handles are loaded.
|
||||
(p/let [handle (nfs/await-get-nfs-file-handle repo handle-path)
|
||||
file (and handle (.getFile handle))]
|
||||
(when file
|
||||
(p/let [url (js/URL.createObjectURL file)]
|
||||
(swap! *assets-url-cache assoc (keyword handle-path) url)
|
||||
url)))))))))
|
||||
(when blob (js/URL.createObjectURL blob)))))))
|
||||
|
||||
(defn- decode-digest
|
||||
[^js/Uint8Array digest]
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
[frontend.extensions.fsrs :as fsrs]
|
||||
[frontend.extensions.srs :as srs]
|
||||
[frontend.fs.capacitor-fs :as capacitor-fs]
|
||||
[frontend.fs.nfs :as nfs]
|
||||
[frontend.fs.sync :as sync]
|
||||
[frontend.handler.db-based.rtc :as rtc-handler]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.events :as events]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.file-sync :as file-sync-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.page :as page-handler]
|
||||
@@ -93,35 +92,12 @@
|
||||
(shui/dialog-open!
|
||||
(component-page/batch-delete-dialog selected-rows ok-handler)))
|
||||
|
||||
(defn ask-permission
|
||||
[repo]
|
||||
(when
|
||||
(and (not (util/electron?))
|
||||
(not (mobile-util/native-platform?)))
|
||||
(fn [{:keys [close]}]
|
||||
[:div
|
||||
;; TODO: fn translation with args
|
||||
[:p
|
||||
"Grant native filesystem permission for directory: "
|
||||
[:b (config/get-local-dir repo)]]
|
||||
(ui/button
|
||||
(t :settings-permission/start-granting)
|
||||
:class "ui__modal-enter"
|
||||
:on-click (fn []
|
||||
(nfs/check-directory-permission! repo)
|
||||
(close)))])))
|
||||
|
||||
(defn get-local-repo
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when (config/local-file-based-graph? repo)
|
||||
repo)))
|
||||
|
||||
(defmethod events/handle :modal/nfs-ask-permission []
|
||||
(when-let [repo (get-local-repo)]
|
||||
(some-> (ask-permission repo)
|
||||
(shui/dialog-open! {:align :top}))))
|
||||
|
||||
(defmethod events/handle :modal/show-cards [[_ cards-id]]
|
||||
(let [db-based? (config/db-based-graph? (state/get-current-repo))]
|
||||
(shui/dialog-open!
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.events :as events]
|
||||
[frontend.handler.file-based.file :as file-handler]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.file-sync :as file-sync-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.page :as page-handler]
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.fs.capacitor-fs :as capacitor-fs]
|
||||
[frontend.fs.nfs :as nfs]
|
||||
[frontend.handler.common.config-edn :as config-edn-common-handler]
|
||||
[frontend.handler.file-based.reset-file :as reset-file-handler]
|
||||
[frontend.handler.global-config :as global-config-handler]
|
||||
@@ -73,7 +72,7 @@
|
||||
:file/content content})]
|
||||
(ok-handler file-contents))))
|
||||
(p/catch (fn [error]
|
||||
(log/error :nfs/load-files-error repo-url)
|
||||
(log/error :fs/load-files-error repo-url)
|
||||
(log/error :exception error))))))
|
||||
|
||||
(defn backup-file!
|
||||
@@ -209,11 +208,8 @@
|
||||
(when path
|
||||
(let [path (common-util/path-normalize path)
|
||||
original-content (get file->content path)]
|
||||
(-> (p/let [_ (or
|
||||
(util/electron?)
|
||||
(nfs/check-directory-permission! repo))]
|
||||
(fs/write-plain-text-file! repo (config/get-repo-dir repo) path content
|
||||
{:old-content original-content}))
|
||||
(-> (fs/write-plain-text-file! repo (config/get-repo-dir repo) path content
|
||||
{:old-content original-content})
|
||||
(p/catch (fn [error]
|
||||
(state/pub-event! [:notification/show
|
||||
{:content (str "Failed to save the file " path ". Error: "
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
(ns frontend.handler.file-based.nfs
|
||||
"The File System Access API, https://web.dev/file-system-access/."
|
||||
(ns frontend.handler.file-based.native-fs
|
||||
"Native fs including Electron and mobile"
|
||||
(:require ["/frontend/utils" :as utils]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[frontend.config :as config]
|
||||
[frontend.db :as db]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.fs.nfs :as nfs]
|
||||
[frontend.handler.common :as common-handler]
|
||||
[frontend.handler.file-based.repo :as file-repo-handler]
|
||||
[frontend.handler.global-config :as global-config-handler]
|
||||
@@ -142,7 +141,7 @@
|
||||
(state/set-loading-files! repo false)
|
||||
(when ok-handler (ok-handler {:url repo})))))))
|
||||
(p/catch (fn [error]
|
||||
(log/error :nfs/load-files-error repo)
|
||||
(log/error :fs/load-files-error repo)
|
||||
(log/error :exception error)))))))
|
||||
(p/catch (fn [error]
|
||||
(log/error :exception error)
|
||||
@@ -253,8 +252,7 @@
|
||||
(->
|
||||
(p/let [handle (when-not electron? (idb/get-item handle-path))]
|
||||
(when (or handle electron? mobile-native?)
|
||||
(p/let [_ (when nfs? (nfs/verify-permission repo true))
|
||||
local-files-result (fs/get-files repo-dir)
|
||||
(p/let [local-files-result (fs/get-files repo-dir)
|
||||
_ (when (config/global-config-enabled?)
|
||||
;; reload global config into state
|
||||
(global-config-handler/restore-global-config!))
|
||||
@@ -262,7 +260,7 @@
|
||||
(remove-ignore-files repo-dir nfs?))]
|
||||
(handle-diffs! repo nfs? old-files new-files re-index? ok-handler))))
|
||||
(p/catch (fn [error]
|
||||
(log/error :nfs/load-files-error repo)
|
||||
(log/error :fs/load-files-error repo)
|
||||
(log/error :exception error)))
|
||||
(p/finally (fn [_]
|
||||
(state/set-graph-syncing? false)))))))
|
||||
@@ -1,25 +1,25 @@
|
||||
(ns frontend.handler.file-based.repo
|
||||
"Repo fns for creating, loading and parsing file graphs"
|
||||
(:require [frontend.config :as config]
|
||||
(:require [clojure.core.async :as async]
|
||||
[clojure.core.async.interop :refer [p->c]]
|
||||
[frontend.config :as config]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.handler.file-based.file :as file-handler]
|
||||
[frontend.handler.repo-config :as repo-config-handler]
|
||||
[frontend.handler.file-based.reset-file :as reset-file-handler]
|
||||
[frontend.handler.repo-config :as repo-config-handler]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
[frontend.spec :as spec]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[promesa.core :as p]
|
||||
[shadow.resource :as rc]
|
||||
[logseq.graph-parser :as graph-parser]
|
||||
[logseq.common.config :as common-config]
|
||||
[clojure.core.async :as async]
|
||||
[medley.core :as medley]
|
||||
[logseq.common.path :as path]
|
||||
[clojure.core.async.interop :refer [p->c]]))
|
||||
[logseq.graph-parser :as graph-parser]
|
||||
[medley.core :as medley]
|
||||
[promesa.core :as p]
|
||||
[shadow.resource :as rc]))
|
||||
|
||||
(defn- create-contents-file
|
||||
[repo-url]
|
||||
@@ -54,49 +54,13 @@
|
||||
|
||||
(comment
|
||||
(defn- create-dummy-notes-page
|
||||
[repo-url content]
|
||||
(spec/validate :repos/url repo-url)
|
||||
(let [repo-dir (config/get-repo-dir repo-url)
|
||||
file-rpath (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")]
|
||||
(p/let [_ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-pages-directory)))
|
||||
_file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
|
||||
(reset-file-handler/reset-file! repo-url file-rpath content)))))
|
||||
|
||||
(comment
|
||||
(defn- create-today-journal-if-not-exists
|
||||
[repo-url {:keys [content]}]
|
||||
(spec/validate :repos/url repo-url)
|
||||
(when (state/enable-journals? repo-url)
|
||||
(let [repo-dir (config/get-repo-dir repo-url)
|
||||
format (state/get-preferred-format repo-url)
|
||||
title (date/today)
|
||||
file-name (date/journal-title->default title)
|
||||
default-content (util/default-content-with-title format)
|
||||
template (state/get-default-journal-template)
|
||||
template (when (and template
|
||||
(not (string/blank? template)))
|
||||
template)
|
||||
content (cond
|
||||
content
|
||||
content
|
||||
|
||||
template
|
||||
(str default-content template)
|
||||
|
||||
:else
|
||||
default-content)
|
||||
file-rpath (path/path-join (config/get-journals-directory) (str file-name "."
|
||||
(config/get-file-extension format)))
|
||||
page-exists? (ldb/get-page (db/get-db) title)
|
||||
empty-blocks? (db/page-empty? repo-url (util/page-name-sanity-lc title))]
|
||||
(when (or empty-blocks? (not page-exists?))
|
||||
(p/let [_ (nfs/check-directory-permission! repo-url)
|
||||
_ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-journals-directory)))
|
||||
file-exists? (fs/file-exists? repo-dir file-rpath)]
|
||||
(when-not file-exists?
|
||||
(p/let [_ (reset-file-handler/reset-file! repo-url file-rpath content)]
|
||||
(fs/create-if-not-exists repo-url repo-dir file-rpath content)))))))))
|
||||
|
||||
[repo-url content]
|
||||
(spec/validate :repos/url repo-url)
|
||||
(let [repo-dir (config/get-repo-dir repo-url)
|
||||
file-rpath (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")]
|
||||
(p/let [_ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-pages-directory)))
|
||||
_file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
|
||||
(reset-file-handler/reset-file! repo-url file-rpath content)))))
|
||||
|
||||
(defn create-config-file-if-not-exists
|
||||
"Creates a default logseq/config.edn if it doesn't exist"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
[frontend.handler.db-based.page :as db-page-handler]
|
||||
[frontend.handler.db-based.property :as db-property-handler]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.file-based.page :as file-page-handler]
|
||||
[frontend.handler.file-based.page-property :as file-page-property]
|
||||
[frontend.handler.graph :as graph-handler]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[clojure.string :as string]
|
||||
[frontend.components.svg :as svg]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.handler.file-based.nfs :as nfs-handler]
|
||||
[frontend.handler.file-based.native-fs :as nfs-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
|
||||
@@ -122,15 +122,8 @@
|
||||
|
||||
(defn <export-db!
|
||||
[repo data]
|
||||
(cond
|
||||
(util/electron?)
|
||||
(ipc/ipc :db-export repo data)
|
||||
|
||||
;; TODO: browser nfs-supported? auto backup
|
||||
|
||||
;;
|
||||
:else
|
||||
nil))
|
||||
(when (util/electron?)
|
||||
(ipc/ipc :db-export repo data)))
|
||||
|
||||
(defn- sqlite-error-handler
|
||||
[error]
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
:notification/show? false
|
||||
:notification/content nil
|
||||
:repo/loading-files? {}
|
||||
:nfs/user-granted? {}
|
||||
:nfs/refreshing? nil
|
||||
:instrument/disabled? (storage/get "instrument-disabled")
|
||||
;; TODO: how to detect the network reliably?
|
||||
@@ -2280,10 +2279,6 @@ Similar to re-frame subscriptions"
|
||||
[]
|
||||
(:pdf/current @state))
|
||||
|
||||
(defn nfs-user-granted?
|
||||
[repo]
|
||||
(get-in @state [:nfs/user-granted? repo]))
|
||||
|
||||
(defn set-current-pdf!
|
||||
[inflated-file]
|
||||
(let [settle-file! #(set-state! :pdf/current inflated-file)]
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
(ns frontend.util.fs
|
||||
"Misc util fns built on top of frontend.fs"
|
||||
(:require ["path" :as node-path]
|
||||
[clojure.string :as string]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.config :as config]
|
||||
[promesa.core :as p]
|
||||
[cljs.reader :as reader]
|
||||
[frontend.common.file.util :as wfu]))
|
||||
[clojure.string :as string]
|
||||
[frontend.common.file.util :as wfu]
|
||||
[frontend.config :as config]
|
||||
[frontend.fs :as fs]
|
||||
[promesa.core :as p]))
|
||||
|
||||
;; NOTE: This is not the same ignored-path? as src/electron/electron/utils.cljs.
|
||||
;; The assets directory is ignored.
|
||||
;;
|
||||
;; When in nfs-mode, dir is "", path is relative path to graph dir.
|
||||
;; When in native-mode, dir and path are absolute paths.
|
||||
(defn ignored-path?
|
||||
"Ignore path for ls-dir-files-with-handler! and reload-dir!"
|
||||
@@ -51,8 +50,8 @@
|
||||
txid-meta (and txid-str (reader/read-string txid-str))]
|
||||
txid-meta)
|
||||
(p/catch
|
||||
(fn [^js e]
|
||||
(js/console.error "[fs read txid data error]" e))))))))
|
||||
(fn [^js e]
|
||||
(js/console.error "[fs read txid data error]" e))))))))
|
||||
|
||||
(defn inflate-graphs-info
|
||||
[graphs]
|
||||
|
||||
Reference in New Issue
Block a user