| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 | (ns frontend.components.reference  (:require [frontend.components.block :as block]            [frontend.components.content :as content]            [frontend.components.editor :as editor]            [frontend.components.reference-filters :as filters]            [frontend.config :as config]            [frontend.context.i18n :refer [t]]            [frontend.db :as db]            [frontend.db-mixins :as db-mixins]            [frontend.db.async :as db-async]            [frontend.db.utils :as db-utils]            [frontend.handler.block :as block-handler]            [frontend.handler.page :as page-handler]            [frontend.modules.outliner.tree :as tree]            [frontend.search :as search]            [frontend.state :as state]            [frontend.ui :as ui]            [frontend.util :as util]            [logseq.shui.ui :as shui]            [promesa.core :as p]            [rum.core :as rum]))(rum/defc block-linked-references < rum/reactive db-mixins/query  {:init (fn [state]           (when-let [e (db/entity [:block/uuid (first (:rum/args state))])]             (db-async/<get-block-refs (state/get-current-repo) (:db/id e)))           state)}  [block-id]  (when-let [e (db/entity [:block/uuid block-id])]    (when-not (state/sub-async-query-loading (str (:db/id e) "-refs"))      (let [page? (some? (:block/name e))            ref-blocks (if page?                         (-> (db/get-page-referenced-blocks (:db/id e))                             db-utils/group-by-page)                         (db/get-block-referenced-blocks (:db/id e)))]        (when (> (count ref-blocks) 0)          (let [ref-hiccup (block/->hiccup ref-blocks                                           {:id (str block-id)                                            :ref? true                                            :breadcrumb-show? true                                            :group-by-page? true                                            :editor-box editor/box}                                           {})]            [:div.references-blocks             (content/content block-id                              {:hiccup ref-hiccup})]))))))(rum/defc references-inner  [page-name filters filtered-ref-blocks]  (let [*ref (rum/use-ref nil)]    [:div.references-blocks.faster.fade-in {:ref *ref}    (let [ref-hiccup (block/->hiccup filtered-ref-blocks                                     {:id page-name                                      :scroll-container *ref                                      :ref? true                                      :breadcrumb-show? true                                      :group-by-page? true                                      :editor-box editor/box                                      :filters filters}                                     {})]      (content/content page-name {:hiccup ref-hiccup}))]))(rum/defc references-cp  [page-entity page-name *filters total filter-n filtered-ref-blocks *ref-pages]  (let [filters @*filters        threshold (state/get-linked-references-collapsed-threshold)        default-collapsed? (>= total threshold)        *collapsed? (atom nil)]    (ui/foldable     [:div.flex.flex-row.flex-1.justify-between.items-center      [:h2.font-medium (t :linked-references/reference-count (when (or (seq (:included filters))                                                                       (seq (:excluded filters))) filter-n) total)]      [:a.filter.fade-link       {:title (t :linked-references/filter-heading)        :on-mouse-over (fn [_e]                         (when @*collapsed? ; collapsed                           ;; expand                           (reset! @*collapsed? false)))        :on-pointer-down (fn [e]                           (util/stop-propagation e)                           (shui/popup-show! (.-target e)                            (fn []                              [:div.p-4                               (filters/filter-dialog page-entity *filters *ref-pages)])                            {:align "end"}))}       (ui/icon "filter" {:class (cond                                   (and (empty? (:included filters)) (empty? (:excluded filters)))                                   "opacity-60 hover:opacity-100"                                   (and (seq (:included filters)) (empty? (:excluded filters)))                                   "text-success"                                   (and (empty? (:included filters)) (seq (:excluded filters)))                                   "text-error"                                   :else                                   "text-warning")                          :size  22})]]     (fn []       (references-inner page-name filters filtered-ref-blocks))     {:default-collapsed? default-collapsed?      :title-trigger? true      :init-collapsed (fn [collapsed-atom]                        (reset! *collapsed? collapsed-atom))})))(defn- get-filtered-children  [block parent->blocks]  (let [children (get parent->blocks (:db/id block))]    (set     (loop [blocks children            result (vec children)]       (if (empty? blocks)         result         (let [fb (first blocks)               children (get parent->blocks (:db/id fb))]           (recur            (concat children (rest blocks))            (conj result fb))))))))(rum/defc references-aux <  {:should-update (fn [old-state new-state]                    ;; Re-render if only filters update                    (not= (last (:rum/args old-state))                          (last (:rum/args new-state))))}  [state repo page-entity *filters filters]  (let [page-name (:block/name page-entity)        *ref-pages (::ref-pages state)        page-id (:db/id page-entity)        ref-blocks (db/get-page-referenced-blocks page-id)        aliases (db/page-alias-set repo page-id)        aliases-exclude-self (set (remove #{page-id} aliases))        top-level-blocks (filter (fn [b] (some aliases (set (map :db/id (:block/refs b))))) ref-blocks)        top-level-blocks-ids (set (map :db/id top-level-blocks))        filtered-ref-blocks (->> (block-handler/filter-blocks ref-blocks filters)                                 (block-handler/get-filtered-ref-blocks-with-parents ref-blocks))        total (count top-level-blocks)        filtered-top-blocks (filter (fn [b] (top-level-blocks-ids (:db/id b))) filtered-ref-blocks)        filter-n (count filtered-top-blocks)        parent->blocks (group-by (fn [x] (:db/id (x :block/parent))) filtered-ref-blocks)        result (->> (group-by :block/page filtered-top-blocks)                    (map (fn [[page blocks]]                           (let [blocks (sort-by (fn [b] (not= (:db/id page) (:db/id (:block/parent b)))) blocks)                                 result (map (fn [block]                                               (let [filtered-children (get-filtered-children block parent->blocks)                                                     refs (when-not (contains? top-level-blocks-ids (:db/id (:block/parent block)))                                                            (block-handler/get-blocks-refed-pages aliases (cons block filtered-children)))                                                     block' (assoc (tree/block-entity->map block) :block/children filtered-children)]                                                 [block' refs])) blocks)                                 blocks' (map first result)                                 page' (if (contains? aliases-exclude-self (:db/id page))                                         {:db/id (:db/id page)                                          :block/alias? true                                          :block/journal-day (:block/journal-day page)}                                         page)]                             [[page' blocks'] (mapcat second result)]))))        filtered-ref-blocks' (map first result)        ref-pages (->>                   (mapcat second result)                   (map :block/original-name)                   frequencies)]    (reset! *ref-pages ref-pages)    (when (or (seq (:included filters)) (seq (:excluded filters)) (> filter-n 0))      [:div.references.page-linked.flex-1.flex-row       [:div.content.pt-6        (references-cp page-entity page-name *filters total filter-n filtered-ref-blocks' *ref-pages)]])))(rum/defcs references* < rum/reactive db-mixins/query  (rum/local nil ::ref-pages)  {:init (fn [state]           (let [page (first (:rum/args state))]             (when page (db-async/<get-block-refs (state/get-current-repo) (:db/id page))))           (assoc state ::filters (atom nil)))}  [state page-entity]  (when page-entity    (let [repo (state/get-current-repo)          *filters (::filters state)]      (when page-entity        (when-not (state/sub-async-query-loading (str (:db/id page-entity) "-refs"))          (let [page-entity (db/sub-block (:db/id page-entity))                filters (page-handler/get-filters page-entity)                _ (when-not (= filters @*filters)                    (reset! *filters filters))]            (references-aux state repo page-entity *filters filters)))))))(rum/defc references  [page-entity]  (ui/catch-error   (ui/component-error (if (config/db-based-graph? (state/get-current-repo))                         "Linked References: Unexpected error."                         "Linked References: Unexpected error. Please re-index your graph first."))   (references* page-entity)))(rum/defcs unlinked-references-aux  < rum/reactive db-mixins/query  {:init   (fn [state]     (let [*result (atom nil)           [page *n-ref] (:rum/args state)]       (p/let [result (search/get-page-unlinked-refs (:db/id page))]         (reset! *n-ref (count result))         (reset! *result result))       (assoc state ::result *result)))}  [state page _n-ref]  (let [ref-blocks (rum/react (::result state))]    (when (seq ref-blocks)      [:div.references-blocks       (let [ref-hiccup (block/->hiccup ref-blocks                                        {:id (str (:block/original-name page) "-unlinked-")                                         :ref? true                                         :group-by-page? true                                         :editor-box editor/box}                                        {})]         (content/content (:block/name page)                          {:hiccup ref-hiccup}))])))(rum/defcs unlinked-references < rum/reactive  (rum/local nil ::n-ref)  [state page]  (let [n-ref (get state ::n-ref)]    (when page      [:div.references.page-unlinked.mt-6.flex-1.flex-row.faster.fade-in       [:div.content.flex-1        (ui/foldable         [:h2.font-medium (t :unlinked-references/reference-count @n-ref)]         (fn [] (unlinked-references-aux page n-ref))         {:default-collapsed? true          :title-trigger? true})]])))
 |