mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 22:25:01 +00:00
267 lines
13 KiB
Clojure
267 lines
13 KiB
Clojure
(ns frontend.components.repo
|
|
(:require [clojure.string :as string]
|
|
[frontend.components.commit :as commit]
|
|
[frontend.components.encryption :as encryption]
|
|
[frontend.components.svg :as svg]
|
|
[frontend.components.widgets :as widgets]
|
|
[frontend.config :as config]
|
|
[frontend.context.i18n :as i18n]
|
|
[frontend.db :as db]
|
|
[frontend.encrypt :as e]
|
|
[frontend.handler.common :as common-handler]
|
|
[frontend.handler.export :as export-handler]
|
|
[frontend.handler.page :as page-handler]
|
|
[frontend.handler.repo :as repo-handler]
|
|
[frontend.handler.route :as route-handler]
|
|
[frontend.handler.web.nfs :as nfs-handler]
|
|
[frontend.modules.shortcut.core :as shortcut]
|
|
[frontend.state :as state]
|
|
[frontend.ui :as ui]
|
|
[frontend.util :as util]
|
|
[frontend.version :as version]
|
|
[reitit.frontend.easy :as rfe]
|
|
[rum.core :as rum]
|
|
[frontend.mobile.util :as mobile-util]))
|
|
|
|
(rum/defc add-repo
|
|
[args]
|
|
(if-let [graph-types (get-in args [:query-params :graph-types])]
|
|
(let [graph-types-s (->> (string/split graph-types #",")
|
|
(mapv keyword))]
|
|
(when (seq graph-types-s)
|
|
(widgets/add-graph :graph-types graph-types-s)))
|
|
(widgets/add-graph)))
|
|
|
|
(rum/defc repos < rum/reactive
|
|
[]
|
|
(let [repos (->> (state/sub [:me :repos])
|
|
(remove #(= (:url %) config/local-repo)))
|
|
repos (util/distinct-by :url repos)]
|
|
(rum/with-context [[t] i18n/*tongue-context*]
|
|
(if (seq repos)
|
|
[:div#graphs
|
|
[:h1.title "All Graphs"]
|
|
[:p.ml-2.opacity-70
|
|
(if (state/github-authed?)
|
|
"A \"graph\" in Logseq could be either a local directory or a git repo."
|
|
"A \"graph\" in Logseq means a local directory.")]
|
|
|
|
[:div.pl-1.content.mt-3
|
|
[:div.flex.flex-row.my-4
|
|
(when (or (nfs-handler/supported?)
|
|
(mobile-util/is-native-platform?))
|
|
[:div.mr-8
|
|
(ui/button
|
|
(t :open-a-directory)
|
|
:on-click #(page-handler/ls-dir-files! shortcut/refresh!))])
|
|
(when (and (state/logged?) (not (util/electron?)))
|
|
(ui/button
|
|
"Add another git repo"
|
|
:href (rfe/href :repo-add nil {:graph-types "github"})
|
|
:intent "logseq"))]
|
|
(for [{:keys [id url] :as repo} repos]
|
|
(let [local? (config/local-db? url)]
|
|
[:div.flex.justify-between.mb-1 {:key id}
|
|
(if local?
|
|
[:a
|
|
(config/get-local-dir url)]
|
|
[:a {:target "_blank"
|
|
:href url}
|
|
(db/get-repo-path url)])
|
|
[:div.controls
|
|
(when (e/encrypted-db? url)
|
|
[:a.control {:title "Show encryption information about this graph"
|
|
:on-click (fn []
|
|
(state/set-modal! (encryption/encryption-dialog url)))}
|
|
"🔐"])
|
|
[:a.text-gray-400.ml-4 {:title "No worries, unlink this graph will clear its cache only, it does not remove your files on the disk."
|
|
:on-click (fn []
|
|
(repo-handler/remove-repo! repo))}
|
|
"Unlink"]]]))]]
|
|
(widgets/add-graph)))))
|
|
|
|
(defn refresh-cb []
|
|
(page-handler/create-today-journal!)
|
|
(shortcut/refresh!))
|
|
|
|
(rum/defc sync-status < rum/reactive
|
|
{:did-mount (fn [state]
|
|
(js/setTimeout common-handler/check-changed-files-status 1000)
|
|
state)}
|
|
[repo]
|
|
(when (and repo
|
|
(string/starts-with? repo "https://"))
|
|
(let [changed-files (state/sub [:repo/changed-files repo])
|
|
should-push? (seq changed-files)
|
|
git-status (state/sub [:git/status repo])
|
|
pushing? (= :pushing git-status)
|
|
pulling? (= :pulling git-status)
|
|
git-failed? (contains?
|
|
#{:push-failed
|
|
:clone-failed
|
|
:checkout-failed
|
|
:fetch-failed
|
|
:merge-failed}
|
|
git-status)
|
|
push-failed? (= :push-failed git-status)
|
|
last-pulled-at (db/sub-key-value repo :git/last-pulled-at)
|
|
;; db-persisted? (state/sub [:db/persisted? repo])
|
|
editing? (seq (state/sub :editor/editing?))]
|
|
[:div.flex-row.flex.items-center.cp__repo-indicator
|
|
(when pushing? svg/loading)
|
|
(ui/dropdown
|
|
(fn [{:keys [toggle-fn]}]
|
|
[:div.cursor.w-2.h-2.sync-status.mr-2
|
|
{:class (cond
|
|
git-failed?
|
|
"bg-red-500"
|
|
(or
|
|
;; (not db-persisted?)
|
|
editing?
|
|
should-push? pushing?)
|
|
"bg-orange-400"
|
|
:else
|
|
"bg-green-600")
|
|
:style {:border-radius "50%"
|
|
:margin-top 2}
|
|
:on-mouse-over
|
|
(fn [e]
|
|
(toggle-fn)
|
|
(js/setTimeout common-handler/check-changed-files-status 0))}])
|
|
(fn [{:keys [toggle-fn]}]
|
|
(rum/with-context [[t] i18n/*tongue-context*]
|
|
[:div.p-2.rounded-md.shadow-xs.bg-base-3.flex.flex-col.sync-content
|
|
{:on-mouse-leave toggle-fn}
|
|
[:div
|
|
[:div
|
|
(cond
|
|
push-failed?
|
|
[:p (t :git/push-failed)]
|
|
(and should-push? (seq changed-files))
|
|
[:div.changes
|
|
[:ul.overflow-y-auto {:style {:max-height 250}}
|
|
(for [file changed-files]
|
|
[:li {:key (str "sync-" file)}
|
|
[:div.flex.flex-row.justify-between.align-items
|
|
[:a {:href (rfe/href :file {:path file})}
|
|
file]
|
|
[:a.ml-4.text-sm.mt-1
|
|
{:on-click (fn [e]
|
|
(export-handler/download-file! file))}
|
|
[:span (t :download)]]]])]]
|
|
:else
|
|
[:p (t :git/local-changes-synced)])]
|
|
;; [:a.text-sm.font-bold {:href "/diff"} "Check diff"]
|
|
[:div.flex.flex-row.justify-between.align-items.mt-2
|
|
(ui/button (t :git/push)
|
|
:on-click (fn [] (state/set-modal! commit/add-commit-message)))
|
|
(when pushing? svg/loading)]]
|
|
[:hr]
|
|
[:div
|
|
(when-not (string/blank? last-pulled-at)
|
|
[:p {:style {:font-size 12}} (t :git/last-pull)
|
|
(str ": " last-pulled-at)])
|
|
[:div.flex.flex-row.justify-between.align-items
|
|
(ui/button (t :git/pull)
|
|
:on-click (fn [] (repo-handler/pull-current-repo)))
|
|
(when pulling? svg/loading)]
|
|
[:a.mt-5.text-sm.opacity-50.block
|
|
{:on-click (fn []
|
|
(export-handler/export-repo-as-zip! repo))}
|
|
(t :repo/download-zip)]
|
|
[:p.pt-2.text-sm.opacity-50
|
|
(t :git/version) (str " " version/version)]]])))])))
|
|
|
|
(rum/defc repos-dropdown < rum/reactive
|
|
[on-click close-modal-fn]
|
|
(when-let [current-repo (state/sub :git/current-repo)]
|
|
(rum/with-context [[t] i18n/*tongue-context*]
|
|
(let [get-repo-name (fn [repo]
|
|
(if (config/local-db? repo)
|
|
(config/get-local-dir repo)
|
|
(db/get-repo-path repo)))
|
|
close-modal-fn (if (fn? close-modal-fn) close-modal-fn (fn []))
|
|
repos (state/sub [:me :repos])
|
|
repos (remove (fn [r] (= config/local-repo (:url r))) repos)
|
|
switch-repos (remove (fn [repo]
|
|
(= current-repo (:url repo)))
|
|
repos)]
|
|
(when (seq repos)
|
|
(ui/dropdown-with-links
|
|
(fn [{:keys [toggle-fn]}]
|
|
[:a#repo-switch.block.pr-2.whitespace-nowrap {:on-click toggle-fn}
|
|
[:span
|
|
(let [repo-name (get-repo-name current-repo)
|
|
repo-name (if (or (util/electron?)
|
|
(mobile-util/is-native-platform?))
|
|
(last
|
|
(string/split repo-name #"/"))
|
|
repo-name)]
|
|
[:span#repo-name.font-medium {:title repo-name} repo-name])
|
|
[:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]])
|
|
(mapv
|
|
(fn [{:keys [id url]}]
|
|
{:title (get-repo-name url)
|
|
:options {:class "ml-1"
|
|
:on-click (fn []
|
|
(repo-handler/push-if-auto-enabled! (state/get-current-repo))
|
|
(state/set-current-repo! url)
|
|
;; load config
|
|
(common-handler/reset-config! url nil)
|
|
(shortcut/refresh!)
|
|
(when-not (= :draw (state/get-current-route))
|
|
(route-handler/redirect-to-home!))
|
|
(when on-click
|
|
(on-click url))
|
|
(close-modal-fn))}})
|
|
switch-repos)
|
|
(cond->
|
|
{:modal-class (util/hiccup->class
|
|
"origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")
|
|
:links-footer [:div
|
|
(when (seq switch-repos) [:hr.my-4])
|
|
[:a {:class "block px-4 py-2 text-sm transition ease-in-out duration-150 cursor menu-link"
|
|
:on-click close-modal-fn
|
|
:href (rfe/href :repo-add)}
|
|
(t :new-graph)]
|
|
[:a {:class "block px-4 py-2 text-sm transition ease-in-out duration-150 cursor menu-link"
|
|
:on-click close-modal-fn
|
|
:href (rfe/href :repos)}
|
|
(t :all-graphs)]
|
|
(let [nfs-repo? (config/local-db? current-repo)]
|
|
(when (and nfs-repo?
|
|
(not= current-repo config/local-repo)
|
|
(or (nfs-handler/supported?)
|
|
(mobile-util/is-native-platform?)))
|
|
[:a {:class "block px-4 py-2 text-sm transition ease-in-out duration-150 cursor menu-link"
|
|
:on-click (fn []
|
|
(close-modal-fn)
|
|
(state/pub-event!
|
|
[:modal/show
|
|
[:div {:style {:max-width 700}}
|
|
[:p "Refresh detects and processes files modified on your disk and diverged from the actual Logseq page content. Continue?"]
|
|
(ui/button
|
|
"Yes"
|
|
:on-click (fn []
|
|
(state/close-modal!)
|
|
(nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]]))}
|
|
(t :sync-from-local-files)]))
|
|
[:a {:class "block px-4 py-2 text-sm transition ease-in-out duration-150 cursor menu-link"
|
|
:on-click (fn []
|
|
(close-modal-fn)
|
|
(state/pub-event!
|
|
[:modal/show
|
|
[:div {:style {:max-width 700}}
|
|
[:p "Re-index will discard the current graph, and then processes all the files again as they are currently stored on disk. You will lose unsaved changes and it might take a while. Continue?"]
|
|
(ui/button
|
|
"Yes"
|
|
:on-click (fn []
|
|
(state/close-modal!)
|
|
(repo-handler/re-index!
|
|
nfs-handler/rebuild-index!
|
|
page-handler/create-today-journal!)))]]))}
|
|
(t :re-index)]]}
|
|
(seq switch-repos)
|
|
(assoc :links-header [:div.font-medium.text-sm.opacity-70.px-4.py-2
|
|
"Switch to:"]))))))))
|