diff --git a/deps/cli/src/logseq/cli/commands/graph.cljs b/deps/cli/src/logseq/cli/commands/graph.cljs index 73e5a0b00c..eb764d5525 100644 --- a/deps/cli/src/logseq/cli/commands/graph.cljs +++ b/deps/cli/src/logseq/cli/commands/graph.cljs @@ -38,6 +38,6 @@ (defn list-graphs [] (let [db-graphs (->> (cli-common-graph/get-db-based-graphs) - (map #(string/replace-first % common-config/db-version-prefix "")) + (map common-config/strip-leading-db-version-prefix) sort)] - (println (string/join "\n" db-graphs)))) \ No newline at end of file + (println (string/join "\n" db-graphs)))) diff --git a/deps/cli/src/logseq/cli/common/graph.cljs b/deps/cli/src/logseq/cli/common/graph.cljs index 87644110f2..d8f636cf09 100644 --- a/deps/cli/src/logseq/cli/common/graph.cljs +++ b/deps/cli/src/logseq/cli/common/graph.cljs @@ -27,5 +27,7 @@ (remove (fn [s] (= s common-config/unlinked-graphs-dir))) (map graph-name->path) (keep (fn [s] - (when-not (string/starts-with? s common-config/file-version-prefix) - (str common-config/db-version-prefix s))))))) + (when (and (string? s) + (not (string/starts-with? s common-config/file-version-prefix))) + (common-config/canonicalize-db-version-repo s)))) + distinct))) diff --git a/deps/common/src/logseq/common/config.cljs b/deps/common/src/logseq/common/config.cljs index f1b297a624..565a05feca 100644 --- a/deps/common/src/logseq/common/config.cljs +++ b/deps/common/src/logseq/common/config.cljs @@ -33,6 +33,25 @@ (defonce db-version-prefix "logseq_db_") (defonce file-version-prefix "logseq_local_") +(defn strip-leading-db-version-prefix + "Strip exactly one leading db prefix for user-facing display values." + [s] + (if (and (string? s) + (string/starts-with? s db-version-prefix)) + (subs s (count db-version-prefix)) + s)) + +(defn canonicalize-db-version-repo + "Normalize any repo/graph name to exactly one leading db prefix." + [s] + (when (seq s) + (let [s (str s) + stripped (loop [name s] + (if (string/starts-with? name db-version-prefix) + (recur (subs name (count db-version-prefix))) + name))] + (str db-version-prefix stripped)))) + (defonce local-assets-dir "assets") (defonce unlinked-graphs-dir "Unlinked graphs") diff --git a/docs/agent-guide/040-hide-db-prefix-in-user-visible-graph-names.md b/docs/agent-guide/040-hide-db-prefix-in-user-visible-graph-names.md new file mode 100644 index 0000000000..1b338148c3 --- /dev/null +++ b/docs/agent-guide/040-hide-db-prefix-in-user-visible-graph-names.md @@ -0,0 +1,204 @@ +# Hide Db Prefix In User Visible Graph Names Implementation Plan + +Goal: Ensure user-visible graph names strip exactly one leading `logseq_db_` prefix while preventing new multi-prefix repos from being created. + +Architecture: Keep display normalization as single-pass prefix stripping for web, Electron, and CLI user-facing fields. + +Architecture: Add shared canonicalization at ingestion and graph-discovery boundaries so internal repo identifiers are normalized to exactly one leading prefix before persistence and routing. + +Architecture: Follow `@test-driven-development` with failing tests first across frontend, Electron boundary code, RTC ingestion, and CLI paths. + +Tech Stack: ClojureScript, Rum, Electron IPC, db-worker-node runtime, Logseq CLI formatting pipeline, Babashka tests. + +Related: Relates to `docs/agent-guide/033-desktop-db-worker-node-backend.md`. + +Related: Builds on `docs/agent-guide/038-electron-db-worker-switch-graph.md`. + +## Problem statement + +Graph names shown in the web graph list can expose `logseq_db_` when the stored repo value has multiple leading prefixes. + +Current rendering logic intentionally strips only one leading prefix, so malformed values like `logseq_db_logseq_db_demo` still render as `logseq_db_demo`. + +The product decision is to keep one-layer stripping behavior and fix the upstream causes that create multi-prefix repo identifiers. + +Multi-prefix data can enter through legacy disk graph discovery, Electron graph mapping, RTC remote metadata ingestion, and CLI graph-name conversion paths. + +The required outcome is stable single-prefix internal repo identifiers plus single-pass display normalization, so normal graphs render as `demo` and malformed legacy doubles render as `logseq_db_demo`. + +## Current and target normalization path + +```text +Current path with multi-prefix source data. +input repo: logseq_db_logseq_db_demo + -> display helper strips once + -> output: logseq_db_demo + -> user-visible prefix leak occurs. + +Target path with source canonicalization + single-pass display stripping. +ingress repo: logseq_db_logseq_db_demo + -> canonicalize to one internal prefix: logseq_db_demo + -> display helper strips once + -> output: demo + +Legacy persisted double-prefix fallback path (no migration). +input repo from old state: logseq_db_logseq_db_demo + -> display helper strips once + -> output: logseq_db_demo +``` + +## Testing Plan + +I will follow `@test-driven-development` and write all failing tests before implementation. + +I will add frontend unit tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/util/text_test.cljs` to assert single-pass prefix stripping behavior. + +I will add frontend persist tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/db/persist_test.cljs` to assert merged graph sources are canonicalized to one internal prefix before UI state usage. + +I will add RTC tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/handler/db_based/rtc_test.cljs` to assert remote graph payload ingestion cannot create local double-prefix repos. + +I will extend CLI formatter tests in `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/format_test.cljs` to assert user-facing fields strip exactly one prefix and never introduce additional prefixes. + +I will extend CLI command tests in `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/commands_test.cljs` for `graph list` and server output paths with unprefixed and prefix-like graph names, and assert prefix-like `--repo` values are treated as graph-name content instead of invalid input. + +I will add legacy graph discovery tests in `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/common/graph_test.cljs` to verify old directory names do not produce multi-prefix repo ids. + +I will run focused tests after RED and GREEN phases, then run `bb dev:lint-and-test` before completion. + +I will review changes against `@prompts/review.md` before merge. + +NOTE: I will write all tests before I add any implementation behavior. + +## Implementation plan + +### Phase 1: Add failing tests for one-layer display stripping and multi-prefix prevention. + +1. Add failing unit tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/util/text_test.cljs` for `logseq_db_demo -> demo`, `logseq_db_logseq_db_demo -> logseq_db_demo`, and middle-substring preservation. +2. Add failing tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/db/persist_test.cljs` to verify worker and Electron graph sources are canonicalized to one internal prefix. +3. Add failing tests in `/Users/rcmerci/gh-repos/logseq/src/test/frontend/handler/db_based/rtc_test.cljs` for remote graph mapping and download paths with prefixed and double-prefixed payload names. +4. Extend `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/format_test.cljs` with failing cases where `:repo` or `:graph` includes one or two prefixes and output uses one-layer stripping only. +5. Extend `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/commands_test.cljs` with failing cases for graph list and server output using unprefixed and prefix-like `--repo` values, and assert prefix-like values are not rejected by argument validation. +6. Add failing tests in `/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/common/graph_test.cljs` for legacy directory names that already contain `logseq_db_`. +7. Run focused tests and confirm failures reflect behavior gaps rather than setup errors. + +### Phase 2: Implement shared helpers for display normalization and repo canonicalization. + +8. Add shared helpers in `/Users/rcmerci/gh-repos/logseq/deps/common/src/logseq/common/config.cljs` for single-pass display stripping and exact-one-prefix canonicalization. +9. Keep display helper semantics strict to remove only one leading prefix and preserve all middle substrings. +10. Keep canonicalization helper semantics strict to collapse any number of leading prefixes to exactly one. +11. Use function names that clearly separate display behavior from internal repo id normalization. +12. Keep helpers pure and dependency-light so they can be reused in frontend, Electron, and CLI namespaces. + +### Phase 3: Apply web app fixes with one-layer display semantics. + +13. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/util/text.cljs` so `get-graph-name-from-path` calls the shared single-pass display helper. +14. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/config.cljs` so `db-graph-name` remains one-layer stripping and does not over-strip. +15. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/db/conn.cljs` so `get-short-repo-name` uses shared one-layer display normalization. +16. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/components/repo.cljs` rendering paths only if needed to ensure all user-visible labels share one-layer stripping behavior. +17. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/db/persist.cljs` so merged graph sources are canonicalized to one internal prefix before entering repo state. +18. Keep `data-testid` and internal routing keys unchanged unless canonicalization is required to prevent multi-prefix key creation. + +### Phase 4: Fix Electron and graph discovery paths that can create multi-prefix repos. + +19. Update `/Users/rcmerci/gh-repos/logseq/deps/cli/src/logseq/cli/common/graph.cljs` so `get-db-based-graphs` canonicalizes discovered graph repo names to one prefix. +20. Update `/Users/rcmerci/gh-repos/logseq/src/electron/electron/handler.cljs` and `/Users/rcmerci/gh-repos/logseq/src/electron/electron/utils.cljs` to canonicalize repo identifiers at IPC mapping boundaries. +21. Verify Electron IPC `getGraphs` keeps stable internal repo identifiers and no path emits new double-prefixed repos. + +### Phase 5: Fix RTC ingestion paths that can reintroduce multi-prefix repos. + +22. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/handler/db_based/rtc.cljs` so remote graph payload mapping canonicalizes incoming graph names before repo/url construction. +23. Update `/Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/rtc/full_upload_download_graph.cljs` so download naming canonicalizes to one internal prefix before local repo creation. +24. Ensure existing graphs with prefixed remote names remain accessible after normalization. +25. Ensure new uploads and downloads cannot create `logseq_db_logseq_db_*` local repo ids. + +### Phase 6: Apply CLI fixes for one-layer display and one-prefix internal ids. + +26. Update `/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/core.cljs` so `repo->graph` strips exactly one leading prefix for user-visible output. +27. Verify `/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/format.cljs` uses one-layer display normalization consistently for human, JSON, and EDN user-facing graph fields. +28. Update `/Users/rcmerci/gh-repos/logseq/deps/cli/src/logseq/cli/commands/graph.cljs` to canonicalize internal repo identifiers before list rendering and server-target resolution. +29. Ensure CLI parsing and command execution treat `--repo` as a graph-name string, so leading `logseq_db_` is interpreted as part of graph name when present and is not rejected by input validation. + +### Phase 7: Verification and release gate. + +30. Run `bb dev:test -v 'frontend.util.text-test'` and confirm one-layer strip behavior and canonicalization tests pass. +31. Run `bb dev:test -v 'frontend.db.persist-test'` and confirm merged-source canonicalization behavior is stable. +32. Run `bb dev:test -v 'frontend.handler.db-based.rtc-test'` and confirm remote ingestion cannot produce multi-prefix repos. +33. Run `bb dev:test -v 'logseq.cli.format-test'` and confirm CLI display fields apply one-layer strip behavior. +34. Run `bb dev:test -v 'logseq.cli.commands-test'` and confirm graph command behavior remains stable with unprefixed and prefix-like `--repo` input. +35. Run `bb dev:test -v 'logseq.cli.common.graph-test'` and confirm legacy graph discovery does not emit double-prefixed repo names. +36. Run `bb dev:lint-and-test` and confirm `0 failures, 0 errors`. +37. Perform a manual graph-list smoke check on web and Electron to confirm normal graphs display without prefix and legacy doubles display with one remaining prefix. +38. Perform a manual CLI smoke check with `logseq graph list`, `logseq server status --repo demo`, and `logseq server status --repo logseq_db_demo` to confirm both inputs are accepted as graph names. + +## Edge cases + +| Scenario | Expected behavior | +|---|---| +| Internal repo is `logseq_db_demo`. | User-visible name is `demo`. | +| Internal repo is `logseq_db_logseq_db_demo`. | User-visible name is `logseq_db_demo`. | +| Graph name contains middle substring like `my_logseq_db_notes`. | Middle substring is preserved and only one leading prefix is removed when present. | +| Legacy disk directory is named `logseq_db_demo`. | Discovery canonicalization keeps exactly one prefix and does not create `logseq_db_logseq_db_demo`. | +| Legacy disk directory is named `logseq_db_logseq_db_demo`. | Discovery canonicalization collapses to internal repo `logseq_db_demo`. | +| Remote graph payload returns `graph-name` as `logseq_db_demo`. | RTC mapping keeps internal repo `logseq_db_demo` and user-visible name `demo`. | +| Remote graph payload returns `graph-name` as `logseq_db_logseq_db_demo`. | RTC mapping canonicalizes to internal repo `logseq_db_demo`, and user-visible name is `demo` after one-layer display strip. | +| CLI receives `--repo demo`. | Command works and output graph name is `demo`. | +| CLI receives `--repo logseq_db_demo`. | Command treats `logseq_db_` as part of graph name and does not fail argument validation. | +| CLI receives `--repo logseq_db_logseq_db_demo`. | Command treats the full value as graph name content and does not fail argument validation. | +| Non-user-visible fields like `data-testid` include repo id. | Existing selectors remain unchanged unless canonicalization is required to prevent duplicate graph entries. | + +## Verification commands and expected outputs + +```bash +bb dev:test -v 'frontend.util.text-test' +bb dev:test -v 'frontend.db.persist-test' +bb dev:test -v 'frontend.handler.db-based.rtc-test' +bb dev:test -v 'logseq.cli.format-test' +bb dev:test -v 'logseq.cli.commands-test' +bb dev:test -v 'logseq.cli.common.graph-test' +bb dev:lint-and-test +``` + +Each command should finish with `0 failures, 0 errors`. + +Web and Electron manual checks should show no new multi-prefix repo entries. + +Web and Electron display should strip one prefix only at render time. + +CLI human output should match one-layer strip semantics, and CLI `--repo` should treat prefix-like values as normal graph names. + +## Testing Details + +The tests verify user-visible behavior and repo-id canonicalization at ingress and discovery boundaries. + +Frontend tests assert display output and merged-state behavior rather than helper internals alone. + +RTC and Electron tests assert that incoming prefixed names cannot generate additional prefixes in local repo ids. + +CLI tests assert command behavior and output formatting remain stable for unprefixed and prefix-like graph-name input. + +## Implementation Details + +- Keep display normalization as single-pass prefix stripping. +- Add one shared helper for exact-one-prefix repo canonicalization. +- Canonicalize ingress and discovery data before it reaches persistent repo state. +- Reuse shared helpers across frontend, Electron, and CLI. +- Preserve `data-testid` compatibility unless canonicalization makes key updates unavoidable. +- Avoid one-time metadata migration for existing persisted graphs. +- Treat CLI `--repo` input as raw graph name where `logseq_db_` may be part of the name. +- Keep internal thread-api contracts based on prefixed repo ids. +- Follow `@test-driven-development` for RED, GREEN, and REFACTOR order. +- Validate final patch with `@prompts/review.md` checklist. + +## Question + +Decision: Display normalization removes only one leading prefix, so `logseq_db_logseq_db_xxxx` displays as `logseq_db_xxxx` in app surfaces that read legacy uncanonicalized values. + +Decision: The implementation focus is to identify and fix all paths that can create multi-prefix repo identifiers, so newly produced data stays canonical. + +Decision: This change does not include a one-time metadata migration for existing persisted legacy values. + +Decision: CLI `--repo` option treats leading `logseq_db_` as graph-name content, not as forbidden prefix. + +Decision: Treat `data-testid` stability as a strict compatibility requirement for `clj-e2e`. + +--- diff --git a/src/electron/electron/handler.cljs b/src/electron/electron/handler.cljs index 9379140af4..3453f88f8c 100644 --- a/src/electron/electron/handler.cljs +++ b/src/electron/electron/handler.cljs @@ -29,6 +29,7 @@ [electron.window :as win] [electron.graph-switch-flow :as graph-switch-flow] [logseq.cli.common.graph :as cli-common-graph] + [logseq.common.config :as common-config] [logseq.common.graph :as common-graph] [logseq.db.sqlite.util :as sqlite-util] [promesa.core :as p])) @@ -200,24 +201,30 @@ [] (distinct (cli-common-graph/get-db-based-graphs))) +(defn- canonical-repo + [graph] + (common-config/canonicalize-db-version-repo graph)) + ;; TODO support alias mechanism (defn get-graph-name "Given a graph's name of string, returns the graph's fullname. For example, given `cat`, returns `logseq_db_cat`. Returns `nil` if no such graph exists." [graph-identifier] - (->> (get-graphs) - (some #(when (or - (= (utils/normalize-lc %) (utils/normalize-lc (str sqlite-util/db-version-prefix graph-identifier))) - (string/ends-with? (utils/normalize-lc %) - (str "/" (utils/normalize-lc graph-identifier)))) - %)))) + (when-let [repo (canonical-repo graph-identifier)] + (let [graph-name (common-config/strip-leading-db-version-prefix repo)] + (->> (get-graphs) + (some #(when (or + (= (utils/normalize-lc %) (utils/normalize-lc repo)) + (string/ends-with? (utils/normalize-lc %) + (str "/" (utils/normalize-lc graph-name)))) + %)))))) (defmethod handle :getGraphs [_window [_]] (get-graphs)) (defmethod handle :deleteGraph [_window [_ graph]] - (when graph - (db/unlink-graph! graph))) + (when-let [repo (canonical-repo graph)] + (db/unlink-graph! repo))) ;; DB related IPCs start @@ -228,20 +235,22 @@ (defmethod handle :db-worker-runtime [^js window [_ repo]] (if (string/blank? repo) (p/rejected (ex-info "repo is required" {:code :missing-repo})) - (db-worker/ensure-runtime! repo (.-id window)))) + (db-worker/ensure-runtime! (canonical-repo repo) (.-id window)))) (defmethod handle :db-export [_window [_ repo data]] - (logger/warn ::db-export-compat - {:repo repo - :message "legacy db-export IPC path invoked; desktop should use db-worker runtime"}) - (db/ensure-graph-dir! repo) - (db/save-db! repo data)) + (when-let [repo (canonical-repo repo)] + (logger/warn ::db-export-compat + {:repo repo + :message "legacy db-export IPC path invoked; desktop should use db-worker runtime"}) + (db/ensure-graph-dir! repo) + (db/save-db! repo data))) (defmethod handle :db-get [_window [_ repo]] - (logger/warn ::db-get-compat - {:repo repo - :message "legacy db-get IPC path invoked; desktop should use db-worker runtime"}) - (db/get-db repo)) + (when-let [repo (canonical-repo repo)] + (logger/warn ::db-get-compat + {:repo repo + :message "legacy db-get IPC path invoked; desktop should use db-worker runtime"}) + (db/get-db repo))) ;; DB related IPCs End diff --git a/src/electron/electron/utils.cljs b/src/electron/electron/utils.cljs index cbb26caf46..8d9f26f596 100644 --- a/src/electron/electron/utils.cljs +++ b/src/electron/electron/utils.cljs @@ -7,7 +7,7 @@ [electron.configs :as cfgs] [electron.logger :as logger] [logseq.cli.common.graph :as cli-common-graph] - [logseq.db.sqlite.util :as sqlite-util] + [logseq.common.config :as common-config] [promesa.core :as p])) (defonce *win (atom nil)) ;; The main window @@ -240,14 +240,17 @@ (defn get-graph-dir "required by all internal state in the electron section" [graph-name] - (when (string/starts-with? graph-name sqlite-util/db-version-prefix) - (node-path/join (cli-common-graph/get-db-graphs-dir) (string/replace-first graph-name sqlite-util/db-version-prefix "")))) + (when (and (string? graph-name) + (string/starts-with? graph-name common-config/db-version-prefix)) + (let [repo (common-config/canonicalize-db-version-repo graph-name)] + (node-path/join (cli-common-graph/get-db-graphs-dir) + (common-config/strip-leading-db-version-prefix repo))))) (comment (defn get-graph-name "Reverse `get-graph-dir`" [graph-dir] - (str sqlite-util/db-version-prefix (node-path/basename graph-dir)))) + (str common-config/db-version-prefix (node-path/basename graph-dir)))) (defn decode-protected-assets-schema-path [schema-path] diff --git a/src/main/frontend/config.cljs b/src/main/frontend/config.cljs index 832c98732f..9396d9c4c3 100644 --- a/src/main/frontend/config.cljs +++ b/src/main/frontend/config.cljs @@ -238,7 +238,7 @@ (defn db-graph-name [repo-with-prefix] - (string/replace-first repo-with-prefix db-version-prefix "")) + (common-config/strip-leading-db-version-prefix repo-with-prefix)) (defn db-based-graph? ([] @@ -257,7 +257,7 @@ (path/path-join (get-in @state/state [:system/info :home-dir]) "logseq" "graphs" - (string/replace repo db-version-prefix ""))) + (db-graph-name repo))) (defn get-electron-backup-dir [repo] @@ -269,7 +269,7 @@ (if (util/electron?) (get-local-dir repo-url) (str "memory:///" - (string/replace-first repo-url db-version-prefix ""))))) + (db-graph-name repo-url))))) (defn get-repo-config-path [] diff --git a/src/main/frontend/db/conn.cljs b/src/main/frontend/db/conn.cljs index f74f76967b..3ef5ab6f58 100644 --- a/src/main/frontend/db/conn.cljs +++ b/src/main/frontend/db/conn.cljs @@ -1,7 +1,6 @@ (ns frontend.db.conn "Contains db connections." - (:require [clojure.string :as string] - [datascript.core :as d] + (:require [datascript.core :as d] [frontend.config :as config] [frontend.db.conn-state :as db-conn-state] [frontend.mobile.util :as mobile-util] @@ -52,7 +51,7 @@ :else repo-name)] (if (config/db-based-graph? repo-name') - (string/replace-first repo-name' config/db-version-prefix "") + (config/db-graph-name repo-name') repo-name'))) (defn remove-conn! diff --git a/src/main/frontend/db/persist.cljs b/src/main/frontend/db/persist.cljs index 156c3333fb..7e170a63a0 100644 --- a/src/main/frontend/db/persist.cljs +++ b/src/main/frontend/db/persist.cljs @@ -3,7 +3,6 @@ (:require [cljs-bean.core :as bean] [clojure.string :as string] [electron.ipc :as ipc] - [frontend.config :as config] [frontend.persist-db :as persist-db] [frontend.util :as util] [logseq.common.config :as common-config] @@ -23,12 +22,13 @@ (map (fn [{:keys [name] :as repo}] (assoc repo :name - (str config/db-version-prefix name))))) + (common-config/canonicalize-db-version-repo name))))) electron-disk-graphs (when (util/electron?) (ipc/ipc "getGraphs"))] (distinct (concat repos' - (map (fn [repo-name] {:name repo-name}) + (map (fn [repo-name] + {:name (common-config/canonicalize-db-version-repo repo-name)}) (some-> electron-disk-graphs bean/->clj)))))) (defn delete-graph! diff --git a/src/main/frontend/handler/db_based/sync.cljs b/src/main/frontend/handler/db_based/sync.cljs index 0443e72b92..7d4e0544b3 100644 --- a/src/main/frontend/handler/db_based/sync.cljs +++ b/src/main/frontend/handler/db_based/sync.cljs @@ -9,6 +9,7 @@ [frontend.state :as state] [frontend.util :as util] [lambdaisland.glogi :as log] + [logseq.common.config :as common-config] [logseq.db :as ldb] [logseq.db-sync.malli-schema :as db-sync-schema] [logseq.db.sqlite.util :as sqlite-util] @@ -286,7 +287,7 @@ (if base (p/let [_ (js/Promise. user-handler/task--ensure-id&access-token) body (coerce-http-request :graphs/create - {:graph-name (string/replace repo config/db-version-prefix "") + {:graph-name (common-config/strip-leading-db-version-prefix repo) :schema-version schema-version :graph-e2ee? graph-e2ee?}) result (if (nil? body) @@ -334,15 +335,15 @@ ([graph-name graph-uuid graph-e2ee?] (state/set-state! :rtc/downloading-graph-uuid graph-uuid) (state/pub-event! - [:rtc/log {:type :rtc.log/download + [:rtc/log {:type :rtc.log/download :sub-type :download-progress :graph-uuid graph-uuid :message "Preparing graph snapshot download"}]) (let [graph-e2ee? (normalize-graph-e2ee? graph-e2ee?) + graph (common-config/canonicalize-db-version-repo graph-name) base (http-base)] (-> (if (and graph-uuid base) (-> (p/let [_ (js/Promise. user-handler/task--ensure-id&access-token) - graph (str config/db-version-prefix graph-name) pull-resp (fetch-json (str base "/sync/" graph-uuid "/pull") {:method "GET"} {:response-schema :sync/pull}) @@ -398,12 +399,14 @@ {:response-schema :graphs/list}) graphs (:graphs resp) result (mapv (fn [graph] - (let [graph-e2ee? (if (contains? graph :graph-e2ee?) + (let [repo (common-config/canonicalize-db-version-repo (:graph-name graph)) + graph-name (common-config/strip-leading-db-version-prefix repo) + graph-e2ee? (if (contains? graph :graph-e2ee?) (normalize-graph-e2ee? (:graph-e2ee? graph)) true)] (merge - {:url (str config/db-version-prefix (:graph-name graph)) - :GraphName (:graph-name graph) + {:url repo + :GraphName graph-name :GraphSchemaVersion (:schema-version graph) :GraphUUID (:graph-id graph) :rtc-graph? true diff --git a/src/main/frontend/util/text.cljs b/src/main/frontend/util/text.cljs index c9a9135059..7c3255d564 100644 --- a/src/main/frontend/util/text.cljs +++ b/src/main/frontend/util/text.cljs @@ -101,4 +101,4 @@ On iOS, repo-url might be nil" [repo-url] (when (not-empty repo-url) - (string/replace-first repo-url config/db-version-prefix ""))) + (config/db-graph-name repo-url))) diff --git a/src/main/logseq/cli/command/core.cljs b/src/main/logseq/cli/command/core.cljs index 94ab0db180..351b7e06f6 100644 --- a/src/main/logseq/cli/command/core.cljs +++ b/src/main/logseq/cli/command/core.cljs @@ -210,15 +210,14 @@ (defn graph->repo [graph] - (when (seq graph) - (if (string/starts-with? graph common-config/db-version-prefix) - graph - (str common-config/db-version-prefix graph)))) + (some-> graph + string/trim + common-config/canonicalize-db-version-repo)) (defn repo->graph [repo] (when (seq repo) - (string/replace-first repo common-config/db-version-prefix ""))) + (common-config/strip-leading-db-version-prefix repo))) (defn resolve-repo [graph] diff --git a/src/test/frontend/db/persist_test.cljs b/src/test/frontend/db/persist_test.cljs new file mode 100644 index 0000000000..6fce792a8a --- /dev/null +++ b/src/test/frontend/db/persist_test.cljs @@ -0,0 +1,31 @@ +(ns frontend.db.persist-test + (:require [cljs.test :refer [async deftest is]] + [electron.ipc :as ipc] + [frontend.db.persist :as db-persist] + [frontend.persist-db :as persist-db] + [frontend.util :as util] + [promesa.core :as p])) + +(deftest get-all-graphs-canonicalizes-db-prefixes-from-all-sources + (async done + (-> (p/with-redefs [persist-db/ (p/with-redefs [db-sync/http-base (constantly "http://base") + user-handler/task--ensure-id&access-token (fn [resolve _reject] + (resolve true)) + db-sync/fetch-json (fn [url _opts _schema] + (if (string/ends-with? url "/graphs") + (p/resolved {:graphs [{:graph-name "logseq_db_demo" + :graph-id "graph-1" + :schema-version 1} + {:graph-name "logseq_db_logseq_db_legacy" + :graph-id "graph-2" + :schema-version 1}]}) + (p/rejected (ex-info "unexpected fetch-json URL" + {:url url})))) + state/set-state! (fn [k v] + (swap! set-state-calls conj [k v])) + repo-handler/refresh-repos! (fn [] nil)] + (p/let [result (db-sync/ (p/let [gzip-bytes ( (p/with-redefs [db-sync/http-base (constantly "http://base") + db-sync/fetch-json (fn [url _opts _schema] + (cond + (string/ends-with? url "/pull") + (p/resolved {:t 8}) + + :else + (p/rejected (ex-info "unexpected fetch-json URL" + {:url url})))) + user-handler/task--ensure-id&access-token (fn [resolve _reject] + (resolve true)) + state/ (p/let [result (commands/execute {:type :graph-list} {})] (is (= :ok (:status result))) - (is (= ["demo" "other"] (get-in result [:data :graphs])))) + (is (= ["demo" "logseq_db_other" "my_logseq_db_notes"] + (get-in result [:data :graphs])))) (p/catch (fn [e] (is false (str "unexpected error: " e)))) (p/finally (fn [] diff --git a/src/test/logseq/cli/common/graph_test.cljs b/src/test/logseq/cli/common/graph_test.cljs new file mode 100644 index 0000000000..1d205a8a39 --- /dev/null +++ b/src/test/logseq/cli/common/graph_test.cljs @@ -0,0 +1,20 @@ +(ns logseq.cli.common.graph-test + (:require [cljs.test :refer [deftest is]] + [clojure.string :as string] + [frontend.test.node-helper :as node-helper] + [logseq.cli.common.graph :as cli-common-graph] + ["fs" :as fs] + ["path" :as node-path])) + +(deftest get-db-based-graphs-canonicalizes-legacy-prefixed-directory-names + (let [graphs-dir (node-helper/create-tmp-dir "cli-common-graph") + _ (doseq [dir ["demo" + "logseq_db_demo" + "logseq_db_logseq_db_demo" + "logseq_local_file-graph" + "Unlinked graphs"]] + (fs/mkdirSync (node-path/join graphs-dir dir) #js {:recursive true}))] + (with-redefs [cli-common-graph/get-db-graphs-dir (fn [] graphs-dir)] + (let [graphs (cli-common-graph/get-db-based-graphs)] + (is (= #{"logseq_db_demo"} (set graphs))) + (is (not-any? #(string/starts-with? % "logseq_db_logseq_db_") graphs)))))) diff --git a/src/test/logseq/cli/format_test.cljs b/src/test/logseq/cli/format_test.cljs index 1374fbffd3..8f8d3239f3 100644 --- a/src/test/logseq/cli/format_test.cljs +++ b/src/test/logseq/cli/format_test.cljs @@ -175,7 +175,34 @@ {:output-format nil})] (is (= (str "Server ready: demo-repo\n" "Host: 127.0.0.1 Port: 1234") - result))))) + result)))) + + (testing "server status strips only one leading db prefix and keeps middle substrings" + (let [double-prefixed (format/format-result {:status :ok + :command :server-status + :data {:repo "logseq_db_logseq_db_demo" + :status :ready}} + {:output-format nil}) + middle-substring (format/format-result {:status :ok + :command :server-status + :data {:repo "my_logseq_db_notes" + :status :ready}} + {:output-format nil})] + (is (= "Server ready: logseq_db_demo" double-prefixed)) + (is (= "Server ready: my_logseq_db_notes" middle-substring))))) + +(deftest test-json-output-normalizes-graph-fields-with-single-leading-strip-only + (let [result (format/format-result {:status :ok + :data {:repo "logseq_db_logseq_db_demo" + :graph "my_logseq_db_notes" + :graphs ["logseq_db_logseq_db_demo" + "my_logseq_db_notes"]}} + {:output-format :edn}) + parsed (reader/read-string result)] + (is (= "logseq_db_demo" (get-in parsed [:data :repo]))) + (is (= "my_logseq_db_notes" (get-in parsed [:data :graph]))) + (is (= ["logseq_db_demo" "my_logseq_db_notes"] + (get-in parsed [:data :graphs]))))) (deftest test-human-output-server-list-includes-owner (testing "server list shows owner column and value"