Merge branch 'feat/db' into feat/capacitor-new

This commit is contained in:
charlie
2025-04-26 14:57:46 +08:00
36 changed files with 770 additions and 668 deletions

View File

@@ -15,4 +15,5 @@
:main-opts ["-m" "cognitect.test-runner"]
:extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}
io.github.cognitect-labs/test-runner
{:git/tag "v0.5.1" :git/sha "dfb30dd"}}}}}
{:git/tag "v0.5.1" :git/sha "dfb30dd"}}}
:dev {:extra-paths ["dev" "test"]}}}

73
clj-e2e/dev/user.clj Normal file
View File

@@ -0,0 +1,73 @@
(ns user
"fns used on repl"
(:require [clojure.test :refer [run-tests run-test]]
[logseq.e2e.config :as config]
[logseq.e2e.editor-test]
[logseq.e2e.fixtures :as fixtures]
[logseq.e2e.multi-tabs-test]
[logseq.e2e.outliner-test]
[logseq.e2e.rtc-basic-test]
[logseq.e2e.util :as util]
[wally.main :as w]
[wally.repl :as repl]))
;; Use port 3001 for local testing
(reset! config/*port 3001)
;; show ui
(reset! config/*headless false)
(def *futures (atom {}))
(defn cancel
[test-name]
(some-> (get @*futures test-name) future-cancel)
(swap! *futures dissoc test-name))
(defn run-editor-test
[]
(->> (future (run-tests 'logseq.e2e.editor-test))
(swap! *futures assoc :editor-test)))
(defn run-outliner-test
[]
(->> (future (run-tests 'logseq.e2e.outliner-test))
(swap! *futures assoc :outliner-test)))
(defn run-rtc-basic-test
[]
(->> (future (run-tests 'logseq.e2e.rtc-basic-test))
(swap! *futures assoc :rtc-basic-test)))
(defn run-multi-tabs-test
[]
(->> (future (run-tests 'logseq.e2e.multi-tabs-test))
(swap! *futures assoc :multi-tabs-test)))
(comment
(future
(fixtures/open-page
repl/pause
{:headless false}))
;; You can put `(repl/pause)` in any test to pause the tests,
;; this allows us to continue experimenting with the current page.
(repl/pause)
;; To resume the tests, close the page/context/browser
(repl/resume)
;; Run specific test
(future (run-test logseq.e2e.editor-test/commands-test))
;; after the test has been paused, you can do anything with the current page like this
(repl/with-page
(w/wait-for (first (util/get-edit-block-container))
{:state :detached}))
(run-tests 'logseq.e2e.editor-test
'logseq.e2e.multi-tabs-test
'logseq.e2e.outliner-test
'logseq.e2e.rtc-basic-test)
;;
)

View File

@@ -0,0 +1,22 @@
(ns logseq.e2e.assert
(:import [com.microsoft.playwright.assertions PlaywrightAssertions])
(:require [wally.main :as w]))
(def assert-that PlaywrightAssertions/assertThat)
(defn assert-is-visible
[q]
(-> (w/-query q) assert-that .isVisible))
(defn assert-is-hidden
[q]
(-> (w/-query q) assert-that .isHidden))
(defn assert-in-normal-mode?
"- not editing mode
- no action bar
- no search(cmdk) modal"
[]
(assert-is-hidden (w/get-by-label "editing block"))
(assert-is-hidden ".selection-action-bar")
(assert-is-visible "#search-button"))

View File

@@ -0,0 +1,5 @@
(ns logseq.e2e.config)
(defonce *port (atom 3002))
(defonce *headless (atom true))
(defonce *slow-mo (atom 100)) ; Set `slow-mo` lower to find more flaky tests

View File

@@ -0,0 +1,24 @@
(ns logseq.e2e.playwright-page
"operations on playwright pages."
(:require [logseq.e2e.config :as config]
[wally.main :as w]))
(defn get-pages
[pw-ctx]
(.pages pw-ctx))
(defn open-pages
"Pages in same pw-ctx share cookies and storages"
[pw-ctx n]
(let [url (str "http://localhost:" @config/*port)]
(dotimes [_i n]
(let [page (.newPage pw-ctx)]
(.navigate page url)
;; wait the demo graph loaded
(w/with-page page
(w/wait-for "span.block-title-wrap"))))))
(defn close-pages
[pages]
(doseq [p pages]
(.close p)))

View File

@@ -1,38 +0,0 @@
(ns logseq.e2e.repl
"fns used on repl"
(:require [clojure.test :refer [run-tests run-test]]
[logseq.e2e.util :as util]
[wally.main :as w]
[wally.repl :as repl]))
(comment
(future
(w/with-page-open
(w/make-page {:headless false
:persistent false
:slow-mo 20})
(w/navigate "http://localhost:3001")
(repl/pause)))
;; You can put `(repl/pause)` in any test to pause the tests,
;; this allows us to continue experimenting with the current page.
(repl/pause)
;; To resume the tests, close the page/context/browser
(repl/resume)
;; Run all the tests in specific ns with `future` to not block repl
(future (run-tests 'logseq.e2e.editor-test))
(future (run-tests 'logseq.e2e.outliner-test))
;; Run specific test
(future (run-test logseq.e2e.editor-test/commands-test))
;; after the test has been paused, you can do anything with the current page like this
(repl/with-page
(w/wait-for (first (util/get-edit-block-container))
{:state :detached}))
;;
)

View File

@@ -2,13 +2,11 @@
(:refer-clojure :exclude [type])
(:require [clojure.string :as string]
[clojure.test :refer [is]]
[logseq.e2e.assert :as assert]
[logseq.e2e.keyboard :as k]
[wally.main :as w]
[wally.selectors :as ws]
[logseq.e2e.keyboard :as k])
(:import [com.microsoft.playwright TimeoutError]
[com.microsoft.playwright.assertions PlaywrightAssertions]))
(def assert-that PlaywrightAssertions/assertThat)
[wally.selectors :as ws])
(:import [com.microsoft.playwright TimeoutError]))
(defn wait-timeout
[ms]
@@ -39,8 +37,16 @@
(let [input-node (w/-query "*:focus")]
(.type input-node text)))
(defn double-esc
"Exits editing mode and ensure there's no action bar"
[]
(k/esc)
(k/esc))
(defn search
[text]
(double-esc)
(assert/assert-in-normal-mode?)
(w/click :#search-button)
(w/fill ".cp__cmdk-search-input" text))
@@ -48,6 +54,7 @@
[title]
;; Question: what's the best way to close all the popups?
;; close popup, exit editing
;; (repl/pause)
(search title)
(w/click [(ws/text "Create page") (ws/nth= "0")])
(w/wait-for ".editor-wrapper textarea"))
@@ -96,18 +103,6 @@
(when-let [editor (get-editor)]
(get-text editor)))
;; TODO: support tree
(defn new-blocks
[titles]
(let [value (get-edit-content)]
(if (string/blank? value) ; empty block
(do
(save-block (first titles))
(doseq [title (rest titles)]
(new-block title)))
(doseq [title titles]
(new-block title)))))
(defn bounding-xy
[locator]
(let [box (.boundingBox locator)]
@@ -133,8 +128,23 @@
(defn open-last-block
[]
(double-esc)
(assert/assert-in-normal-mode?)
(w/click (last (w/query ".ls-page-blocks .ls-block .block-content"))))
;; TODO: support tree
(defn new-blocks
[titles]
(open-last-block)
(let [value (get-edit-content)]
(if (string/blank? value) ; empty block
(do
(save-block (first titles))
(doseq [title (rest titles)]
(new-block title)))
(doseq [title titles]
(new-block title)))))
(defn repeat-keyboard
[n shortcut]
(dotimes [_i n]

View File

@@ -1,20 +1,18 @@
(ns logseq.e2e.fixtures
(:require [wally.main :as w]))
(:require [wally.main :as w]
[logseq.e2e.config :as config]
[logseq.e2e.playwright-page :as pw-page]))
;; TODO: save trace
;; TODO: parallel support
(defn open-page
[f & {:keys [headless port]
:or {headless true
port 3002}}]
[f & {:keys [headless port]}]
(w/with-page-open
(w/make-page {:headless headless
(w/make-page {:headless (or headless @config/*headless)
:persistent false
:slow-mo 100
;; Set `slow-mo` lower to find more flaky tests
;; :slow-mo 30
:slow-mo @config/*slow-mo
})
(w/navigate (str "http://localhost:" port))
(w/navigate (str "http://localhost:" (or port @config/*port)))
(f)))
(def *page1 (atom nil))
@@ -22,18 +20,17 @@
(defn open-2-pages
"Use `*page1` and `*page2` in `f`"
[f & {:keys [headless port]
:or {headless true
port 3002}}]
(let [p1 (w/make-page {:headless headless
:persistent false
:slow-mo 100})
p2 (w/make-page {:headless headless
:persistent false
:slow-mo 100})]
[f & {:keys [headless port]}]
(let [headless (or headless @config/*headless)
page-opts {:headless headless
:persistent false
:slow-mo @config/*slow-mo}
p1 (w/make-page page-opts)
p2 (w/make-page page-opts)
port' (or port @config/*port)]
(run!
#(w/with-page %
(w/navigate (str "http://localhost:" port)))
(w/navigate (str "http://localhost:" port')))
[p1 p2])
(reset! *page1 p1)
@@ -42,3 +39,19 @@
(f))
(w/with-page-open p1)
(w/with-page-open p2)))
(def ^:dynamic *pw-ctx* nil)
(defn open-new-context
"create a new playwright-context in `*pw-ctx*`"
[f]
(let [page-opts {:headless @config/*headless
:persistent false
:slow-mo @config/*slow-mo}
p @(w/make-page page-opts)
ctx (.newContext (.browser (.context p)))]
;; context for p is no longer needed
(.close (.context p))
(w/with-page-open p) ; use with-page-open to close playwright instance
(binding [*pw-ctx* ctx]
(f)
(.close (.browser *pw-ctx*)))))

View File

@@ -0,0 +1,23 @@
(ns logseq.e2e.multi-tabs-test
(:require
[clojure.test :refer [deftest testing is use-fixtures]]
[logseq.e2e.fixtures :as fixtures]
[logseq.e2e.playwright-page :as pw-page]
[logseq.e2e.util :as util]
[wally.main :as w]
[wally.repl :as repl]))
(use-fixtures :once fixtures/open-new-context)
(deftest multi-tabs-test
(testing "edit on one tab, check all tab's blocks are same"
(pw-page/open-pages fixtures/*pw-ctx* 3)
(let [[p1 p2 p3 :as pages] (pw-page/get-pages fixtures/*pw-ctx*)
blocks-to-add (map #(str "b" %) (range 10))]
(is (= 3 (count pages)))
(w/with-page p1
(util/new-blocks blocks-to-add))
(w/with-page p2
(is (= (util/page-blocks-count) (count blocks-to-add))))
(w/with-page p3
(is (= (util/page-blocks-count) (count blocks-to-add)))))))

View File

@@ -4,13 +4,10 @@
[com.climate.claypoole :as cp]
[logseq.e2e.fixtures :as fixtures :refer [*page1 *page2]]
[logseq.e2e.util :as util]
[wally.main :as w]
[wally.repl :as repl]))
[wally.main :as w]))
(use-fixtures :once fixtures/open-2-pages)
;; (use-fixtures :once #(fixtures/open-2-pages % :headless false :port 3001))
(deftest rtc-basic-test
(let [graph-name (str "rtc-graph-" (.toEpochMilli (java.time.Instant/now)))]
(testing "open 2 app instances"
@@ -23,7 +20,3 @@
(util/new-graph graph-name true))
(w/with-page @*page2
(util/wait-for-remote-graph graph-name)))))
(comment
(def xxx (future (clojure.test/run-tests)))
(future-cancel xxx))

View File

@@ -134,8 +134,7 @@
(hooks/use-effect!
(fn []
(when (false? open?)
(let [timeout (js/setTimeout #(detach-modal! id) 128)]
#(js/clearTimeout timeout))))
(detach-modal! id)))
[open?])
(dialog
@@ -159,12 +158,14 @@
(cond-> (merge props content-props)
auto-width? (assoc :data-auto-width true)
(false? close-btn?) (assoc :data-close-btn false))
(when title
(dialog-header
(when title (dialog-title title))
(when description (dialog-description description))))
;; nested title component is required for radix dialog content
(dialog-title {:class (when (nil? title) "hidden")} title)
(when description (dialog-description description))
(when content
[:div.ui__dialog-main-content content])
(when footer
(dialog-footer footer)))))))

View File

@@ -178,7 +178,6 @@
:top y
:left x}} ""))
(let [content-props (cond-> (merge content-props {:onEscapeKeyDown handle-key-escape!
:disableOutsideScroll false
:onPointerDownOutside handle-pointer-outside!})
(and (not force-popover?)
(not as-dropdown?))

View File

@@ -27,7 +27,8 @@
[data & {:keys [html-props]}]
(let [convert-to-camel (fn [[key value]]
(let [k (name key)]
[(if-not (s/starts-with? k "data-")
[(if-not (or (s/starts-with? k "data-")
(s/starts-with? k "aria-"))
(kebab-case->camel-case k) k) value]))]
(w/postwalk (fn [x]
(if (map? x)

View File

@@ -80,6 +80,7 @@ const common = {
'node_modules/react-dom/umd/react-dom.production.min.js',
'node_modules/react-dom/umd/react-dom.development.js',
'node_modules/prop-types/prop-types.min.js',
'node_modules/dompurify/dist/purify.js',
]).pipe(gulp.dest(path.join(outputPath, 'js'))),
() => gulp.src([
'node_modules/@tabler/icons-react/dist/umd/tabler-icons-react.min.js',

View File

@@ -5,7 +5,7 @@ import '../src/index.css'
import { useEffect } from 'react'
// require in this file to keep app state when HMR
const { setupGlobals } = require('../src')
const { setupGlobals } = require('../src/ui')
setupGlobals()

View File

@@ -36,6 +36,7 @@ const DialogContent = React.forwardRef<
<DialogOverlay {...overlayProps}>
<DialogPrimitive.Content
ref={ref}
aria-describedby={undefined}
className={cn(
'ui__dialog-content',
'relative grid w-full max-w-2xl lg:max-w-3xl gap-4 border sm:rounded-lg ' +

View File

@@ -22,6 +22,7 @@ export function Toaster() {
description,
action,
icon,
onDismiss, // remove from toast props
...props
}) {
const duration = props?.duration

View File

@@ -1,5 +1,5 @@
import 'src/index.css'
import { setupGlobals } from '../src'
import '../src/index.css'
import { setupGlobals } from '../src/ui'
import * as React from 'react'
import * as ReactDOM from 'react-dom'

View File

@@ -8,33 +8,30 @@
"build:ui:only": "parcel build --target ui",
"build:ui": "rm -rf .parcel-cache && yarn build:ui:only",
"watch:storybook": "storybook dev -p 6006",
"install:primitives": "rm -rf primitives/ && git clone -b x https://github.com/xyhp915/primitives.git --depth=1",
"build:primitives": "yarn install:primitives && cd primitives/ && yarn install && yarn build",
"preinstall": "test -f primitives/package.json || yarn build:primitives",
"postinstall": "yarn build:ui"
},
"dependencies": {
"@hookform/resolvers": "^3.3.2",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.1.4",
"@radix-ui/react-alert-dialog": "^1.1.11",
"@radix-ui/react-avatar": "^1.1.7",
"@radix-ui/react-checkbox": "^1.2.3",
"@radix-ui/react-context-menu": "^2.2.12",
"@radix-ui/react-dialog": "^1.1.11",
"@radix-ui/react-dropdown-menu": "^2.1.12",
"@radix-ui/react-label": "^2.1.4",
"@radix-ui/react-popover": "^1.1.11",
"@radix-ui/react-radio-group": "^1.3.4",
"@radix-ui/react-select": "^2.2.2",
"@radix-ui/react-separator": "^1.1.4",
"@radix-ui/react-slider": "^1.3.2",
"@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-switch": "^1.2.2",
"@radix-ui/react-tabs": "^1.1.9",
"@radix-ui/react-toast": "^1.2.11",
"@radix-ui/react-toggle": "^1.1.6",
"@radix-ui/react-toggle-group": "^1.1.7",
"@radix-ui/react-tooltip": "^1.2.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.0.0",
"cmdk": "^0.2.0",
@@ -89,8 +86,7 @@
},
"react/jsx-dev-runtime": "./node_modules/react/jsx-dev-runtime.js",
"react/jsx-runtime": "./node_modules/react/jsx-runtime.js",
"@/*": "./@/$1",
"@radix-ui/react-*": "./primitives/packages/react/$1"
"@/*": "./@/$1"
},
"targets": {
"main": false,

View File

@@ -1,4 +1,4 @@
import { Button } from '../@/components/ui/button'
import { Button } from '@/components/ui/button'
import { Meta, StoryObj } from '@storybook/react'
import { DropdownMenuCheckboxItemProps } from '@radix-ui/react-dropdown-menu'
@@ -73,6 +73,7 @@ export const Primary: StoryObj =
<div className={'p-20'}>
<DropdownMenuCheckboxes/>
<Button onClick={() => {
// @ts-ignore
const p = toast({
title: 'hello',
description: <Button onClick={() => p.dismiss()}>hello</Button>

File diff suppressed because it is too large Load Diff

View File

@@ -69,6 +69,7 @@
<body>
<div id="app"></div>
<script src="./js/marked.min.js"></script>
<script src="./js/purify.js"></script>
<script>
;(async function () {
const app = document.getElementById('app')
@@ -131,7 +132,7 @@
}
content = marked.parse(content).replace('src="./', `src="${fixLink('')}`)
setContent(content)
setContent(DOMPurify.sanitize(content))
}
// load default

View File

@@ -495,12 +495,11 @@
(defmethod handle-action :trigger [_ state _event]
(let [command (some-> state state->highlighted-item :source-command)
dont-close-commands #{:graph/open :graph/remove :dev/replace-graph-with-db-file
:ui/toggle-settings :go/flashcards :misc/import-edn-data}]
dont-close-commands #{:graph/open :graph/remove :dev/replace-graph-with-db-file :misc/import-edn-data}]
(when-let [action (:action command)]
(action)
(when-not (contains? dont-close-commands (:id command))
(shui/dialog-close! :ls-dialog-cmdk)))))
(shui/dialog-close! :ls-dialog-cmdk))
(util/schedule #(action) 32))))
(defmethod handle-action :create [_ state _event]
(let [item (state->highlighted-item state)

View File

@@ -708,7 +708,6 @@
(let [default-home (get-default-home-if-valid)
current-repo (state/sub :git/current-repo)
loading-files? (when current-repo (state/sub [:repo/loading-files? current-repo]))
latest-journals (db/get-latest-journals (state/get-current-repo) 1)
graph-parsing-state (state/sub [:graph/parsing-state current-repo])]
(cond
(or
@@ -727,20 +726,17 @@
(:page default-home))
(route-handler/redirect-to-page! (:page default-home))
(and config/publishing?
(not default-home)
(empty? latest-journals))
(let [latest-journals (db/get-latest-journals (state/get-current-repo) 1)]
(and config/publishing?
(not default-home)
(empty? latest-journals)))
(route-handler/redirect! {:to :all-pages})
loading-files?
(ui/loading (t :loading-files))
(seq latest-journals)
(journal/all-journals)
;; FIXME: why will this happen?
:else
[:div])])))
(journal/all-journals))])))
(defn- hide-context-menu-and-clear-selection
[e]

View File

@@ -202,7 +202,7 @@
(rum/defc remote-readme-display
[{:keys [repo]} _content]
(let [src (str (if (string/includes? js/location.href "logseq")
(let [src (str (if (string/includes? js/location.host "logseq")
"./static/" "./") "marketplace.html?repo=" repo)]
[:iframe.lsp-frame-readme {:src src}]))

View File

@@ -235,8 +235,7 @@
(state/pub-event! [:graph/open-new-window url])
(cond
;; exists locally?
(or (:root graph)
(and db-only? (not rtc-graph?)))
(or (:root graph) (not rtc-graph?))
(state/pub-event! [:graph/switch url])
(and rtc-graph? remote?)

View File

@@ -31,7 +31,7 @@
get-block-parent get-block-parents parents-collapsed? get-block-referenced-blocks
get-block-immediate-children get-block-page
get-custom-css
get-file-last-modified-at get-file get-file-page get-file-page-id file-exists?
get-file get-file-page get-file-page-id file-exists?
get-files-blocks get-files-full get-journals-length
get-latest-journals get-page get-case-page get-page-alias-names
get-page-blocks-count get-page-blocks-no-cache get-page-file get-page-format

View File

@@ -82,13 +82,6 @@
(conn/get-db repo-url) pred)
db-utils/seq-flatten)))
(defn get-file-last-modified-at
[repo path]
(when (and repo path)
(when-let [db (conn/get-db repo)]
(-> (db-utils/entity db [:file/path path])
:file/last-modified-at))))
(defn file-exists?
[repo path]
(when (and repo path)

View File

@@ -4,9 +4,9 @@
[clojure.string :as string]
[frontend.config :as config]
[frontend.db :as db]
[frontend.db.async :as db-async]
[frontend.db.model :as model]
[frontend.fs :as fs]
[logseq.common.path :as path]
[frontend.handler.file-based.file :as file-handler]
[frontend.handler.file-based.property :as file-property-handler]
[frontend.handler.global-config :as global-config-handler]
@@ -17,9 +17,9 @@
[frontend.util.fs :as fs-util]
[lambdaisland.glogi :as log]
[logseq.common.config :as common-config]
[logseq.common.path :as path]
[logseq.common.util.block-ref :as block-ref]
[promesa.core :as p]
[frontend.db.async :as db-async]))
[promesa.core :as p]))
;; all IPC paths must be normalized! (via common-util/path-normalize)
@@ -42,12 +42,11 @@
(defn- handle-add-and-change!
[repo path content db-content ctime mtime backup?]
(let [config (state/get-config repo)
path-hidden-patterns (:hidden config)
db-last-modified-at (db/get-file-last-modified-at repo path)]
path-hidden-patterns (:hidden config)]
(when-not (or (and (seq path-hidden-patterns)
(common-config/hidden? path path-hidden-patterns))
(common-config/hidden? path path-hidden-patterns))
;; File not changed
(= db-last-modified-at mtime))
(= content db-content))
(p/let [;; save the previous content in a versioned bak file to avoid data overwritten.
_ (when backup?
(-> (when-let [repo-dir (config/get-local-dir repo)]

View File

@@ -376,7 +376,7 @@
:path-params {:name link}}))
(defmethod handle :graph/save-db-to-disk [[_ _opts]]
(persist-db/export-current-graph! {:succ-notification? true}))
(persist-db/export-current-graph! {:succ-notification? true :force-save? true}))
(defmethod handle :ui/re-render-root [[_]]
(ui-handler/re-render-root!))

View File

@@ -8,20 +8,20 @@
[frontend.fs :as fs]
[frontend.fs.nfs :as nfs]
[frontend.handler.common :as common-handler]
[frontend.handler.file-based.repo :as file-repo-handler]
[frontend.handler.global-config :as global-config-handler]
[frontend.handler.repo :as repo-handler]
[frontend.handler.file-based.repo :as file-repo-handler]
[frontend.handler.route :as route-handler]
[frontend.idb :as idb]
[frontend.mobile.util :as mobile-util]
[frontend.persist-db :as persist-db]
[frontend.state :as state]
[frontend.util :as util]
[frontend.util.fs :as util-fs]
[goog.object :as gobj]
[lambdaisland.glogi :as log]
[logseq.common.util :as common-util]
[promesa.core :as p]
[frontend.persist-db :as persist-db]))
[promesa.core :as p]))
(defn remove-ignore-files
[files dir-name nfs?]
@@ -273,7 +273,7 @@
(when repo
(p/do!
(repo-handler/remove-repo! {:url repo} :switch-graph? false)
(ls-dir-files-with-path! graph-dir)
(ls-dir-files-with-path! graph-dir {:re-index? true})
(when (fn? ok-handler) (ok-handler))))))
;; TODO: move to frontend.handler.repo

View File

@@ -466,7 +466,6 @@
:graph/db-save {:fn #(state/pub-event! [:graph/save-db-to-disk])
:inactive (not (util/electron?))
:db-graph? true
:binding "mod+s"}
:graph/re-index {:fn (fn []

View File

@@ -42,10 +42,10 @@
(<export-db repo {})))
(defn export-current-graph!
[& {:keys [succ-notification?]}]
[& {:keys [succ-notification? force-save?]}]
(when (util/electron?)
(when-let [repo (state/get-current-repo)]
(when (config/db-based-graph? repo)
(when (or (config/db-based-graph? repo) force-save?)
(println :debug :save-db-to-disk repo)
(->
(p/do!

View File

@@ -1248,7 +1248,9 @@
#?(:cljs
(defn scroll-editor-cursor
[^js/HTMLElement el & {:keys [to-vw-one-quarter?]}]
(when (and el (or (mobile-util/native-platform?) (mobile?)))
(when (and el (or web-platform?
(mobile-util/native-platform?)
(mobile?)))
(let [box-rect (.getBoundingClientRect el)
box-top (.-top box-rect)
box-bottom (.-bottom box-rect)
@@ -1260,7 +1262,7 @@
scroll-top' (.-scrollTop main-node)
current-pos (get-selection-start el)
grapheme-pos (get-graphemes-pos (.-value (.textContent el)) current-pos)
grapheme-pos (get-graphemes-pos (.-value el) current-pos)
mock-text (some-> (gdom/getElement "mock-text")
gdom/getChildren
array-seq

View File

@@ -880,13 +880,11 @@
(= :thread-api/create-or-open-db method-k)
;; because shared-service operates at the graph level,
;; creating a new database or switching to another one requires re-initializing the service.
(let [[graph opts] (ldb/read-transit-str (last args))]
(if (:import-type opts)
(start-db! graph opts)
(p/let [service (<init-service! graph)]
(get-in service [:status :ready])
(let [[graph _opts] (ldb/read-transit-str (last args))]
(p/let [service (<init-service! graph)]
(get-in service [:status :ready])
;; wait for service ready
(js-invoke (:proxy service) k args))))
(js-invoke (:proxy service) k args)))
(or (contains? #{:thread-api/sync-app-state} method-k)
(nil? service))

View File

@@ -328,26 +328,27 @@
{:proxy (js/Proxy. target
#js {:get (fn [target method]
(assert (identical? "remoteInvoke" method) method)
(fn [args]
(cond
@*master-client?
(<apply-target-f! target method args)
(if (= "remoteInvoke" method)
(fn [args]
(cond
@*master-client?
(<apply-target-f! target method args)
:else
(let [request-id (next-request-id)
client-channel (ensure-client-channel client-id service-name)]
(p/create
(fn [resolve-fn reject-fn]
(vswap! *requests-in-flight assoc request-id {:method method
:args args
:resolve-fn resolve-fn
:reject-fn reject-fn})
(.postMessage client-channel (bean/->js
{:id request-id
:type "request"
:method method
:args args}))))))))})
:else
(let [request-id (next-request-id)
client-channel (ensure-client-channel client-id service-name)]
(p/create
(fn [resolve-fn reject-fn]
(vswap! *requests-in-flight assoc request-id {:method method
:args args
:resolve-fn resolve-fn
:reject-fn reject-fn})
(.postMessage client-channel (bean/->js
{:id request-id
:type "request"
:method method
:args args})))))))
(log/error :invalid-invoke-method method)))})
:status status}))
(defn broadcast-to-clients!