mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
enhance(cli): add --ref-id-footer in show cmd
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
:complete :pages}
|
||||
:linked-references {:desc "Include linked references (default true)"
|
||||
:coerce :boolean}
|
||||
:ref-id-footer {:desc "Show referenced entity id footer (default true)"
|
||||
:coerce :boolean}
|
||||
:level {:desc "Limit tree depth (default 10)"
|
||||
:coerce :long}})
|
||||
|
||||
@@ -454,12 +456,19 @@
|
||||
distinct
|
||||
vec)))
|
||||
|
||||
(defn- fetch-uuid-labels
|
||||
(defn- uuid-entity-label
|
||||
[entity]
|
||||
(let [uuid-str (some-> (:block/uuid entity) str)]
|
||||
(or (:block/title entity)
|
||||
(:block/name entity)
|
||||
uuid-str)))
|
||||
|
||||
(defn- fetch-uuid-entities
|
||||
[config repo uuid-strings]
|
||||
(if (seq uuid-strings)
|
||||
(p/let [blocks (p/all (map (fn [uuid-str]
|
||||
(transport/invoke config :thread-api/pull false
|
||||
[repo [:block/uuid :block/title :block/name]
|
||||
[repo [:db/id :block/uuid :block/title :block/name]
|
||||
[:block/uuid (uuid uuid-str)]]))
|
||||
uuid-strings))]
|
||||
(->> blocks
|
||||
@@ -467,7 +476,8 @@
|
||||
(map (fn [block]
|
||||
(let [uuid-str (some-> (:block/uuid block) str)]
|
||||
[(string/lower-case uuid-str)
|
||||
(or (:block/title block) (:block/name block) uuid-str)])))
|
||||
{:id (:db/id block)
|
||||
:label (uuid-entity-label block)}])))
|
||||
(into {})))
|
||||
(p/resolved {})))
|
||||
|
||||
@@ -847,6 +857,20 @@
|
||||
(linked-refs->text refs uuid->label property-titles property-value-labels))
|
||||
tree-text)))
|
||||
|
||||
(defn- referenced-entity-row
|
||||
[uuid uuid->entity]
|
||||
(let [{:keys [id label]} (get uuid->entity (string/lower-case uuid))
|
||||
id* (or id "-")
|
||||
label* (or label uuid)]
|
||||
(str id* " -> " label*)))
|
||||
|
||||
(defn- render-referenced-entities-footer
|
||||
[ordered-uuids uuid->entity]
|
||||
(let [ordered-uuids (vec (distinct (remove string/blank? ordered-uuids)))]
|
||||
(when (seq ordered-uuids)
|
||||
(str "Referenced Entities (" (count ordered-uuids) ")\n"
|
||||
(string/join "\n" (map #(referenced-entity-row % uuid->entity) ordered-uuids))))))
|
||||
|
||||
(defn build-action
|
||||
[options repo]
|
||||
(if-not (seq repo)
|
||||
@@ -875,6 +899,9 @@
|
||||
:linked-references? (if (contains? options :linked-references)
|
||||
(:linked-references options)
|
||||
true)
|
||||
:ref-id-footer? (if (contains? options :ref-id-footer)
|
||||
(:ref-id-footer options)
|
||||
true)
|
||||
:uuid (:uuid options)
|
||||
:page (:page options)
|
||||
:level (:level options)}})))))
|
||||
@@ -890,8 +917,16 @@
|
||||
(or linked-refs {:count 0 :blocks []})
|
||||
{:count 0 :blocks []})
|
||||
uuid-refs (collect-uuid-refs tree-data linked-refs*)
|
||||
uuid->label (fetch-uuid-labels config (:repo action) uuid-refs)
|
||||
tree-data (cond-> (assoc tree-data :uuid->label uuid->label)
|
||||
uuid->entity (fetch-uuid-entities config (:repo action) uuid-refs)
|
||||
uuid->label (->> uuid->entity
|
||||
(keep (fn [[uuid-key {:keys [label]}]]
|
||||
(when (seq label)
|
||||
[uuid-key label])))
|
||||
(into {}))
|
||||
tree-data (cond-> (assoc tree-data
|
||||
:referenced-uuids uuid-refs
|
||||
:uuid->entity uuid->entity
|
||||
:uuid->label uuid->label)
|
||||
linked-enabled? (assoc :linked-references linked-refs*))
|
||||
tree-data (resolve-uuid-refs-in-tree-data tree-data uuid->label)]
|
||||
tree-data))
|
||||
@@ -938,11 +973,25 @@
|
||||
entry))
|
||||
tree-data))
|
||||
|
||||
(defn- strip-show-internal-data
|
||||
[tree-data]
|
||||
(dissoc tree-data :referenced-uuids :uuid->entity))
|
||||
|
||||
(defn- render-tree-text
|
||||
[tree-data action]
|
||||
(if (false? (:linked-references? action))
|
||||
(tree->text tree-data)
|
||||
(tree->text-with-linked-refs tree-data)))
|
||||
(let [tree-text (if (false? (:linked-references? action))
|
||||
(tree->text tree-data)
|
||||
(tree->text-with-linked-refs tree-data))
|
||||
footer-enabled? (not= false (:ref-id-footer? action))
|
||||
linked-refs (when (not= false (:linked-references? action))
|
||||
(:linked-references tree-data))
|
||||
ordered-uuids (or (:referenced-uuids tree-data)
|
||||
(collect-uuid-refs tree-data linked-refs))
|
||||
footer (when footer-enabled?
|
||||
(render-referenced-entities-footer ordered-uuids (:uuid->entity tree-data)))]
|
||||
(if (seq footer)
|
||||
(str tree-text "\n\n" footer)
|
||||
tree-text)))
|
||||
|
||||
(defn- render-tree-text-with-properties
|
||||
[config action tree-data]
|
||||
@@ -981,7 +1030,9 @@
|
||||
(and ok? (contained? id)))
|
||||
results))
|
||||
sanitize-tree (fn [tree]
|
||||
(strip-block-uuid tree))
|
||||
(-> tree
|
||||
strip-show-internal-data
|
||||
strip-block-uuid))
|
||||
render-result (fn [{:keys [ok? tree id error]}]
|
||||
(if ok?
|
||||
(render-tree-text-with-properties cfg action tree)
|
||||
@@ -1011,13 +1062,17 @@
|
||||
(p/let [tree-data (build-tree-data cfg action)]
|
||||
(case format
|
||||
:edn
|
||||
(let [tree-data (strip-block-uuid tree-data)]
|
||||
(let [tree-data (-> tree-data
|
||||
strip-show-internal-data
|
||||
strip-block-uuid)]
|
||||
{:status :ok
|
||||
:data tree-data
|
||||
:output-format :edn})
|
||||
|
||||
:json
|
||||
(let [tree-data (strip-block-uuid tree-data)]
|
||||
(let [tree-data (-> tree-data
|
||||
strip-show-internal-data
|
||||
strip-block-uuid)]
|
||||
{:status :ok
|
||||
:data tree-data
|
||||
:output-format :json})
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
[cljs.test :refer [async deftest is testing]]
|
||||
[clojure.string :as string]
|
||||
[logseq.cli.command.show :as show-command]
|
||||
[logseq.cli.server :as cli-server]
|
||||
[logseq.cli.style :as style]
|
||||
[logseq.cli.transport :as transport]
|
||||
[promesa.core :as p]))
|
||||
|
||||
@@ -120,3 +122,184 @@
|
||||
(is (= "hello" (get-in result [10 :user.property/title]))))))
|
||||
(p/catch (fn [e] (is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(defn- call-private
|
||||
[sym & args]
|
||||
(when-let [v (get (ns-interns 'logseq.cli.command.show) sym)]
|
||||
(apply @v args)))
|
||||
|
||||
(defn- make-show-invoke-mock
|
||||
[{:keys [entities-by-id children-by-page-id uuid-entities linked-refs-by-root-id]}]
|
||||
(fn [_ method _ args]
|
||||
(case method
|
||||
:thread-api/pull
|
||||
(let [[_repo _selector target] args]
|
||||
(cond
|
||||
(number? target)
|
||||
(p/resolved (get entities-by-id target))
|
||||
|
||||
(and (vector? target) (= :block/uuid (first target)))
|
||||
(let [uuid-str (some-> (second target) str string/lower-case)]
|
||||
(p/resolved (get uuid-entities uuid-str)))
|
||||
|
||||
:else
|
||||
(p/resolved nil)))
|
||||
|
||||
:thread-api/q
|
||||
(let [[_repo query-args] args
|
||||
[_query & inputs] query-args]
|
||||
(if (= 1 (count inputs))
|
||||
(let [page-id (first inputs)
|
||||
blocks (get children-by-page-id page-id [])]
|
||||
(p/resolved (mapv vector blocks)))
|
||||
(p/resolved [])))
|
||||
|
||||
:thread-api/get-block-refs
|
||||
(let [[_repo root-id] args]
|
||||
(p/resolved (get linked-refs-by-root-id root-id [])))
|
||||
|
||||
(p/resolved nil))))
|
||||
|
||||
(deftest test-render-referenced-entities-footer
|
||||
(let [render-footer (fn [ordered-uuids uuid->entity]
|
||||
(call-private 'render-referenced-entities-footer ordered-uuids uuid->entity))
|
||||
u1 "11111111-1111-1111-1111-111111111111"
|
||||
u2 "22222222-2222-2222-2222-222222222222"
|
||||
u3 "33333333-3333-3333-3333-333333333333"]
|
||||
(testing "returns nil when no refs"
|
||||
(is (nil? (render-footer [] {}))))
|
||||
|
||||
(testing "renders ordered refs with id and label"
|
||||
(is (= (str "Referenced Entities (2)\n"
|
||||
"181 -> First child\n"
|
||||
"179 -> Root task")
|
||||
(render-footer [u1 u2]
|
||||
{(string/lower-case u1) {:id 181 :label "First child"}
|
||||
(string/lower-case u2) {:id 179 :label "Root task"}}))))
|
||||
|
||||
(testing "renders fallback rows for missing id/label and unresolved refs"
|
||||
(is (= (str "Referenced Entities (3)\n"
|
||||
"- -> Broken ref\n"
|
||||
"88 -> " u2 "\n"
|
||||
"- -> " u3)
|
||||
(render-footer [u1 u2 u3]
|
||||
{(string/lower-case u1) {:label "Broken ref"}
|
||||
(string/lower-case u2) {:id 88}}))))))
|
||||
|
||||
(deftest test-build-action-ref-id-footer
|
||||
(testing "ref-id-footer defaults to true"
|
||||
(let [result (show-command/build-action {:id "42"}
|
||||
"logseq_db_demo")]
|
||||
(is (true? (:ok? result)))
|
||||
(is (true? (get-in result [:action :ref-id-footer?])))))
|
||||
|
||||
(testing "ref-id-footer false is threaded into action"
|
||||
(let [result (show-command/build-action {:id "42"
|
||||
:ref-id-footer false}
|
||||
"logseq_db_demo")]
|
||||
(is (true? (:ok? result)))
|
||||
(is (false? (get-in result [:action :ref-id-footer?]))))))
|
||||
|
||||
(deftest test-execute-show-human-ref-id-footer-default-enabled
|
||||
(async done
|
||||
(let [resolved-uuid "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||
missing-uuid "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
|
||||
invoke-mock (make-show-invoke-mock
|
||||
{:entities-by-id {1 {:db/id 1
|
||||
:block/title (str "Root [[" resolved-uuid "]] [[" missing-uuid "]]")
|
||||
:block/page {:db/id 100}}}
|
||||
:children-by-page-id {100 [{:db/id 2
|
||||
:block/title "Child"
|
||||
:block/order 0
|
||||
:block/parent {:db/id 1}}]}
|
||||
:uuid-entities {(string/lower-case resolved-uuid)
|
||||
{:db/id 179
|
||||
:block/uuid (uuid resolved-uuid)
|
||||
:block/title "Root task"}}})]
|
||||
(-> (p/with-redefs [cli-server/ensure-server! (fn [config _] config)
|
||||
transport/invoke invoke-mock]
|
||||
(p/let [result (show-command/execute-show {:type :show
|
||||
:repo "demo"
|
||||
:id 1
|
||||
:linked-references? false}
|
||||
{:output-format nil})
|
||||
plain (-> result :data :message style/strip-ansi)]
|
||||
(is (= :ok (:status result)))
|
||||
(is (string/includes? plain "Referenced Entities (2)"))
|
||||
(is (string/includes? plain "179 -> Root task"))
|
||||
(is (string/includes? plain (str "- -> " missing-uuid)))))
|
||||
(p/catch (fn [e] (is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest test-execute-show-human-ref-id-footer-multi-id
|
||||
(async done
|
||||
(let [uuid-a "cccccccc-cccc-cccc-cccc-cccccccccccc"
|
||||
uuid-b "dddddddd-dddd-dddd-dddd-dddddddddddd"
|
||||
invoke-mock (make-show-invoke-mock
|
||||
{:entities-by-id {1 {:db/id 1
|
||||
:block/title "Root A"
|
||||
:block/page {:db/id 101}}
|
||||
2 {:db/id 2
|
||||
:block/title "Root B"
|
||||
:block/page {:db/id 102}}}
|
||||
:children-by-page-id {101 [{:db/id 11
|
||||
:block/title (str "Child A [[" uuid-a "]]")
|
||||
:block/order 0
|
||||
:block/parent {:db/id 1}}]
|
||||
102 [{:db/id 22
|
||||
:block/title (str "Child B [[" uuid-b "]]")
|
||||
:block/order 0
|
||||
:block/parent {:db/id 2}}]}
|
||||
:uuid-entities {(string/lower-case uuid-a)
|
||||
{:db/id 501
|
||||
:block/uuid (uuid uuid-a)
|
||||
:block/title "Ref A"}
|
||||
(string/lower-case uuid-b)
|
||||
{:db/id 502
|
||||
:block/uuid (uuid uuid-b)
|
||||
:block/title "Ref B"}}})]
|
||||
(-> (p/with-redefs [cli-server/ensure-server! (fn [config _] config)
|
||||
transport/invoke invoke-mock]
|
||||
(p/let [result (show-command/execute-show {:type :show
|
||||
:repo "demo"
|
||||
:ids [1 2]
|
||||
:multi-id? true
|
||||
:linked-references? false}
|
||||
{:output-format nil})
|
||||
plain (-> result :data :message style/strip-ansi)
|
||||
footer-count (count (re-seq #"Referenced Entities \(1\)" plain))]
|
||||
(is (= :ok (:status result)))
|
||||
(is (= 2 footer-count))
|
||||
(is (string/includes? plain "501 -> Ref A"))
|
||||
(is (string/includes? plain "502 -> Ref B"))))
|
||||
(p/catch (fn [e] (is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest test-execute-show-human-ref-id-footer-disabled
|
||||
(async done
|
||||
(let [uuid-a "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"
|
||||
invoke-mock (make-show-invoke-mock
|
||||
{:entities-by-id {1 {:db/id 1
|
||||
:block/title "Root"
|
||||
:block/page {:db/id 201}}}
|
||||
:children-by-page-id {201 [{:db/id 12
|
||||
:block/title (str "Child [[" uuid-a "]]")
|
||||
:block/order 0
|
||||
:block/parent {:db/id 1}}]}
|
||||
:uuid-entities {(string/lower-case uuid-a)
|
||||
{:db/id 601
|
||||
:block/uuid (uuid uuid-a)
|
||||
:block/title "Ref A"}}})]
|
||||
(-> (p/with-redefs [cli-server/ensure-server! (fn [config _] config)
|
||||
transport/invoke invoke-mock]
|
||||
(p/let [result (show-command/execute-show {:type :show
|
||||
:repo "demo"
|
||||
:id 1
|
||||
:linked-references? false
|
||||
:ref-id-footer? false}
|
||||
{:output-format nil})
|
||||
plain (-> result :data :message style/strip-ansi)]
|
||||
(is (= :ok (:status result)))
|
||||
(is (not (string/includes? plain "Referenced Entities (")))))
|
||||
(p/catch (fn [e] (is false (str "unexpected error: " e))))
|
||||
(p/finally done)))))
|
||||
|
||||
@@ -1303,10 +1303,16 @@
|
||||
(is (false? (:ok? result)))
|
||||
(is (= :invalid-options (get-in result [:error :code])))))
|
||||
|
||||
(testing "show help lists linked references option"
|
||||
(testing "show parses ref-id-footer option"
|
||||
(let [result (commands/parse-args ["show" "--page" "Home" "--ref-id-footer" "false"])]
|
||||
(is (true? (:ok? result)))
|
||||
(is (= false (get-in result [:options :ref-id-footer])))))
|
||||
|
||||
(testing "show help lists linked references and ref-id-footer options"
|
||||
(let [summary (:summary (binding [style/*color-enabled?* true]
|
||||
(commands/parse-args ["show" "--help"])))]
|
||||
(is (string/includes? (strip-ansi summary) "--linked-references")))))
|
||||
(is (string/includes? (strip-ansi summary) "--linked-references"))
|
||||
(is (string/includes? (strip-ansi summary) "--ref-id-footer")))))
|
||||
|
||||
(deftest test-verb-subcommand-parse-query
|
||||
(testing "query shows group help"
|
||||
|
||||
Reference in New Issue
Block a user