Merge branch 'feat/db' into refactor/db-properties-schema

pull/11196/head
Tienson Qin 2024-04-03 20:29:11 +08:00
commit 7084b53dad
14 changed files with 518 additions and 63 deletions

View File

@ -222,7 +222,7 @@ jobs:
DEBUG: "pw:api"
RELEASE: true # skip dev only test
build-linux:
build-linux-x64:
runs-on: ubuntu-20.04
needs: [ compile-cljs ]
steps:
@ -265,7 +265,61 @@ jobs:
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: logseq-linux-builds
name: logseq-linux-x64-builds
path: builds
build-linux-arm64:
runs-on: ubuntu-20.04
needs: [ compile-cljs ]
steps:
- name: Download The Static Asset
uses: actions/download-artifact@v3
with:
name: static
path: static
- name: Retrieve tag version
id: ref
run: |
pkgver=$(cat ./static/VERSION)
echo "version=$pkgver" >> $GITHUB_OUTPUT
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
- name: Fetch deps
env:
npm_config_arch: arm64
run: |
yarn install --target_arch=arm64 --target_platform=linux
rsapi_version=`node -e 'console.log(require("@logseq/rsapi/package.json").optionalDependencies["@logseq/rsapi-linux-arm64-gnu"])'`
temp_dir=`mktemp -d`
cd "$temp_dir"
echo '{"dependencies": {"@logseq/rsapi-linux-arm64-gnu": "'"$rsapi_version"'"}}' > package.json
yarn install --ignore-platform
cd -
mv "$temp_dir/node_modules/@logseq/rsapi-linux-arm64-gnu" node_modules/@logseq/rsapi-linux-arm64-gnu
rm -rf "$temp_dir" "node_modules/@logseq/rsapi-linux-x64-gnu"
working-directory: ./static
- name: Build/Release Electron App
run: yarn electron:make-linux-arm64
working-directory: ./static
- name: Save artifacts
run: |
mkdir -p builds
# NOTE: save VERSION file to builds directory
cp static/VERSION ./builds/VERSION
# mv static/out/make/*-*.AppImage ./builds/Logseq-linux-arm64-${{ steps.ref.outputs.version }}.AppImage
mv static/out/make/zip/linux/arm64/*-linux-arm64-*.zip ./builds/Logseq-linux-arm64-${{ steps.ref.outputs.version }}.zip
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: logseq-linux-arm64-builds
path: builds
build-windows:
@ -498,7 +552,7 @@ jobs:
nightly-release:
if: ${{ github.event_name == 'schedule' || github.event.inputs.build-target == 'nightly' }}
needs: [ build-macos-x64, build-macos-arm64, build-linux, build-windows, build-android, e2e-test ]
needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, build-windows, build-android, e2e-test ]
runs-on: ubuntu-20.04
steps:
- name: Download MacOS x64 Artifacts
@ -513,10 +567,16 @@ jobs:
name: logseq-darwin-arm64-builds
path: ./
- name: Download The Linux Artifacts
- name: Download The Linux x64 Artifacts
uses: actions/download-artifact@v3
with:
name: logseq-linux-builds
name: logseq-linux-x64-builds
path: ./
- name: Download The Linux arm64 Artifacts
uses: actions/download-artifact@v3
with:
name: logseq-linux-arm64-builds
path: ./
- name: Download The Windows Artifact
@ -565,7 +625,7 @@ jobs:
release:
# NOTE: For now, we only have beta channel to be released on Github
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.build-target == 'beta' }}
needs: [ build-macos-x64, build-macos-arm64, build-linux, build-windows, e2e-test ]
needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, build-windows, e2e-test ]
runs-on: ubuntu-20.04
steps:
- name: Download MacOS x64 Artifacts
@ -580,10 +640,16 @@ jobs:
name: logseq-darwin-arm64-builds
path: ./
- name: Download The Linux Artifacts
- name: Download The Linux x64 Artifacts
uses: actions/download-artifact@v3
with:
name: logseq-linux-builds
name: logseq-linux-x64-builds
path: ./
- name: Download The Linux arm64 Artifacts
uses: actions/download-artifact@v3
with:
name: logseq-linux-arm64-builds
path: ./
- name: Download The Windows Artifact

View File

@ -13,6 +13,7 @@
[logseq.db.frontend.property :as db-property]
[logseq.db.frontend.property.type :as db-property-type]
[logseq.common.util.macro :as macro-util]
[logseq.common.util.date-time :as date-time-util]
[logseq.db.sqlite.util :as sqlite-util]
[logseq.db :as ldb]
[logseq.db.frontend.rules :as rules]
@ -110,6 +111,108 @@
(keep #(convert-tag-to-class % tag-classes) tags)))))
block))
(defn- update-block-marker
"If a block has a marker, convert it to a task object"
[block db {:keys [log-fn]}]
(if-let [marker (:block/marker block)]
(let [old-to-new {"TODO" :logseq.task/status.todo
"LATER" :logseq.task/status.todo
"IN-PROGRESS" :logseq.task/status.doing
"NOW" :logseq.task/status.doing
"DOING" :logseq.task/status.doing
"DONE" :logseq.task/status.done
"WAIT" :logseq.task/status.backlog
"WAITING" :logseq.task/status.backlog
"CANCELED" :logseq.task/status.canceled
"CANCELLED" :logseq.task/status.canceled}
status-prop (:block/uuid (d/entity db :logseq.task/status))
status-ident (or (old-to-new marker)
(do
(log-fn :invalid-todo (str (pr-str marker) " is not a valid marker so setting it to TODO"))
:logseq.task/status.todo))
status-value (:block/uuid (d/entity db status-ident))]
(-> block
(update :block/properties assoc status-prop status-value)
(update :block/content string/replace-first (re-pattern (str marker "\\s*")) "")
(update :block/tags (fnil conj []) :logseq.class/task)
(update :block/refs (fn [refs]
(into (remove #(= marker (:block/original-name %)) refs)
[:logseq.class/task :logseq.task/status status-ident])))
(update :block/path-refs (fn [refs]
(into (remove #(= marker (:block/original-name %)) refs)
[:logseq.class/task :logseq.task/status status-ident])))
(dissoc :block/marker)))
block))
(defn- update-block-priority
[block db {:keys [log-fn]}]
(if-let [priority (:block/priority block)]
(let [old-to-new {"A" :logseq.task/priority.high
"B" :logseq.task/priority.medium
"C" :logseq.task/priority.low}
priority-prop (:block/uuid (d/entity db :logseq.task/priority))
priority-ident (or (old-to-new priority)
(do
(log-fn :invalid-priority (str (pr-str priority) " is not a valid priority so setting it to low"))
:logseq.task/priority.low))
priority-value (:block/uuid (d/entity db priority-ident))]
(-> block
(update :block/properties assoc priority-prop priority-value)
(update :block/content string/replace-first (re-pattern (str "\\[#" priority "\\]" "\\s*")) "")
(update :block/refs (fn [refs]
(into (remove #(= priority (:block/original-name %)) refs)
[:logseq.task/priority priority-ident])))
(update :block/path-refs (fn [refs]
(into (remove #(= priority (:block/original-name %)) refs)
[:logseq.task/priority priority-ident])))
(dissoc :block/priority)))
block))
(defn- update-block-deadline
":block/content doesn't contain DEADLINE.* text so unable to detect timestamp
or repeater usage and notify user that they aren't supported"
[block db {:keys [user-config]}]
(if-let [deadline (:block/deadline block)]
(let [deadline-prop (:block/uuid (d/entity db :logseq.task/deadline))
deadline-page (or (ffirst (d/q '[:find (pull ?b [:block/uuid])
:in $ ?journal-day
:where [?b :block/journal-day ?journal-day]]
db deadline))
;; FIXME: Register new pages so that two different refs to same new page
;; don't create different uuids and thus an invalid page
(assoc (sqlite-util/build-new-page
(date-time-util/int->journal-title deadline (common-config/get-date-formatter user-config)))
:block/journal? true
:block/journal-day deadline
:block/format :markdown))]
(-> block
(update :block/properties assoc deadline-prop (:block/uuid deadline-page))
(update :block/refs (fnil into []) [:logseq.task/deadline deadline-page])
(update :block/path-refs (fnil into []) [:logseq.task/deadline deadline-page])
(dissoc :block/deadline)))
block))
(defn- update-block-scheduled
"Should have same implementation as update-block-deadline"
[block db {:keys [user-config]}]
(if-let [scheduled (:block/scheduled block)]
(let [scheduled-prop (:block/uuid (d/entity db :logseq.task/scheduled))
scheduled-page (or (ffirst (d/q '[:find (pull ?b [:block/uuid])
:in $ ?journal-day
:where [?b :block/journal-day ?journal-day]]
db scheduled))
(assoc (sqlite-util/build-new-page
(date-time-util/int->journal-title scheduled (common-config/get-date-formatter user-config)))
:block/journal? true
:block/journal-day scheduled
:block/format :markdown))]
(-> block
(update :block/properties assoc scheduled-prop (:block/uuid scheduled-page))
(update :block/refs (fnil into []) [:logseq.task/scheduled scheduled-page])
(update :block/path-refs (fnil into []) [:logseq.task/scheduled scheduled-page])
(dissoc :block/scheduled)))
block))
(defn- text-with-refs?
"Detects if a property value has text with refs e.g. `#Logseq is #awesome`
instead of `#Logseq #awesome`. If so the property type is :default instead of :page"
@ -448,6 +551,10 @@
(handle-block-properties db page-names-to-uuids (:block/refs block) options)
(update-block-refs page-names-to-uuids old-property-schemas options)
(update-block-tags tag-classes page-names-to-uuids)
(update-block-marker db options)
(update-block-priority db options)
(update-block-deadline db options)
(update-block-scheduled db options)
add-missing-timestamps
;; ((fn [x] (prn :block-out x) x))
;; TODO: org-mode content needs to be handled
@ -831,6 +938,7 @@
:user-config config
:filename-format (or (:file/name-format config) :legacy)
:verbose (:verbose options)}
:user-config config
:user-options (select-keys options [:tag-classes :property-classes :property-parent-classes])
:page-tags-uuid (:block/uuid (d/entity @conn :logseq.property/page-tags))
:import-state (new-import-state)

View File

@ -931,9 +931,10 @@
(remove nil?)))))
(defn ^:api delete-block
"Delete block from the tree."
"FIXME: why expose this fn? there's already a public fn `delete-blocks!`
Delete block from the tree."
[repo conn txs-state node {:keys [children? children-check? date-formatter]
:or {children-check? true}}]
:or {children-check? true}}]
(if (and children-check?
(not children?)
(first (:block/_parent (d/entity @conn [:block/uuid (:block/uuid (get-data node))]))))

View File

@ -11,6 +11,7 @@
"electron:dev": "electron-forge start",
"electron:debug": "electron-forge start --inspect-electron",
"electron:make": "electron-forge make",
"electron:make-linux-arm64": "electron-forge make --platform=linux --arch=arm64",
"electron:make-macos-arm64": "electron-forge make --platform=darwin --arch=arm64",
"electron:publish:github": "electron-forge publish",
"rebuild:all": "electron-rebuild -v 27.1.3 -f",
@ -28,7 +29,7 @@
"chokidar": "^3.5.1",
"command-exists": "1.2.9",
"diff-match-patch": "1.0.5",
"dugite": "2.5.0",
"dugite": "2.5.1",
"electron-deeplink": "1.0.10",
"electron-dl": "3.3.0",
"electron-log": "4.3.1",

View File

@ -10,6 +10,7 @@
[datascript.core :as d]
[datascript.storage :refer [IStorage]]
[frontend.worker.async-util :include-macros true :refer [<?] :as async-util]
[frontend.worker.db-listener :as db-listener]
[frontend.worker.db-metadata :as worker-db-metadata]
[frontend.worker.export :as worker-export]
[frontend.worker.file :as file]
@ -22,6 +23,7 @@
[frontend.worker.rtc.snapshot :as rtc-snapshot]
[frontend.worker.search :as search]
[frontend.worker.state :as worker-state]
[frontend.worker.undo-redo]
[frontend.worker.util :as worker-util]
[logseq.db :as ldb]
[logseq.db.sqlite.common-db :as sqlite-common-db]
@ -174,7 +176,9 @@
conn (sqlite-common-db/get-storage-conn storage schema)]
(swap! *datascript-conns assoc repo conn)
(p/let [_ (op-mem-layer/<init-load-from-indexeddb! repo)]
(rtc-db-listener/listen-to-db-changes! repo conn))))))
(rtc-db-listener/listen-to-db-changes! repo conn)
(db-listener/listen-db-changes! repo conn))
))))
(defn- iter->vec [iter]
(when iter

View File

@ -718,7 +718,7 @@
(js/console.error e)
(dec current-pos)))
(dec current-pos))
(dec current-pos))))
current-pos)))
#?(:cljs
;; for widen char
@ -735,7 +735,7 @@
(js/console.error e)
(inc current-pos)))
(inc current-pos))
(inc current-pos))))
current-pos)))
#?(:cljs
(defn kill-line-before!

View File

@ -0,0 +1,46 @@
(ns frontend.worker.db-listener
"Db listeners for worker-db."
(:require [datascript.core :as d]))
(defn- entity-datoms=>attr->datom
[entity-datoms]
(reduce
(fn [m datom]
(let [[_e a _v t add?] datom]
(if-let [[_e _a _v old-t old-add?] (get m a)]
(cond
(and (= old-t t)
(true? add?)
(false? old-add?))
(assoc m a datom)
(< old-t t)
(assoc m a datom)
:else
m)
(assoc m a datom))))
{} entity-datoms))
(defmulti listen-db-changes
(fn [listen-key & _] listen-key))
(defn listen-db-changes!
[repo conn]
(let [handlers (methods listen-db-changes)]
(prn :listen-db-changes! (keys handlers))
(d/unlisten! conn ::listen-db-changes!)
(d/listen! conn ::listen-db-changes!
(fn [{:keys [tx-data] :as args}]
(let [datom-vec-coll (map vec tx-data)
id->same-entity-datoms (group-by first datom-vec-coll)
id-order (distinct (map first datom-vec-coll))
same-entity-datoms-coll (map id->same-entity-datoms id-order)
id->attr->datom (update-vals id->same-entity-datoms entity-datoms=>attr->datom)]
(doseq [[k handler-fn] handlers]
(handler-fn k (assoc args
:repo repo
:id->attr->datom id->attr->datom
:same-entity-datoms-coll same-entity-datoms-coll))))))))

View File

@ -18,10 +18,18 @@
[entity-datoms]
(reduce
(fn [m datom]
(let [[_e a _v t _add?] datom]
(if-let [[_e _a _v old-t _old-add?] (get m a)]
(if (<= old-t t)
(let [[_e a _v t add?] datom]
(if-let [[_e _a _v old-t old-add?] (get m a)]
(cond
(and (= old-t t)
(true? add?)
(false? old-add?))
(assoc m a datom)
(< old-t t)
(assoc m a datom)
:else
m)
(assoc m a datom))))
{} entity-datoms))

View File

@ -8,11 +8,15 @@
:db/latest-transact-time {}
:worker/context {}
;; FIXME: this name :config is too general
:config {}
:git/current-repo nil
:rtc/batch-processing? false
:rtc/remote-batch-txs nil
:rtc/downloading-graph? false}))
:rtc/downloading-graph? false
:undo/repo->undo-stack (atom {})
:undo/repo->redo-stack (atom {})}))
(defonce *rtc-ws-url (atom nil))

View File

@ -1,35 +1,52 @@
(ns frontend.worker.undo-redo
"undo/redo related fns and op-schema"
(:require [datascript.core :as d]))
(:require [datascript.core :as d]
[frontend.worker.db-listener :as db-listener]
[frontend.worker.state :as worker-state]
[logseq.common.config :as common-config]
[logseq.outliner.core :as outliner-core]
[logseq.outliner.transaction :as outliner-tx]
[malli.core :as m]
[malli.util :as mu]))
(def undo-op-schema
[:multi {:dispatch first}
[:boundary
[:cat :keyword]]
[:insert-block
[:cat :keyword
[:map
[:block-uuid :uuid]]]]
[:move-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-origin-left :uuid]
[:block-origin-parent :uuid]]]]
[:remove-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-entity-map :map]]]]
[:update-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-origin-content {:optional true} :string]
;; TODO: add more attrs
]]]])
(mu/closed-schema
[:multi {:dispatch first}
[:boundary
[:cat :keyword]]
[:insert-block
[:cat :keyword
[:map
[:block-uuid :uuid]]]]
[:move-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-origin-left :uuid]
[:block-origin-parent :uuid]]]]
[:remove-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-entity-map
[:map
[:block/uuid :uuid]
[:block/left :uuid]
[:block/parent :uuid]
[:block/content :string]
[:block/created-at :int]
[:block/updated-at :int]
[:block/format :any]
[:block/tags {:optional true} [:sequential :uuid]]]]]]]
[:update-block
[:cat :keyword
[:map
[:block-uuid :uuid]
[:block-origin-content {:optional true} :string]
;; TODO: add more attrs
]]]]))
(def undo-ops-validator (m/validator [:sequential undo-op-schema]))
(defn reverse-op
[db op]
@ -68,3 +85,198 @@
[:update-block
(cond-> {:block-uuid block-uuid}
block-origin-content (assoc :block-origin-content block-origin-content))]))))
(def ^:private apply-conj-vec (partial apply (fnil conj [])))
(defn- push-undo-ops
[repo ops]
(swap! (:undo/repo->undo-stack @worker-state/*state) update repo apply-conj-vec ops))
(defn- pop-undo-op
[repo]
(let [repo->undo-stack (:undo/repo->undo-stack @worker-state/*state)]
(when-let [peek-op (peek (@repo->undo-stack repo))]
(swap! repo->undo-stack update repo pop)
peek-op)))
(defn- push-redo-ops
[repo ops]
(swap! (:undo/repo->redo-stack @worker-state/*state) update repo apply-conj-vec ops))
(defn- pop-redo-op
[repo]
(let [repo->redo-stack (:undo/repo->redo-stack @worker-state/*state)]
(when-let [peek-op (peek (@repo->redo-stack repo))]
(swap! repo->redo-stack update repo pop)
peek-op)))
(defmulti reverse-apply-op (fn [op _conn _repo] (first op)))
(defmethod reverse-apply-op :remove-block
[op conn repo]
(let [[_ {:keys [block-uuid block-entity-map]}] op]
(when-let [left-entity (d/entity @conn [:block/uuid (:block/left block-entity-map)])]
(let [sibling? (not= (:block/left block-entity-map) (:block/parent block-entity-map))]
(outliner-tx/transact!
{:gen-undo-op? false
:outliner-op :insert-blocks
:transact-opts {:repo repo
:conn conn}}
(outliner-core/insert-blocks! repo conn
[(cond-> {:block/uuid block-uuid
:block/content (:block/content block-entity-map)
:block/created-at (:block/created-at block-entity-map)
:block/updated-at (:block/updated-at block-entity-map)
:block/format :markdown}
(seq (:block/tags block-entity-map))
(assoc :block/tags (mapv (partial vector :block/uuid)
(:block/tags block-entity-map))))]
left-entity {:sibling? sibling? :keep-uuid? true}))
:push-undo-redo
))))
(defmethod reverse-apply-op :insert-block
[op conn repo]
(let [[_ {:keys [block-uuid]}] op]
(when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
(when (empty? (seq (:block/_parent block-entity))) ;if have children, skip
(outliner-tx/transact!
{:gen-undo-op? false
:outliner-op :delete-blocks
:transact-opts {:repo repo
:conn conn}}
(outliner-core/delete-blocks! repo conn
(common-config/get-date-formatter (worker-state/get-config repo))
[block-entity]
{:children? false}))
:push-undo-redo))))
(defmethod reverse-apply-op :move-block
[op conn repo]
(let [[_ {:keys [block-uuid block-origin-left block-origin-parent]}] op]
(when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
(when-let [left-entity (d/entity @conn [:block/uuid block-origin-left])]
(let [sibling? (not= block-origin-left block-origin-parent)]
(outliner-tx/transact!
{:gen-undo-op? false
:outliner-op :move-blocks
:transact-opts {:repo repo
:conn conn}}
(outliner-core/move-blocks! repo conn [block-entity] left-entity sibling?))
:push-undo-redo)))))
(defmethod reverse-apply-op :update-block
[op conn repo]
(let [[_ {:keys [block-uuid block-origin-content]}] op]
(when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
(let [new-block (assoc block-entity :block/content block-origin-content)]
(outliner-tx/transact!
{:gen-undo-op? false
:outliner-op :save-block
:transact-opts {:repo repo
:conn conn}}
(outliner-core/save-block! repo conn
(common-config/get-date-formatter (worker-state/get-config repo))
new-block))
:push-undo-redo))))
(defn undo
[repo]
(when-let [op (pop-undo-op repo)]
(let [conn (worker-state/get-datascript-conn repo)
rev-op (reverse-op @conn op)]
(when (= :push-undo-redo (reverse-apply-op op conn repo))
(push-redo-ops repo [rev-op])))))
(defn redo
[repo]
(when-let [op (pop-redo-op repo)]
(let [conn (worker-state/get-datascript-conn repo)
rev-op (reverse-op @conn op)]
(when (= :push-undo-redo (reverse-apply-op op conn repo))
(push-undo-ops repo [rev-op])))))
;;; listen db changes and push undo-ops
(def ^:private entity-map-pull-pattern
[:block/uuid
{:block/left [:block/uuid]}
{:block/parent [:block/uuid]}
:block/content
:block/created-at
:block/updated-at
:block/format
{:block/tags [:block/uuid]}])
(defn- ->block-entity-map
[db eid]
(let [m (-> (d/pull db entity-map-pull-pattern eid)
(update :block/left :block/uuid)
(update :block/parent :block/uuid))]
(if (seq (:block/tags m))
(update m :block/tags (partial mapv :block/uuid))
m)))
(defn- normal-block?
[entity]
(and (:block/parent entity)
(:block/left entity)))
(defn- entity-datoms=>ops
[db-before db-after id->attr->datom entity-datoms]
(when-let [e (ffirst entity-datoms)]
(let [attr->datom (id->attr->datom e)]
(when (seq attr->datom)
(let [{[_ _ block-uuid _ add1?] :block/uuid
[_ _ block-content _ add2?] :block/content
[_ _ _ _ add3?] :block/left
[_ _ _ _ add4?] :block/parent} attr->datom
entity-before (d/entity db-before e)
entity-after (d/entity db-after e)]
(cond
(and (not add1?) block-uuid
(normal-block? entity-before))
[[:remove-block
{:block-uuid (:block/uuid entity-before)
:block-entity-map (->block-entity-map db-before e)}]]
(and add1? block-uuid
(normal-block? entity-after))
[[:insert-block {:block-uuid (:block/uuid entity-after)}]]
(and (or add3? add4?)
(normal-block? entity-after))
(cond-> [[:move-block
{:block-uuid (:block/uuid entity-after)
:block-origin-left (:block/uuid (:block/left entity-before))
:block-origin-parent (:block/uuid (:block/parent entity-before))}]]
(and add2? block-content)
(conj [:update-block
{:block-uuid (:block/uuid entity-after)
:block-origin-content (:block/content entity-before)}]))
(and add2? block-content
(normal-block? entity-after))
[[:update-block
{:block-uuid (:block/uuid entity-after)
:block-origin-content (:block/content entity-before)}]]))))))
(defn- generate-undo-ops
[repo db-before db-after same-entity-datoms-coll id->attr->datom]
(let [ops (mapcat (partial entity-datoms=>ops db-before db-after id->attr->datom) same-entity-datoms-coll)]
(assert (undo-ops-validator ops) ops)
(when (seq ops)
(push-undo-ops repo ops))))
(defmethod db-listener/listen-db-changes :gen-undo-ops
[_ {:keys [_tx-data tx-meta db-before db-after
repo id->attr->datom same-entity-datoms-coll]}]
(when (:gen-undo-op? tx-meta true)
(generate-undo-ops repo db-before db-after same-entity-datoms-coll id->attr->datom)))
;;; listen db changes and push undo-ops (ends)

View File

@ -585,11 +585,11 @@
:plugin.install-from-file/title "Installa plugin da plugins.edn"
:query/config-property-settings "Impostazioni per le proprietà di questa richiesta:"
:right-side-bar/flashcards "Flashcard"
:right-side-bar/history "(Dev) cronologia disfai/rifai"
:right-side-bar/history "(Dev) cronologia disfare/rifare"
:right-side-bar/history-global "globale"
:right-side-bar/history-pageonly "solo pagina corrente"
:right-side-bar/history-redos "Rifai"
:right-side-bar/history-undos "Disfai"
:right-side-bar/history-undos "Rifare"
:right-side-bar/pane-close "Chiudi"
:right-side-bar/pane-close-all "Chiudi tutti"
:right-side-bar/pane-close-others "Chiudi altri"
@ -649,9 +649,9 @@
:settings-page/tab-editor "Editor"
:settings-page/tab-features "Funzionalità"
:settings-page/tab-keymap "Scorciatoie"
:settings-page/theme-dark "scuro"
:settings-page/theme-light "chiaro"
:settings-page/theme-system "sistema"
:settings-page/theme-dark "Scuro"
:settings-page/theme-light "Chiaro"
:settings-page/theme-system "Sistema"
:settings-page/update-available "Trovato una nuova versione "
:settings-page/update-error-1 "⚠️ Ops, qualcosa è andato storto!"
:settings-page/update-error-2 " Per favore, controlla il "
@ -703,8 +703,8 @@
:whiteboard/link-to-any-page-or-block "Collega a qualsiasi pagina o blocco"
:whiteboard/lock "Blocca"
:whiteboard/medium "Medio"
:whiteboard/move-to-back "Sposta in retro"
:whiteboard/move-to-front "Sposta in fronte"
:whiteboard/move-to-back "Sposta sul retro"
:whiteboard/move-to-front "Sposta sul fronte"
:whiteboard/new-block "Nuovo blocco:"
:whiteboard/new-block-no-colon "Nuovo blocco"
:whiteboard/new-page "Nuova pagina:"
@ -713,8 +713,8 @@
:whiteboard/open-page "Apri pagina"
:whiteboard/open-page-in-sidebar "Apri pagina nel pannello laterale"
:whiteboard/open-twitter-url "Apri link Twitter"
:whiteboard/open-website-url "Open sito internet"
:whiteboard/open-youtube-url "Open link YouTube"
:whiteboard/open-website-url "Apri sito internet"
:whiteboard/open-youtube-url "Apri link YouTube"
:whiteboard/pack-into-rectangle "Forma rettangolo compresso"
:whiteboard/pan "Muovi"
:whiteboard/paste "Incolla"
@ -741,7 +741,7 @@
:whiteboard/toggle-pen-mode "Attiva/disattiva modalità penna"
:whiteboard/triangle "Triangolo"
:whiteboard/twitter-url "Indirizzo Twitter"
:whiteboard/undo "Disfai"
:whiteboard/undo "Rifare"
:whiteboard/ungroup "Annulla raggruppamento"
:whiteboard/unlock "Blocca"
:whiteboard/website-url "Link sito internet"

View File

@ -15,14 +15,17 @@
(is (= 0 (util/safe-dec-current-pos-from-end "😀" 2)))
(is (= 0 (util/safe-dec-current-pos-from-end "a" 1)))
(is (= 4 (util/safe-dec-current-pos-from-end "abcde" 5)))
(is (= 1 (util/safe-dec-current-pos-from-end "中文" 2))))
(is (= 1 (util/safe-dec-current-pos-from-end "中文" 2)))
(is (= 0 (util/safe-dec-current-pos-from-end "中" 1)))
(is (= 0 (util/safe-dec-current-pos-from-end "a" 1))))
(testing "safe current position from start for emoji"
(is (= 5 (util/safe-inc-current-pos-from-start "abc😀d" 3)))
(is (= 2 (util/safe-inc-current-pos-from-start "😀" 0)))
(is (= 2 (util/safe-inc-current-pos-from-start "abcde" 1)))
(is (= 1 (util/safe-inc-current-pos-from-start "a" 0)))
(is (= 1 (util/safe-inc-current-pos-from-start "中文" 0)))))
(is (= 1 (util/safe-inc-current-pos-from-start "中文" 0)))
(is (= 2 (util/safe-inc-current-pos-from-start "😀" 0)))
(is (= 1 (util/safe-inc-current-pos-from-start "中" 0)))
(is (= 1 (util/safe-inc-current-pos-from-start "a" 0)))))
(deftest test-get-line-pos
(testing "get-line-pos"

View File

@ -8,4 +8,6 @@
;; TODO: add tests for undo-redo
undo-redo/undo-op-schema
undo-redo/reverse-op
undo-redo/undo
undo-redo/redo
)

View File

@ -1856,10 +1856,10 @@ ds-store@^0.1.5:
macos-alias "~0.2.5"
tn1150 "^0.1.0"
dugite@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/dugite/-/dugite-2.5.0.tgz#8b235564fdf8692688283c714149a59d9da79865"
integrity sha512-sYsSOqV7NidthDtMUPgKCvqMGqswKkcyAxOMhwEswlcGZ+kHadT2SEDFUJOy0AVR/yTJL6wBF7q1OiySfU0gGA==
dugite@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/dugite/-/dugite-2.5.1.tgz#6ab808ebf321809edf42d974e62eea9c9e256722"
integrity sha512-9OjUguynzq8v3GSmp01kbVcMmErc65ZZ0OssO/0PM2RyhD8Dzb8cCuy3z72+IxLwPwNi754jZ0FtMLAFA3D0qA==
dependencies:
progress "^2.0.3"
tar "^6.1.11"