|
@@ -8,7 +8,7 @@
|
|
|
[frontend.components.reference :as reference]
|
|
|
[frontend.components.svg :as svg]
|
|
|
[frontend.config :as config]
|
|
|
- [frontend.context.i18n :as i18n]
|
|
|
+ [frontend.context.i18n :refer [t]]
|
|
|
[frontend.date :as date]
|
|
|
[frontend.db :as db]
|
|
|
[frontend.db-mixins :as db-mixins]
|
|
@@ -257,78 +257,77 @@
|
|
|
journal? (db/journal-page? page-name)
|
|
|
fmt-journal? (boolean (date/journal-title->int page-name))
|
|
|
sidebar? (:sidebar? option)]
|
|
|
- (rum/with-context [[_t] i18n/*tongue-context*]
|
|
|
- (let [route-page-name path-page-name
|
|
|
- page (if block?
|
|
|
- (->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
|
|
|
- (db/entity repo))
|
|
|
- (do
|
|
|
- (when-not (db/entity repo [:block/name page-name])
|
|
|
- (let [m (format-block/page-name->map path-page-name true)]
|
|
|
- (db/transact! repo [m])))
|
|
|
- (db/pull [:block/name page-name])))
|
|
|
- {:keys [icon]} (:block/properties page)
|
|
|
- page-name (:block/name page)
|
|
|
- page-original-name (:block/original-name page)
|
|
|
- title (or page-original-name page-name)
|
|
|
- icon (or icon "")
|
|
|
- today? (and
|
|
|
- journal?
|
|
|
- (= page-name (util/page-name-sanity-lc (date/journal-name))))]
|
|
|
- [:div.flex-1.page.relative
|
|
|
- (merge (if (seq (:block/tags page))
|
|
|
- (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
|
|
|
- {:data-page-tags (text/build-data-value page-names)})
|
|
|
- {})
|
|
|
-
|
|
|
- {:key path-page-name
|
|
|
- :class (util/classnames [{:is-journals (or journal? fmt-journal?)}])})
|
|
|
-
|
|
|
- [:div.relative
|
|
|
- (when (and (not sidebar?)
|
|
|
- (not block?))
|
|
|
- [:div.flex.flex-row.space-between
|
|
|
- [:div.flex-1.flex-row
|
|
|
- (page-title page-name icon title format fmt-journal?)]
|
|
|
- (when (not config/publishing?)
|
|
|
- [:div.flex.flex-row
|
|
|
- (when plugin-handler/lsp-enabled?
|
|
|
- (plugins/hook-ui-slot :page-head-actions-slotted nil)
|
|
|
- (plugins/hook-ui-items :pagebar))])])
|
|
|
- [:div
|
|
|
- (when (and block? (not sidebar?))
|
|
|
- (let [config {:id "block-parent"
|
|
|
- :block? true}]
|
|
|
- [:div.mb-4
|
|
|
- (block/block-parents config repo block-id {:level-limit 3})]))
|
|
|
-
|
|
|
- ;; blocks
|
|
|
- (let [page (if block?
|
|
|
- (db/entity repo [:block/uuid block-id])
|
|
|
- page)]
|
|
|
- (page-blocks-cp repo page {:sidebar? sidebar?}))]]
|
|
|
-
|
|
|
- (when-not block?
|
|
|
- (today-queries repo today? sidebar?))
|
|
|
-
|
|
|
- (when-not block?
|
|
|
- (tagged-pages repo page-name))
|
|
|
-
|
|
|
- ;; referenced blocks
|
|
|
- [:div {:key "page-references"}
|
|
|
- (rum/with-key
|
|
|
- (reference/references route-page-name false)
|
|
|
- (str route-page-name "-refs"))]
|
|
|
-
|
|
|
- (when-not block?
|
|
|
- [:div
|
|
|
- (when (not journal?)
|
|
|
- (hierarchy/structures route-page-name))
|
|
|
-
|
|
|
- ;; TODO: or we can lazy load them
|
|
|
- (when-not sidebar?
|
|
|
- [:div {:key "page-unlinked-references"}
|
|
|
- (reference/unlinked-references route-page-name)])])])))))
|
|
|
+ (let [route-page-name path-page-name
|
|
|
+ page (if block?
|
|
|
+ (->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
|
|
|
+ (db/entity repo))
|
|
|
+ (do
|
|
|
+ (when-not (db/entity repo [:block/name page-name])
|
|
|
+ (let [m (format-block/page-name->map path-page-name true)]
|
|
|
+ (db/transact! repo [m])))
|
|
|
+ (db/pull [:block/name page-name])))
|
|
|
+ {:keys [icon]} (:block/properties page)
|
|
|
+ page-name (:block/name page)
|
|
|
+ page-original-name (:block/original-name page)
|
|
|
+ title (or page-original-name page-name)
|
|
|
+ icon (or icon "")
|
|
|
+ today? (and
|
|
|
+ journal?
|
|
|
+ (= page-name (util/page-name-sanity-lc (date/journal-name))))]
|
|
|
+ [:div.flex-1.page.relative
|
|
|
+ (merge (if (seq (:block/tags page))
|
|
|
+ (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
|
|
|
+ {:data-page-tags (text/build-data-value page-names)})
|
|
|
+ {})
|
|
|
+
|
|
|
+ {:key path-page-name
|
|
|
+ :class (util/classnames [{:is-journals (or journal? fmt-journal?)}])})
|
|
|
+
|
|
|
+ [:div.relative
|
|
|
+ (when (and (not sidebar?)
|
|
|
+ (not block?))
|
|
|
+ [:div.flex.flex-row.space-between
|
|
|
+ [:div.flex-1.flex-row
|
|
|
+ (page-title page-name icon title format fmt-journal?)]
|
|
|
+ (when (not config/publishing?)
|
|
|
+ [:div.flex.flex-row
|
|
|
+ (when plugin-handler/lsp-enabled?
|
|
|
+ (plugins/hook-ui-slot :page-head-actions-slotted nil)
|
|
|
+ (plugins/hook-ui-items :pagebar))])])
|
|
|
+ [:div
|
|
|
+ (when (and block? (not sidebar?))
|
|
|
+ (let [config {:id "block-parent"
|
|
|
+ :block? true}]
|
|
|
+ [:div.mb-4
|
|
|
+ (block/block-parents config repo block-id {:level-limit 3})]))
|
|
|
+
|
|
|
+ ;; blocks
|
|
|
+ (let [page (if block?
|
|
|
+ (db/entity repo [:block/uuid block-id])
|
|
|
+ page)]
|
|
|
+ (page-blocks-cp repo page {:sidebar? sidebar?}))]]
|
|
|
+
|
|
|
+ (when-not block?
|
|
|
+ (today-queries repo today? sidebar?))
|
|
|
+
|
|
|
+ (when-not block?
|
|
|
+ (tagged-pages repo page-name))
|
|
|
+
|
|
|
+ ;; referenced blocks
|
|
|
+ [:div {:key "page-references"}
|
|
|
+ (rum/with-key
|
|
|
+ (reference/references route-page-name false)
|
|
|
+ (str route-page-name "-refs"))]
|
|
|
+
|
|
|
+ (when-not block?
|
|
|
+ [:div
|
|
|
+ (when (not journal?)
|
|
|
+ (hierarchy/structures route-page-name))
|
|
|
+
|
|
|
+ ;; TODO: or we can lazy load them
|
|
|
+ (when-not sidebar?
|
|
|
+ [:div {:key "page-unlinked-references"}
|
|
|
+ (reference/unlinked-references route-page-name)])])]))))
|
|
|
|
|
|
(defonce layout (atom [js/window.innerWidth js/window.innerHeight]))
|
|
|
|
|
@@ -374,103 +373,102 @@
|
|
|
(config-handler/set-config! :graph/settings new-settings)))
|
|
|
search-graph-filters (state/sub :search/graph-filters)
|
|
|
focus-nodes (rum/react *focus-nodes)]
|
|
|
- (rum/with-context [[t] i18n/*tongue-context*]
|
|
|
- [:div.absolute.top-4.right-4.graph-filters
|
|
|
- [:div.flex.flex-col
|
|
|
- [:div.shadow-xl.rounded-sm
|
|
|
- [:ul
|
|
|
- (graph-filter-section
|
|
|
- [:span.font-medium "Nodes"]
|
|
|
- (fn [open?]
|
|
|
- (filter-expand-area
|
|
|
- open?
|
|
|
- [:div
|
|
|
- [:p.text-sm.opacity-70.px-4
|
|
|
- (let [c1 (count (:nodes graph))
|
|
|
- s1 (if (> c1 1) "s" "")
|
|
|
- ;; c2 (count (:links graph))
|
|
|
- ;; s2 (if (> c2 1) "s" "")
|
|
|
- ]
|
|
|
- ;; (util/format "%d page%s, %d link%s" c1 s1 c2 s2)
|
|
|
- (util/format "%d page%s" c1 s1))]
|
|
|
- [:div.p-6
|
|
|
- ;; [:div.flex.items-center.justify-between.mb-2
|
|
|
- ;; [:span "Layout"]
|
|
|
- ;; (ui/select
|
|
|
- ;; (mapv
|
|
|
- ;; (fn [item]
|
|
|
- ;; (if (= (:label item) layout)
|
|
|
- ;; (assoc item :selected "selected")
|
|
|
- ;; item))
|
|
|
- ;; [{:label "gForce"}
|
|
|
- ;; {:label "dagre"}])
|
|
|
- ;; (fn [value]
|
|
|
- ;; (set-setting! :layout value))
|
|
|
- ;; "graph-layout")]
|
|
|
- [:div.flex.items-center.justify-between.mb-2
|
|
|
- [:span (t :right-side-bar/journals)]
|
|
|
- ;; FIXME: why it's not aligned well?
|
|
|
- [:div.mt-1
|
|
|
- (ui/toggle journal?
|
|
|
- (fn []
|
|
|
- (let [value (not journal?)]
|
|
|
- (reset! *journal? value)
|
|
|
- (set-setting! :journal? value)))
|
|
|
- true)]]
|
|
|
- [:div.flex.items-center.justify-between.mb-2
|
|
|
- [:span "Orphan pages"]
|
|
|
- [:div.mt-1
|
|
|
- (ui/toggle orphan-pages?
|
|
|
- (fn []
|
|
|
- (let [value (not orphan-pages?)]
|
|
|
- (reset! *orphan-pages? value)
|
|
|
- (set-setting! :orphan-pages? value)))
|
|
|
- true)]]
|
|
|
- [:div.flex.items-center.justify-between.mb-2
|
|
|
- [:span "Built-in pages"]
|
|
|
- [:div.mt-1
|
|
|
- (ui/toggle builtin-pages?
|
|
|
- (fn []
|
|
|
- (let [value (not builtin-pages?)]
|
|
|
- (reset! *builtin-pages? value)
|
|
|
- (set-setting! :builtin-pages? value)))
|
|
|
- true)]]
|
|
|
- (when (seq focus-nodes)
|
|
|
- [:div.flex.flex-col.mb-2
|
|
|
- [:p {:title "N hops from selected nodes"}
|
|
|
- "N hops from selected nodes"]
|
|
|
- (ui/tippy {:html [:div.pr-3 n-hops]}
|
|
|
- (ui/slider (or n-hops 10)
|
|
|
- {:min 1
|
|
|
- :max 10
|
|
|
- :on-change #(reset! *n-hops (int %))}))])
|
|
|
-
|
|
|
- [:a.opacity-70.opacity-100 {:on-click (fn []
|
|
|
- (swap! *graph-reset? not)
|
|
|
- (reset! *focus-nodes [])
|
|
|
- (reset! *n-hops nil)
|
|
|
- (state/clear-search-filters!))}
|
|
|
- "Reset Graph"]]]))
|
|
|
- {})
|
|
|
- (graph-filter-section
|
|
|
- [:span.font-medium "Search"]
|
|
|
- (fn [open?]
|
|
|
- (filter-expand-area
|
|
|
- open?
|
|
|
- [:div.p-6
|
|
|
- (if (seq search-graph-filters)
|
|
|
- [:div
|
|
|
- (for [q search-graph-filters]
|
|
|
- [:div.flex.flex-row.justify-between.items-center.mb-2
|
|
|
- [:span.font-medium q]
|
|
|
- [:a.search-filter-close.opacity-70.opacity-100 {:on-click #(state/remove-search-filter! q)}
|
|
|
- svg/close]])
|
|
|
-
|
|
|
- [:a.opacity-70.opacity-100 {:on-click state/clear-search-filters!}
|
|
|
- "Clear All"]]
|
|
|
- [:a.opacity-70.opacity-100 {:on-click #(route-handler/go-to-search! :graph)}
|
|
|
- "Click to search"])]))
|
|
|
- {:search-filters search-graph-filters})]]]])))
|
|
|
+ [:div.absolute.top-4.right-4.graph-filters
|
|
|
+ [:div.flex.flex-col
|
|
|
+ [:div.shadow-xl.rounded-sm
|
|
|
+ [:ul
|
|
|
+ (graph-filter-section
|
|
|
+ [:span.font-medium "Nodes"]
|
|
|
+ (fn [open?]
|
|
|
+ (filter-expand-area
|
|
|
+ open?
|
|
|
+ [:div
|
|
|
+ [:p.text-sm.opacity-70.px-4
|
|
|
+ (let [c1 (count (:nodes graph))
|
|
|
+ s1 (if (> c1 1) "s" "")
|
|
|
+ ;; c2 (count (:links graph))
|
|
|
+ ;; s2 (if (> c2 1) "s" "")
|
|
|
+ ]
|
|
|
+ ;; (util/format "%d page%s, %d link%s" c1 s1 c2 s2)
|
|
|
+ (util/format "%d page%s" c1 s1))]
|
|
|
+ [:div.p-6
|
|
|
+ ;; [:div.flex.items-center.justify-between.mb-2
|
|
|
+ ;; [:span "Layout"]
|
|
|
+ ;; (ui/select
|
|
|
+ ;; (mapv
|
|
|
+ ;; (fn [item]
|
|
|
+ ;; (if (= (:label item) layout)
|
|
|
+ ;; (assoc item :selected "selected")
|
|
|
+ ;; item))
|
|
|
+ ;; [{:label "gForce"}
|
|
|
+ ;; {:label "dagre"}])
|
|
|
+ ;; (fn [value]
|
|
|
+ ;; (set-setting! :layout value))
|
|
|
+ ;; "graph-layout")]
|
|
|
+ [:div.flex.items-center.justify-between.mb-2
|
|
|
+ [:span (t :right-side-bar/journals)]
|
|
|
+ ;; FIXME: why it's not aligned well?
|
|
|
+ [:div.mt-1
|
|
|
+ (ui/toggle journal?
|
|
|
+ (fn []
|
|
|
+ (let [value (not journal?)]
|
|
|
+ (reset! *journal? value)
|
|
|
+ (set-setting! :journal? value)))
|
|
|
+ true)]]
|
|
|
+ [:div.flex.items-center.justify-between.mb-2
|
|
|
+ [:span "Orphan pages"]
|
|
|
+ [:div.mt-1
|
|
|
+ (ui/toggle orphan-pages?
|
|
|
+ (fn []
|
|
|
+ (let [value (not orphan-pages?)]
|
|
|
+ (reset! *orphan-pages? value)
|
|
|
+ (set-setting! :orphan-pages? value)))
|
|
|
+ true)]]
|
|
|
+ [:div.flex.items-center.justify-between.mb-2
|
|
|
+ [:span "Built-in pages"]
|
|
|
+ [:div.mt-1
|
|
|
+ (ui/toggle builtin-pages?
|
|
|
+ (fn []
|
|
|
+ (let [value (not builtin-pages?)]
|
|
|
+ (reset! *builtin-pages? value)
|
|
|
+ (set-setting! :builtin-pages? value)))
|
|
|
+ true)]]
|
|
|
+ (when (seq focus-nodes)
|
|
|
+ [:div.flex.flex-col.mb-2
|
|
|
+ [:p {:title "N hops from selected nodes"}
|
|
|
+ "N hops from selected nodes"]
|
|
|
+ (ui/tippy {:html [:div.pr-3 n-hops]}
|
|
|
+ (ui/slider (or n-hops 10)
|
|
|
+ {:min 1
|
|
|
+ :max 10
|
|
|
+ :on-change #(reset! *n-hops (int %))}))])
|
|
|
+
|
|
|
+ [:a.opacity-70.opacity-100 {:on-click (fn []
|
|
|
+ (swap! *graph-reset? not)
|
|
|
+ (reset! *focus-nodes [])
|
|
|
+ (reset! *n-hops nil)
|
|
|
+ (state/clear-search-filters!))}
|
|
|
+ "Reset Graph"]]]))
|
|
|
+ {})
|
|
|
+ (graph-filter-section
|
|
|
+ [:span.font-medium "Search"]
|
|
|
+ (fn [open?]
|
|
|
+ (filter-expand-area
|
|
|
+ open?
|
|
|
+ [:div.p-6
|
|
|
+ (if (seq search-graph-filters)
|
|
|
+ [:div
|
|
|
+ (for [q search-graph-filters]
|
|
|
+ [:div.flex.flex-row.justify-between.items-center.mb-2
|
|
|
+ [:span.font-medium q]
|
|
|
+ [:a.search-filter-close.opacity-70.opacity-100 {:on-click #(state/remove-search-filter! q)}
|
|
|
+ svg/close]])
|
|
|
+
|
|
|
+ [:a.opacity-70.opacity-100 {:on-click state/clear-search-filters!}
|
|
|
+ "Clear All"]]
|
|
|
+ [:a.opacity-70.opacity-100 {:on-click #(route-handler/go-to-search! :graph)}
|
|
|
+ "Click to search"])]))
|
|
|
+ {:search-filters search-graph-filters})]]]]))
|
|
|
|
|
|
(defonce last-node-position (atom nil))
|
|
|
(defn- graph-register-handlers
|
|
@@ -503,18 +501,17 @@
|
|
|
(and (not (nodes (:source link)))
|
|
|
(not (nodes (:target link)))))
|
|
|
links))))]
|
|
|
- (rum/with-context [[_t] i18n/*tongue-context*]
|
|
|
- [:div.relative#global-graph
|
|
|
- (graph/graph-2d {:nodes (:nodes graph)
|
|
|
- :links (:links graph)
|
|
|
- :width (- width 24)
|
|
|
- :height (- height 48)
|
|
|
- :dark? dark?
|
|
|
- :register-handlers-fn
|
|
|
- (fn [graph]
|
|
|
- (graph-register-handlers graph *focus-nodes *n-hops dark?))
|
|
|
- :reset? reset?})
|
|
|
- (graph-filters graph settings n-hops)])))
|
|
|
+ [:div.relative#global-graph
|
|
|
+ (graph/graph-2d {:nodes (:nodes graph)
|
|
|
+ :links (:links graph)
|
|
|
+ :width (- width 24)
|
|
|
+ :height (- height 48)
|
|
|
+ :dark? dark?
|
|
|
+ :register-handlers-fn
|
|
|
+ (fn [graph]
|
|
|
+ (graph-register-handlers graph *focus-nodes *n-hops dark?))
|
|
|
+ :reset? reset?})
|
|
|
+ (graph-filters graph settings n-hops)]))
|
|
|
|
|
|
(defn- filter-graph-nodes
|
|
|
[nodes filters]
|
|
@@ -612,55 +609,52 @@
|
|
|
(defn batch-delete-dialog
|
|
|
[pages orphaned-pages? refresh-fn]
|
|
|
(fn [close-fn]
|
|
|
- (rum/with-context
|
|
|
- [[t] i18n/*tongue-context*]
|
|
|
-
|
|
|
- [:div
|
|
|
- [:div.sm:flex.items-center
|
|
|
- [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
|
|
|
- [:span.text-red-600.text-xl
|
|
|
- (ui/icon "alert-triangle")]]
|
|
|
- [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
|
|
|
- [:h3#modal-headline.text-lg.leading-6.font-medium
|
|
|
- (if orphaned-pages?
|
|
|
- (str (t :remove-orphaned-pages) "?")
|
|
|
- (t :page/delete-confirmation))]]]
|
|
|
-
|
|
|
- [:table.table-auto.cp__all_pages_table.mt-4
|
|
|
- [:thead
|
|
|
- [:tr.opacity-70
|
|
|
- [:th [:span "#"]]
|
|
|
- [:th [:span (t :block/name)]]
|
|
|
- [:th [:span (t :page/backlinks)]]
|
|
|
- (when-not orphaned-pages? [:th [:span (t :page/created-at)]])
|
|
|
- (when-not orphaned-pages? [:th [:span (t :page/updated-at)]])]]
|
|
|
-
|
|
|
- [:tbody
|
|
|
- (for [[n {:block/keys [name created-at updated-at backlinks] :as page}] (medley/indexed pages)]
|
|
|
- [:tr {:key name}
|
|
|
- [:td.n.w-10 [:span.opacity-70 (str (inc n) ". ")]]
|
|
|
- [:td.name [:a {:href (rfe/href :page {:name (:block/name page)})}
|
|
|
- (block/page-cp {} page)]]
|
|
|
- [:td.backlinks [:span (or backlinks "0")]]
|
|
|
- (when-not orphaned-pages? [:td.created-at [:span (if created-at (date/int->local-time-2 created-at) "Unknown")]])
|
|
|
- (when-not orphaned-pages? [:td.updated-at [:span (if updated-at (date/int->local-time-2 updated-at) "Unknown")]])])]]
|
|
|
-
|
|
|
- [:div.pt-6.flex.justify-end
|
|
|
-
|
|
|
- [:span.pr-2
|
|
|
- (ui/button
|
|
|
- (t :cancel)
|
|
|
- :intent "logseq"
|
|
|
- :on-click close-fn)]
|
|
|
-
|
|
|
- (ui/button
|
|
|
- (t :yes)
|
|
|
- :on-click (fn []
|
|
|
- (close-fn)
|
|
|
- (doseq [page-name (map :block/name pages)]
|
|
|
- (page-handler/delete! page-name #()))
|
|
|
- (notification/show! (str (t :tips/all-done) "!") :success)
|
|
|
- (js/setTimeout #(refresh-fn) 200)))]])))
|
|
|
+ [:div
|
|
|
+ [:div.sm:flex.items-center
|
|
|
+ [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
|
|
|
+ [:span.text-red-600.text-xl
|
|
|
+ (ui/icon "alert-triangle")]]
|
|
|
+ [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
|
|
|
+ [:h3#modal-headline.text-lg.leading-6.font-medium
|
|
|
+ (if orphaned-pages?
|
|
|
+ (str (t :remove-orphaned-pages) "?")
|
|
|
+ (t :page/delete-confirmation))]]]
|
|
|
+
|
|
|
+ [:table.table-auto.cp__all_pages_table.mt-4
|
|
|
+ [:thead
|
|
|
+ [:tr.opacity-70
|
|
|
+ [:th [:span "#"]]
|
|
|
+ [:th [:span (t :block/name)]]
|
|
|
+ [:th [:span (t :page/backlinks)]]
|
|
|
+ (when-not orphaned-pages? [:th [:span (t :page/created-at)]])
|
|
|
+ (when-not orphaned-pages? [:th [:span (t :page/updated-at)]])]]
|
|
|
+
|
|
|
+ [:tbody
|
|
|
+ (for [[n {:block/keys [name created-at updated-at backlinks] :as page}] (medley/indexed pages)]
|
|
|
+ [:tr {:key name}
|
|
|
+ [:td.n.w-10 [:span.opacity-70 (str (inc n) ". ")]]
|
|
|
+ [:td.name [:a {:href (rfe/href :page {:name (:block/name page)})}
|
|
|
+ (block/page-cp {} page)]]
|
|
|
+ [:td.backlinks [:span (or backlinks "0")]]
|
|
|
+ (when-not orphaned-pages? [:td.created-at [:span (if created-at (date/int->local-time-2 created-at) "Unknown")]])
|
|
|
+ (when-not orphaned-pages? [:td.updated-at [:span (if updated-at (date/int->local-time-2 updated-at) "Unknown")]])])]]
|
|
|
+
|
|
|
+ [:div.pt-6.flex.justify-end
|
|
|
+
|
|
|
+ [:span.pr-2
|
|
|
+ (ui/button
|
|
|
+ (t :cancel)
|
|
|
+ :intent "logseq"
|
|
|
+ :on-click close-fn)]
|
|
|
+
|
|
|
+ (ui/button
|
|
|
+ (t :yes)
|
|
|
+ :on-click (fn []
|
|
|
+ (close-fn)
|
|
|
+ (doseq [page-name (map :block/name pages)]
|
|
|
+ (page-handler/delete! page-name #()))
|
|
|
+ (notification/show! (str (t :tips/all-done) "!") :success)
|
|
|
+ (js/setTimeout #(refresh-fn) 200)))]]))
|
|
|
|
|
|
(rum/defcs all-pages < rum/reactive
|
|
|
(rum/local nil ::pages)
|
|
@@ -721,187 +715,186 @@
|
|
|
(reset! *pages nil)
|
|
|
(reset! *current-page 1))]
|
|
|
|
|
|
- (rum/with-context [[t] i18n/*tongue-context*]
|
|
|
- [:div.flex-1.cp__all_pages
|
|
|
- [:h1.title (t :all-pages)]
|
|
|
-
|
|
|
- (when current-repo
|
|
|
-
|
|
|
- ;; all pages
|
|
|
- (when (nil? @*pages)
|
|
|
- (let [pages (->> (page-handler/get-all-pages current-repo)
|
|
|
- (map-indexed (fn [idx page] (assoc page
|
|
|
- :block/backlinks (count (:block/_refs (db/entity (:db/id page))))
|
|
|
- :block/idx idx))))]
|
|
|
- (reset! *filter-fn
|
|
|
- (memoize (fn [sort-by-item desc? journal?]
|
|
|
- (->> pages
|
|
|
- (filter #(or (boolean journal?)
|
|
|
- (= false (boolean (:block/journal? %)))))
|
|
|
- (sort-pages-by sort-by-item desc?)))))
|
|
|
- (reset! *pages pages)))
|
|
|
-
|
|
|
- ;; filter results
|
|
|
- (when @*filter-fn
|
|
|
- (let [pages (@*filter-fn @*sort-by-item @*desc? @*journal?)
|
|
|
-
|
|
|
- ;; search key
|
|
|
- pages (if-not (string/blank? @*search-key)
|
|
|
- (search/fuzzy-search pages (util/page-name-sanity-lc @*search-key)
|
|
|
- :limit 20
|
|
|
- :extract-fn :block/name)
|
|
|
- pages)
|
|
|
-
|
|
|
- _ (reset! *results-all pages)
|
|
|
-
|
|
|
- pages (take per-page-num (drop (* per-page-num (dec @*current-page)) pages))]
|
|
|
-
|
|
|
- (reset! *checks (into {} (for [{:block/keys [idx]} pages]
|
|
|
- [idx (boolean (get @*checks idx))])))
|
|
|
- (reset! *results pages)))
|
|
|
-
|
|
|
- [[:div.actions
|
|
|
- {:class (util/classnames [{:has-selected (or (nil? @*indeterminate)
|
|
|
- (not= 0 @*indeterminate))}])}
|
|
|
- [:div.l.flex.items-center
|
|
|
- [:div.actions-wrap
|
|
|
- (ui/button
|
|
|
- [(ui/icon "trash") (t :delete)]
|
|
|
- :on-click (fn []
|
|
|
- (let [selected (filter (fn [[_ v]] v) @*checks)
|
|
|
- selected (and (seq selected)
|
|
|
- (into #{} (for [[k _] selected] k)))]
|
|
|
- (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))]
|
|
|
- (state/set-modal! (batch-delete-dialog pages false #(do
|
|
|
- (reset! *checks nil)
|
|
|
- (refresh-pages)))))))
|
|
|
- :small? true)]
|
|
|
-
|
|
|
- [:div.search-wrap.flex.items-center.pl-2
|
|
|
- (let [search-fn (fn []
|
|
|
- (let [^js input (rum/deref *search-input)]
|
|
|
- (search-key (.-value input))
|
|
|
- (reset! *current-page 1)))
|
|
|
- reset-fn (fn []
|
|
|
- (let [^js input (rum/deref *search-input)]
|
|
|
- (set! (.-value input) "")
|
|
|
- (reset! *search-key nil)))]
|
|
|
-
|
|
|
- [(ui/button (ui/icon "search")
|
|
|
- :on-click search-fn
|
|
|
- :small? true)
|
|
|
- [:input.form-input {:placeholder (t :search/page-names)
|
|
|
- :on-key-up (fn [^js e]
|
|
|
- (let [^js target (.-target e)]
|
|
|
- (if (string/blank? (.-value target))
|
|
|
- (reset! *search-key nil)
|
|
|
- (cond
|
|
|
- (= 13 (.-keyCode e)) (search-fn)
|
|
|
- (= 27 (.-keyCode e)) (reset-fn)))))
|
|
|
- :ref *search-input
|
|
|
- :default-value ""}]
|
|
|
-
|
|
|
- (when (not (string/blank? @*search-key))
|
|
|
- [:a.cancel {:on-click reset-fn}
|
|
|
- (ui/icon "x")])])]]
|
|
|
-
|
|
|
- [:div.r.flex.items-center.justify-between
|
|
|
- (let [orphaned-pages (model/get-orphaned-pages {})
|
|
|
- orphaned-pages? (seq orphaned-pages)]
|
|
|
- [:a.ml-1.pr-2.opacity-70.hover:opacity-100
|
|
|
- {:on-click (fn []
|
|
|
- (if orphaned-pages?
|
|
|
- (state/set-modal!
|
|
|
- (batch-delete-dialog
|
|
|
- orphaned-pages true
|
|
|
- #(do
|
|
|
- (reset! *checks nil)
|
|
|
- (refresh-pages))))
|
|
|
- (notification/show! "Congratulations, no orphaned pages in your graph!" :success)))}
|
|
|
- [:span
|
|
|
- (ui/icon "file-x")
|
|
|
- [:span.ml-1 (t :remove-orphaned-pages)]]])
|
|
|
-
|
|
|
- [:a.ml-1.pr-2.opacity-70.hover:opacity-100 {:href (rfe/href :all-files)}
|
|
|
+ [:div.flex-1.cp__all_pages
|
|
|
+ [:h1.title (t :all-pages)]
|
|
|
+
|
|
|
+ (when current-repo
|
|
|
+
|
|
|
+ ;; all pages
|
|
|
+ (when (nil? @*pages)
|
|
|
+ (let [pages (->> (page-handler/get-all-pages current-repo)
|
|
|
+ (map-indexed (fn [idx page] (assoc page
|
|
|
+ :block/backlinks (count (:block/_refs (db/entity (:db/id page))))
|
|
|
+ :block/idx idx))))]
|
|
|
+ (reset! *filter-fn
|
|
|
+ (memoize (fn [sort-by-item desc? journal?]
|
|
|
+ (->> pages
|
|
|
+ (filter #(or (boolean journal?)
|
|
|
+ (= false (boolean (:block/journal? %)))))
|
|
|
+ (sort-pages-by sort-by-item desc?)))))
|
|
|
+ (reset! *pages pages)))
|
|
|
+
|
|
|
+ ;; filter results
|
|
|
+ (when @*filter-fn
|
|
|
+ (let [pages (@*filter-fn @*sort-by-item @*desc? @*journal?)
|
|
|
+
|
|
|
+ ;; search key
|
|
|
+ pages (if-not (string/blank? @*search-key)
|
|
|
+ (search/fuzzy-search pages (util/page-name-sanity-lc @*search-key)
|
|
|
+ :limit 20
|
|
|
+ :extract-fn :block/name)
|
|
|
+ pages)
|
|
|
+
|
|
|
+ _ (reset! *results-all pages)
|
|
|
+
|
|
|
+ pages (take per-page-num (drop (* per-page-num (dec @*current-page)) pages))]
|
|
|
+
|
|
|
+ (reset! *checks (into {} (for [{:block/keys [idx]} pages]
|
|
|
+ [idx (boolean (get @*checks idx))])))
|
|
|
+ (reset! *results pages)))
|
|
|
+
|
|
|
+ [[:div.actions
|
|
|
+ {:class (util/classnames [{:has-selected (or (nil? @*indeterminate)
|
|
|
+ (not= 0 @*indeterminate))}])}
|
|
|
+ [:div.l.flex.items-center
|
|
|
+ [:div.actions-wrap
|
|
|
+ (ui/button
|
|
|
+ [(ui/icon "trash") (t :delete)]
|
|
|
+ :on-click (fn []
|
|
|
+ (let [selected (filter (fn [[_ v]] v) @*checks)
|
|
|
+ selected (and (seq selected)
|
|
|
+ (into #{} (for [[k _] selected] k)))]
|
|
|
+ (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))]
|
|
|
+ (state/set-modal! (batch-delete-dialog pages false #(do
|
|
|
+ (reset! *checks nil)
|
|
|
+ (refresh-pages)))))))
|
|
|
+ :small? true)]
|
|
|
+
|
|
|
+ [:div.search-wrap.flex.items-center.pl-2
|
|
|
+ (let [search-fn (fn []
|
|
|
+ (let [^js input (rum/deref *search-input)]
|
|
|
+ (search-key (.-value input))
|
|
|
+ (reset! *current-page 1)))
|
|
|
+ reset-fn (fn []
|
|
|
+ (let [^js input (rum/deref *search-input)]
|
|
|
+ (set! (.-value input) "")
|
|
|
+ (reset! *search-key nil)))]
|
|
|
+
|
|
|
+ [(ui/button (ui/icon "search")
|
|
|
+ :on-click search-fn
|
|
|
+ :small? true)
|
|
|
+ [:input.form-input {:placeholder (t :search/page-names)
|
|
|
+ :on-key-up (fn [^js e]
|
|
|
+ (let [^js target (.-target e)]
|
|
|
+ (if (string/blank? (.-value target))
|
|
|
+ (reset! *search-key nil)
|
|
|
+ (cond
|
|
|
+ (= 13 (.-keyCode e)) (search-fn)
|
|
|
+ (= 27 (.-keyCode e)) (reset-fn)))))
|
|
|
+ :ref *search-input
|
|
|
+ :default-value ""}]
|
|
|
+
|
|
|
+ (when (not (string/blank? @*search-key))
|
|
|
+ [:a.cancel {:on-click reset-fn}
|
|
|
+ (ui/icon "x")])])]]
|
|
|
+
|
|
|
+ [:div.r.flex.items-center.justify-between
|
|
|
+ (let [orphaned-pages (model/get-orphaned-pages {})
|
|
|
+ orphaned-pages? (seq orphaned-pages)]
|
|
|
+ [:a.ml-1.pr-2.opacity-70.hover:opacity-100
|
|
|
+ {:on-click (fn []
|
|
|
+ (if orphaned-pages?
|
|
|
+ (state/set-modal!
|
|
|
+ (batch-delete-dialog
|
|
|
+ orphaned-pages true
|
|
|
+ #(do
|
|
|
+ (reset! *checks nil)
|
|
|
+ (refresh-pages))))
|
|
|
+ (notification/show! "Congratulations, no orphaned pages in your graph!" :success)))}
|
|
|
[:span
|
|
|
- (ui/icon "files")
|
|
|
- [:span.ml-1 (t :all-files)]]]
|
|
|
+ (ui/icon "file-x")
|
|
|
+ [:span.ml-1 (t :remove-orphaned-pages)]]])
|
|
|
|
|
|
- [:div
|
|
|
- (ui/tippy
|
|
|
- {:html [:small (str (t :page/show-journals) " ?")]
|
|
|
- :arrow true}
|
|
|
- [:a.button.journal
|
|
|
- {:class (util/classnames [{:active (boolean @*journal?)}])
|
|
|
- :on-click #(reset! *journal? (not @*journal?))}
|
|
|
- (ui/icon "calendar")])]
|
|
|
-
|
|
|
- [:div.paginates
|
|
|
- [:span.flex.items-center.opacity-60.text-sm
|
|
|
- [:span.pr-1 (t :paginates/pages (count @*results-all))]]
|
|
|
- [:span.flex.items-center
|
|
|
- {:class (util/classnames [{:is-first (= 1 @*current-page)
|
|
|
- :is-last (= @*current-page total-pages)}])}
|
|
|
- [:a.py-4.pr-2 {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
|
|
|
- [:span.opacity-30 (str @*current-page "/" total-pages)]
|
|
|
- [:a.py-4.pl-2 {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]]]
|
|
|
-
|
|
|
- [:table.table-auto.cp__all_pages_table
|
|
|
- [:thead
|
|
|
- [:tr
|
|
|
- [:th.selector
|
|
|
- (checkbox-opt "all-pages-select-all"
|
|
|
- (= 1 @*indeterminate)
|
|
|
- {:on-change (fn []
|
|
|
- (let [indeterminate? (= -1 @*indeterminate)
|
|
|
- all? (= 1 @*indeterminate)]
|
|
|
- (doseq [{:block/keys [idx]} @*results]
|
|
|
- (swap! *checks assoc idx (or indeterminate? (not all?))))))
|
|
|
- :indeterminate (= -1 @*indeterminate)})]
|
|
|
-
|
|
|
- (sortable-title (t :block/name) :block/name *sort-by-item *desc?)
|
|
|
- (when-not mobile?
|
|
|
- [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?)
|
|
|
- (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?)
|
|
|
- (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]]
|
|
|
-
|
|
|
- [:tbody
|
|
|
- (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results]
|
|
|
- (when-not (string/blank? name)
|
|
|
- [:tr {:key name}
|
|
|
- [:td.selector
|
|
|
- (checkbox-opt (str "label-" idx)
|
|
|
- (get @*checks idx)
|
|
|
- {:on-change (fn []
|
|
|
- (swap! *checks update idx not))})]
|
|
|
-
|
|
|
- [:td.name [:a {:on-click (fn [e]
|
|
|
- (let [repo (state/get-current-repo)]
|
|
|
- (when (gobj/get e "shiftKey")
|
|
|
- (state/sidebar-add-block!
|
|
|
- repo
|
|
|
- (:db/id page)
|
|
|
- :page
|
|
|
- {:page (:block/name page)}))))
|
|
|
- :href (rfe/href :page {:name (:block/name page)})}
|
|
|
- (block/page-cp {} page)]]
|
|
|
-
|
|
|
- (when-not mobile?
|
|
|
- [:td.backlinks [:span backlinks]])
|
|
|
-
|
|
|
- (when-not mobile?
|
|
|
- [:td.created-at [:span (if created-at
|
|
|
- (date/int->local-time-2 created-at)
|
|
|
- "Unknown")]])
|
|
|
- (when-not mobile?
|
|
|
- [:td.updated-at [:span (if updated-at
|
|
|
- (date/int->local-time-2 updated-at)
|
|
|
- "Unknown")]])]))]]
|
|
|
+ [:a.ml-1.pr-2.opacity-70.hover:opacity-100 {:href (rfe/href :all-files)}
|
|
|
+ [:span
|
|
|
+ (ui/icon "files")
|
|
|
+ [:span.ml-1 (t :all-files)]]]
|
|
|
+
|
|
|
+ [:div
|
|
|
+ (ui/tippy
|
|
|
+ {:html [:small (str (t :page/show-journals) " ?")]
|
|
|
+ :arrow true}
|
|
|
+ [:a.button.journal
|
|
|
+ {:class (util/classnames [{:active (boolean @*journal?)}])
|
|
|
+ :on-click #(reset! *journal? (not @*journal?))}
|
|
|
+ (ui/icon "calendar")])]
|
|
|
|
|
|
[:div.paginates
|
|
|
- [:span]
|
|
|
+ [:span.flex.items-center.opacity-60.text-sm
|
|
|
+ [:span.pr-1 (t :paginates/pages (count @*results-all))]]
|
|
|
[:span.flex.items-center
|
|
|
{:class (util/classnames [{:is-first (= 1 @*current-page)
|
|
|
:is-last (= @*current-page total-pages)}])}
|
|
|
- [:a.py-4.text-sm {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
|
|
|
- [:a.py-4.pl-2.text-sm {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]])])))
|
|
|
+ [:a.py-4.pr-2 {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
|
|
|
+ [:span.opacity-30 (str @*current-page "/" total-pages)]
|
|
|
+ [:a.py-4.pl-2 {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]]]
|
|
|
+
|
|
|
+ [:table.table-auto.cp__all_pages_table
|
|
|
+ [:thead
|
|
|
+ [:tr
|
|
|
+ [:th.selector
|
|
|
+ (checkbox-opt "all-pages-select-all"
|
|
|
+ (= 1 @*indeterminate)
|
|
|
+ {:on-change (fn []
|
|
|
+ (let [indeterminate? (= -1 @*indeterminate)
|
|
|
+ all? (= 1 @*indeterminate)]
|
|
|
+ (doseq [{:block/keys [idx]} @*results]
|
|
|
+ (swap! *checks assoc idx (or indeterminate? (not all?))))))
|
|
|
+ :indeterminate (= -1 @*indeterminate)})]
|
|
|
+
|
|
|
+ (sortable-title (t :block/name) :block/name *sort-by-item *desc?)
|
|
|
+ (when-not mobile?
|
|
|
+ [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?)
|
|
|
+ (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?)
|
|
|
+ (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]]
|
|
|
+
|
|
|
+ [:tbody
|
|
|
+ (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results]
|
|
|
+ (when-not (string/blank? name)
|
|
|
+ [:tr {:key name}
|
|
|
+ [:td.selector
|
|
|
+ (checkbox-opt (str "label-" idx)
|
|
|
+ (get @*checks idx)
|
|
|
+ {:on-change (fn []
|
|
|
+ (swap! *checks update idx not))})]
|
|
|
+
|
|
|
+ [:td.name [:a {:on-click (fn [e]
|
|
|
+ (let [repo (state/get-current-repo)]
|
|
|
+ (when (gobj/get e "shiftKey")
|
|
|
+ (state/sidebar-add-block!
|
|
|
+ repo
|
|
|
+ (:db/id page)
|
|
|
+ :page
|
|
|
+ {:page (:block/name page)}))))
|
|
|
+ :href (rfe/href :page {:name (:block/name page)})}
|
|
|
+ (block/page-cp {} page)]]
|
|
|
+
|
|
|
+ (when-not mobile?
|
|
|
+ [:td.backlinks [:span backlinks]])
|
|
|
+
|
|
|
+ (when-not mobile?
|
|
|
+ [:td.created-at [:span (if created-at
|
|
|
+ (date/int->local-time-2 created-at)
|
|
|
+ "Unknown")]])
|
|
|
+ (when-not mobile?
|
|
|
+ [:td.updated-at [:span (if updated-at
|
|
|
+ (date/int->local-time-2 updated-at)
|
|
|
+ "Unknown")]])]))]]
|
|
|
+
|
|
|
+ [:div.paginates
|
|
|
+ [:span]
|
|
|
+ [:span.flex.items-center
|
|
|
+ {:class (util/classnames [{:is-first (= 1 @*current-page)
|
|
|
+ :is-last (= @*current-page total-pages)}])}
|
|
|
+ [:a.py-4.text-sm {:on-click #(to-page (dec @*current-page))} (ui/icon "caret-left") (str " " (t :paginates/prev))]
|
|
|
+ [:a.py-4.pl-2.text-sm {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") (ui/icon "caret-right")]]]])]))
|