page_menu.cljs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. (ns frontend.components.page-menu
  2. (:require [frontend.commands :as commands]
  3. [frontend.components.export :as export]
  4. [frontend.context.i18n :refer [t]]
  5. [frontend.db :as db]
  6. [frontend.handler.notification :as notification]
  7. [frontend.handler.page :as page-handler]
  8. [frontend.handler.common.developer :as dev-common-handler]
  9. [frontend.state :as state]
  10. [frontend.ui :as ui]
  11. [frontend.util :as util]
  12. [frontend.util.page :as page-util]
  13. [frontend.handler.shell :as shell]
  14. [frontend.mobile.util :as mobile-util]
  15. [electron.ipc :as ipc]
  16. [frontend.config :as config]
  17. [frontend.handler.user :as user-handler]
  18. [frontend.handler.file-sync :as file-sync-handler]
  19. [logseq.common.path :as path]
  20. [frontend.handler.property.util :as pu]
  21. [logseq.db.frontend.property :as db-property]))
  22. (defn- delete-page!
  23. [page-name]
  24. (page-handler/delete! page-name
  25. (fn []
  26. (notification/show! (str "Page " page-name " was deleted successfully!")
  27. :success))
  28. {:error-handler (fn [{:keys [msg]}]
  29. (notification/show! msg :warning))})
  30. (state/close-modal!))
  31. (defn delete-page-dialog
  32. [page-name]
  33. (fn [close-fn]
  34. [:div
  35. [:div.sm:flex.items-center
  36. [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-error.sm:mx-0.sm:h-10.sm:w-10
  37. [:span.text-error.text-xl
  38. (ui/icon "alert-triangle")]]
  39. [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
  40. [:h3#modal-headline.text-lg.leading-6.font-medium
  41. (if (config/db-based-graph? (state/get-current-repo))
  42. (t :page/db-delete-confirmation)
  43. (t :page/delete-confirmation))]]]
  44. [:div.mt-5.sm:mt-4.flex.gap-4
  45. (ui/button
  46. (t :cancel)
  47. {:theme :gray
  48. :on-click close-fn})
  49. (ui/button
  50. (t :yes)
  51. {:class "ui__modal-enter"
  52. :on-click (fn []
  53. (delete-page! page-name))
  54. :button-props {:autoFocus "on"}})]]))
  55. (defn ^:large-vars/cleanup-todo page-menu
  56. [page-name]
  57. (when-let [page-name (or
  58. page-name
  59. (state/get-current-page)
  60. (state/get-current-whiteboard))]
  61. (let [page-name (util/page-name-sanity-lc page-name)
  62. repo (state/sub :git/current-repo)
  63. page (db/entity repo [:block/name page-name])
  64. page-original-name (:block/original-name page)
  65. whiteboard? (contains? (set (:block/type page)) "whiteboard")
  66. block? (and page (util/uuid-string? page-name) (not whiteboard?))
  67. contents? (= page-name "contents")
  68. properties (:block/properties page)
  69. public? (true? (pu/lookup properties :public))
  70. favorited? (page-handler/favorited? page-name)
  71. developer-mode? (state/sub [:ui/developer-mode?])
  72. file-rpath (when (util/electron?) (page-util/get-page-file-rpath page-name))
  73. _ (state/sub :auth/id-token)
  74. file-sync-graph-uuid (and (user-handler/logged-in?)
  75. (file-sync-handler/enable-sync?)
  76. ;; FIXME: Sync state is not cleared when switching to a new graph
  77. (file-sync-handler/current-graph-sync-on?)
  78. (file-sync-handler/get-current-graph-uuid))
  79. built-in-property? (and (contains? (:block/type page) "property")
  80. (contains? db-property/built-in-properties-keys-str page-name))]
  81. (when (and page (not block?))
  82. (->>
  83. [(when-not config/publishing?
  84. {:title (if favorited?
  85. (t :page/unfavorite)
  86. (t :page/add-to-favorites))
  87. :options {:on-click
  88. (fn []
  89. (if favorited?
  90. (page-handler/<unfavorite-page! page-original-name)
  91. (page-handler/<favorite-page! page-original-name)))}})
  92. (when (or (util/electron?) file-sync-graph-uuid)
  93. {:title (t :page/version-history)
  94. :options {:on-click
  95. (fn []
  96. (cond
  97. file-sync-graph-uuid
  98. (state/pub-event! [:graph/pick-page-histories file-sync-graph-uuid page-name])
  99. (util/electron?)
  100. (shell/get-file-latest-git-log page 100)
  101. :else
  102. nil))
  103. :class "cp__btn_history_version"}})
  104. (when (or (util/electron?)
  105. (mobile-util/native-platform?))
  106. {:title (t :page/copy-page-url)
  107. :options {:on-click #(page-handler/copy-page-url page-original-name)}})
  108. (when-not (or contents?
  109. config/publishing?
  110. (and (config/db-based-graph? repo)
  111. built-in-property?))
  112. {:title (t :page/delete)
  113. :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
  114. (when (and (not (mobile-util/native-platform?))
  115. (state/get-current-page))
  116. {:title (t :page/slide-view)
  117. :options {:on-click (fn []
  118. (state/sidebar-add-block!
  119. repo
  120. (:db/id page)
  121. :page-slide-view))}})
  122. ;; TODO: In the future, we'd like to extract file-related actions
  123. ;; (such as open-in-finder & open-with-default-app) into a sub-menu of
  124. ;; this one. However this component doesn't yet exist. PRs are welcome!
  125. ;; Details: https://github.com/logseq/logseq/pull/3003#issuecomment-952820676
  126. (when file-rpath
  127. (let [repo-dir (config/get-repo-dir repo)
  128. file-fpath (path/path-join repo-dir file-rpath)]
  129. [{:title (t :page/open-in-finder)
  130. :options {:on-click #(ipc/ipc "openFileInFolder" file-fpath)}}
  131. {:title (t :page/open-with-default-app)
  132. :options {:on-click #(js/window.apis.openPath file-fpath)}}]))
  133. (when (or (state/get-current-page) whiteboard?)
  134. {:title (t :export-page)
  135. :options {:on-click #(state/set-modal!
  136. (fn []
  137. (export/export-blocks (:block/name page) {:whiteboard? whiteboard?})))}})
  138. (when (util/electron?)
  139. {:title (t (if public? :page/make-private :page/make-public))
  140. :options {:on-click
  141. (fn []
  142. (page-handler/update-public-attribute!
  143. page-name
  144. (if public? false true))
  145. (state/close-modal!))}})
  146. (when (and (util/electron?) file-rpath
  147. (not (file-sync-handler/synced-file-graph? repo)))
  148. {:title (t :page/open-backup-directory)
  149. :options {:on-click
  150. (fn []
  151. (ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-rpath))}})
  152. (when config/lsp-enabled?
  153. (for [[_ {:keys [label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
  154. {:title label
  155. :options {:on-click #(commands/exec-plugin-simple-command!
  156. pid (assoc cmd :page page-name) action)}}))
  157. (when developer-mode?
  158. {:title (t :dev/show-page-data)
  159. :options {:on-click (fn []
  160. (dev-common-handler/show-entity-data (:db/id page)))}})
  161. (when (and developer-mode?
  162. ;; Remove when we have an easy way to fetch file content for a DB graph
  163. (not (config/db-based-graph? repo)))
  164. {:title (t :dev/show-page-ast)
  165. :options {:on-click (fn []
  166. (let [page (db/pull '[:block/format {:block/file [:file/content]}] (:db/id page))]
  167. (dev-common-handler/show-content-ast
  168. (get-in page [:block/file :file/content])
  169. (:block/format page))))}})]
  170. (flatten)
  171. (remove nil?))))))