Merge branch 'master' into feat/ai-lab

This commit is contained in:
Tienson Qin
2023-05-18 15:45:52 +08:00
114 changed files with 3139 additions and 803 deletions

View File

@@ -23,8 +23,8 @@
[frontend.context.i18n :refer [t]]
[frontend.date :as date]
[frontend.db :as db]
[frontend.db-mixins :as db-mixins]
[frontend.db.model :as model]
[frontend.db-mixins :as db-mixins]
[frontend.extensions.highlight :as highlight]
[frontend.extensions.latex :as latex]
[frontend.extensions.lightbox :as lightbox]
@@ -53,6 +53,7 @@
[frontend.mobile.util :as mobile-util]
[frontend.modules.outliner.tree :as tree]
[frontend.security :as security]
[frontend.shui :refer [get-shui-component-version make-shui-context]]
[frontend.state :as state]
[frontend.template :as template]
[frontend.ui :as ui]
@@ -74,6 +75,7 @@
[logseq.graph-parser.util.block-ref :as block-ref]
[logseq.graph-parser.util.page-ref :as page-ref]
[logseq.graph-parser.whiteboard :as gp-whiteboard]
[logseq.shui.core :as shui]
[medley.core :as medley]
[promesa.core :as p]
[reitit.frontend.easy :as rfe]
@@ -293,8 +295,8 @@
(js/setTimeout #(reset! *resizing-image? false) 200)))
:onClick (fn [e]
(when @*resizing-image? (util/stop e)))}
(and (:width metadata) (not (util/mobile?)))
(assoc :style {:width (:width metadata)}))
(and (:width metadata) (not (util/mobile?)))
(assoc :style {:width (:width metadata)}))
{})
[:div.asset-container {:key "resize-asset-container"}
[:img.rounded-sm.relative
@@ -938,9 +940,8 @@
inner)])
[:span.warning.mr-1 {:title "Block ref invalid"}
(block-ref/->block-ref id)]))
[:span.warning.mr-1 {:title "Block ref invalid"}
(block-ref/->block-ref id)]
))
[:span.warning.mr-1 {:title "Block ref invalid"}
(block-ref/->block-ref id)]))
(defn inline-text
([format v]
@@ -1119,8 +1120,8 @@
{:href (path/path-join "file://" path)
:data-href path
:target "_blank"}
title
(assoc :title title))
title
(assoc :title title))
(map-inline config label)))
:else
@@ -1213,8 +1214,8 @@
(cond->
{:href (ar-url->http-url href)
:target "_blank"}
title
(assoc :title title))
title
(assoc :title title))
(map-inline config label))
:else
@@ -1223,11 +1224,11 @@
(cond->
{:href href
:target "_blank"}
title
(assoc :title title))
title
(assoc :title title))
(map-inline config label)))))))
(declare ->hiccup)
(declare ->hiccup inline)
(defn wrap-query-components
[config]
@@ -1236,7 +1237,8 @@
:->elem ->elem
:page-cp page-cp
:inline-text inline-text
:map-inline map-inline}))
:map-inline map-inline
:inline inline}))
;;;; Macro component render functions
(defn- macro-query-cp
@@ -1751,7 +1753,7 @@
order-list? (boolean own-number-list?)
order-list-idx (:own-order-list-index config)
collapsable? (editor-handler/collapsable? uuid {:semantic? true})]
[:div.block-control-wrap.mr-1.flex.flex-row.items-center.sm:mr-2
[:div.block-control-wrap.flex.flex-row.items-center
{:class (util/classnames [{:is-order-list order-list?
:bullet-closed collapsed?}])}
(when (or (not fold-button-right?) collapsable?)
@@ -2222,7 +2224,10 @@
(editor-handler/clear-selection!)
(editor-handler/unhighlight-blocks!)
(let [f #(let [block (or (db/pull [:block/uuid (:block/uuid block)]) block)
cursor-range (util/caret-range (gdom/getElement block-id))
cursor-range (some-> (gdom/getElement block-id)
(dom/by-class "block-content-wrapper")
first
util/caret-range)
{:block/keys [content format]} block
content (->> content
(property/remove-built-in-properties format)
@@ -2260,7 +2265,7 @@
(and (not block-content?)
(seq (:block/children block))
(= move-to :nested)))
(dnd-separator move-to block-content?))))))
(dnd-separator move-to block-content?))))))
(defn clock-summary-cp
[block body]
@@ -2331,19 +2336,19 @@
content (if (string? content) (string/trim content) "")
mouse-down-key (if (util/ios?)
:on-click
:on-mouse-down ; TODO: it seems that Safari doesn't work well with on-mouse-down
)
:on-mouse-down) ; TODO: it seems that Safari doesn't work well with on-mouse-down
attrs (cond->
{:blockid (str uuid)
:data-type (name block-type)
:style {:width "100%" :pointer-events (when stop-events? "none")}}
(not (string/blank? (:hl-color properties)))
(assoc :data-hl-color (:hl-color properties))
(not (string/blank? (:hl-color properties)))
(assoc :data-hl-color (:hl-color properties))
(not block-ref?)
(assoc mouse-down-key (fn [e]
(block-content-on-mouse-down e block block-id content edit-input-id))))]
(not block-ref?)
(assoc mouse-down-key (fn [e]
(block-content-on-mouse-down e block block-id content edit-input-id))))]
[:div.block-content.inline
(cond-> {:id (str "block-content-" uuid)
:on-mouse-up (fn [e]
@@ -3021,8 +3026,8 @@
:li
(cond->
{:checked checked?}
number
(assoc :value number))
number
(assoc :value number))
(vec-cat
[(->elem
:p
@@ -3040,52 +3045,55 @@
(defn table
[config {:keys [header groups col_groups]}]
(let [tr (fn [elm cols]
(->elem
:tr
(mapv (fn [col]
(->elem
elm
{:scope "col"
:class "org-left"}
(map-inline config col)))
cols)))
tb-col-groups (try
(mapv (fn [number]
(let [col-elem [:col {:class "org-left"}]]
(->elem
:colgroup
(repeat number col-elem))))
col_groups)
(catch :default _e
[]))
head (when header
[:thead (tr :th header)])
groups (mapv (fn [group]
(->elem
:tbody
(mapv #(tr :td %) group)))
groups)]
[:div.table-wrapper
(->elem
:table
{:class "table-auto"
:border 2
:cell-spacing 0
:cell-padding 6
:rules "groups"
:frame "hsides"}
(vec-cat
tb-col-groups
(cons head groups)))]))
(case (get-shui-component-version :table config)
2 (shui/table-v2 {:data (concat [[header]] groups)}
(make-shui-context config inline))
1 (let [tr (fn [elm cols]
(->elem
:tr
(mapv (fn [col]
(->elem
elm
{:scope "col"
:class "org-left"}
(map-inline config col)))
cols)))
tb-col-groups (try
(mapv (fn [number]
(let [col-elem [:col {:class "org-left"}]]
(->elem
:colgroup
(repeat number col-elem))))
col_groups)
(catch :default _e
[]))
head (when header
[:thead (tr :th header)])
groups (mapv (fn [group]
(->elem
:tbody
(mapv #(tr :td %) group)))
groups)]
[:div.table-wrapper
(->elem
:table
{:class "table-auto"
:border 2
:cell-spacing 0
:cell-padding 6
:rules "groups"
:frame "hsides"}
(vec-cat
tb-col-groups
(cons head groups)))])))
(defn logbook-cp
[log]
(let [clocks (filter #(string/starts-with? % "CLOCK:") log)
clocks (reverse (sort-by str clocks))
clocks (reverse (sort-by str clocks))]
;; TODO: display states change log
; states (filter #(not (string/starts-with? % "CLOCK:")) log)
]
(when (seq clocks)
(let [tr (fn [elm cols] (->elem :tr
(mapv (fn [col] (->elem elm col)) cols)))
@@ -3110,6 +3118,8 @@
[config col]
(map #(inline config %) col))
(declare ->hiccup)
(rum/defc src-cp < rum/static
[config options html-export?]
(when options

View File

@@ -201,11 +201,14 @@
}
.block-control-wrap {
height: 24px;
margin-top: 0;
@apply h-[24px] mt-0 pr-[6px];
&.is-order-list {
@apply relative right-0 mr-0;
@apply mr-0 pr-0;
.bullet-link-wrap {
@apply relative left-[-3px];
}
}
}
@@ -531,12 +534,14 @@
}
&.as-order-list {
@apply w-[28px] whitespace-nowrap justify-start;
@apply w-[22px] whitespace-nowrap justify-center pl-[3px];
}
.bullet {
@apply rounded-full w-[6px] h-[6px];
font-size: 14px;
background-color: var(--ls-block-bullet-color, #394b59);
transition: transform 0.2s;

View File

@@ -46,7 +46,7 @@
(let [show? (rum/react *show-repeater?)]
(if (or show? (and num duration kind))
[:div.w.full.flex.flex-row.justify-left
[:input#repeater-num.form-input.mt-1.w-8.px-1.sm:w-20.sm:px-2.text-center
[:input#repeater-num.form-input.w-8.mr-2.px-1.sm:w-20.sm:px-2.text-center
{:default-value num
:on-change (fn [event]
(let [value (util/evalue event)]
@@ -66,7 +66,7 @@
(swap! *timestamp assoc-in [:repeater :duration] value))
nil)
[:a.ml-1.self-center {:on-click (fn []
[:a.ml-2.self-center {:on-click (fn []
(reset! *show-repeater? false)
(swap! *timestamp assoc :repeater {}))}
svg/close]]

View File

@@ -588,7 +588,7 @@
(async/go
(set-loading? true)
(try
(let [files (async/<! (file-sync-handler/fetch-page-file-versions graph-uuid page-entity))]
(let [files (async/<! (file-sync-handler/<fetch-page-file-versions graph-uuid page-entity))]
(set-version-files files)
(set-page-fn (first files))
(set-list-ready? true))

View File

@@ -38,7 +38,9 @@
[logseq.graph-parser.util :as gp-util]
[medley.core :as medley]
[reitit.frontend.easy :as rfe]
[rum.core :as rum]))
[rum.core :as rum]
[logseq.graph-parser.util.page-ref :as page-ref]
[logseq.graph-parser.mldoc :as gp-mldoc]))
(defn- get-page-name
[state]
@@ -261,7 +263,7 @@
:else
(state/set-modal! (confirm-fn)))
(util/stop e))]
[:span.absolute.inset-0.edit-input-wrapper
[:span.absolute.inset-0.edit-input-wrapper.z-10
{:class (util/classnames [{:editing @*edit?}])}
[:input.edit-input
{:type "text"
@@ -296,7 +298,8 @@
(assoc state ::title-value (atom (nth (:rum/args state) 2))))}
[state page-name icon title _format fmt-journal?]
(when title
(let [*title-value (get state ::title-value)
(let [page (when page-name (db/entity [:block/name page-name]))
*title-value (get state ::title-value)
*edit? (get state ::edit?)
*input-value (get state ::input-value)
repo (state/get-current-repo)
@@ -305,7 +308,9 @@
untitled? (and whiteboard-page? (parse-uuid page-name)) ;; normal page cannot be untitled right?
title (if hls-page?
[:a.asset-ref (pdf-utils/fix-local-asset-pagename title)]
(if fmt-journal? (date/journal-title->custom-format title) title))
(if fmt-journal?
(date/journal-title->custom-format title)
title))
old-name (or title page-name)]
[:h1.page-title.flex.cursor-pointer.gap-1.w-full
{:class (when-not whiteboard-page? "title")
@@ -313,16 +318,17 @@
(when (util/right-click? e)
(state/set-state! :page-title/context {:page page-name})))
:on-click (fn [e]
(.preventDefault e)
(if (gobj/get e "shiftKey")
(when-let [page (db/pull repo '[*] [:block/name page-name])]
(state/sidebar-add-block!
repo
(:db/id page)
:page))
(when (and (not hls-page?) (not fmt-journal?) (not config/publishing?))
(reset! *input-value (if untitled? "" old-name))
(reset! *edit? true))))}
(when-not (= (.-nodeName (.-target e)) "INPUT")
(.preventDefault e)
(if (gobj/get e "shiftKey")
(when-let [page (db/pull repo '[*] [:block/name page-name])]
(state/sidebar-add-block!
repo
(:db/id page)
:page))
(when (and (not hls-page?) (not fmt-journal?) (not config/publishing?))
(reset! *input-value (if untitled? "" old-name))
(reset! *edit? true)))))}
(when (not= icon "") [:span.page-icon icon])
[:div.page-title-sizer-wrapper.relative
(when @*edit?
@@ -338,9 +344,13 @@
{:data-value @*input-value
:data-ref page-name
:style {:opacity (when @*edit? 0)}}
(cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)]
untitled? [:span.opacity-50 (t :untitled)]
:else title)]]])))
(let [nested? (and (string/includes? title page-ref/left-brackets)
(string/includes? title page-ref/right-brackets))]
(cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)]
untitled? [:span.opacity-50 (t :untitled)]
nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config
(:block/format page))))
:else title))]]])))
(defn- page-mouse-over
[e *control-show? *all-collapsed?]

View File

@@ -249,6 +249,7 @@
box-shadow: none;
padding-left: 5px;
padding-top: 5px;
padding-bottom: 4px;
&-wrapper {
@apply rounded;
@@ -276,7 +277,7 @@ a.page-title {
}
> .title {
@apply w-full pointer-events-none overflow-hidden overflow-ellipsis;
@apply w-full overflow-hidden overflow-ellipsis;
}
.edit-input {

View File

@@ -836,6 +836,16 @@
> .injected-ui-item-pagebar {
@apply pr-3 opacity-30 hover:opacity-100 transition-opacity;
}
> .list-wrap {
@apply flex items-center flex-nowrap overflow-x-hidden pt-[14px];
}
a.button {
@apply flex items-center;
color: var(--ls-primary-text-color);
}
}
.toolbar-plugins-manager {

View File

@@ -50,7 +50,7 @@
view-f
result
group-by-page?]}]
(let [{:keys [->hiccup ->elem inline-text page-cp map-inline]} config
(let [{:keys [->hiccup ->elem inline-text page-cp map-inline inline]} config
*query-error query-error-atom
only-blocks? (:block/uuid (first result))
blocks-grouped-by-page? (and group-by-page?
@@ -59,6 +59,7 @@
(:block/name (ffirst result))
(:block/uuid (first (second (first result))))
true)]
(println "this should be a function" inline)
(if @*query-error
(do
(log/error :exception @*query-error)
@@ -77,10 +78,10 @@
(util/hiccup-keywordize result))
page-list?
(query-table/result-table config current-block result {:page? true} map-inline page-cp ->elem inline-text)
(query-table/result-table config current-block result {:page? true} map-inline page-cp ->elem inline-text inline)
table?
(query-table/result-table config current-block result {:page? false} map-inline page-cp ->elem inline-text)
(query-table/result-table config current-block result {:page? false} map-inline page-cp ->elem inline-text inline)
(and (seq result) (or only-blocks? blocks-grouped-by-page?))
(->hiccup result

View File

@@ -3,13 +3,15 @@
[frontend.date :as date]
[frontend.db :as db]
[frontend.db.query-dsl :as query-dsl]
[frontend.format.block :as block]
[frontend.handler.common :as common-handler]
[frontend.handler.editor.property :as editor-property]
[frontend.shui :refer [get-shui-component-version make-shui-context]]
[frontend.state :as state]
[frontend.util :as util]
[frontend.util.clock :as clock]
[frontend.util.property :as property]
[frontend.format.block :as block]
[logseq.shui.core :as shui]
[medley.core :as medley]
[rum.core :as rum]
[logseq.graph-parser.text :as text]))
@@ -42,9 +44,9 @@
(defn- locale-compare
"Use locale specific comparison for strings and general comparison for others."
[x y]
(if (and (number? x) (number? y))
(< x y)
(.localeCompare (str x) (str y) (state/sub :preferred-language) #js {:numeric true})))
(if (and (number? x) (number? y))
(< x y)
(.localeCompare (str x) (str y) (state/sub :preferred-language) #js {:numeric true})))
(defn- sort-result [result {:keys [sort-by-column sort-desc? sort-nlp-date? page?]}]
(if (some? sort-by-column)
@@ -98,7 +100,7 @@
keys (if page? (distinct (concat keys [:created-at :updated-at])) keys)]
keys))
(defn- get-columns [current-block result {:keys [page?]}]
(defn get-columns [current-block result {:keys [page?]}]
(let [query-properties (some-> (get-in current-block [:block/properties :query-properties] "")
(common-handler/safe-read-string "Parsing query properties failed"))
query-properties (if page? (remove #{:block} query-properties) query-properties)
@@ -152,10 +154,21 @@
;; Fallback to original properties for page blocks
(get-in row [:block/properties column])))]))
(defn build-column-text [row column]
(case column
:page (or (get-in row [:block/page :block/original-name])
(get-in row [:block/original-name])
(get-in row [:block/content]))
:block (or (get-in row [:block/original-name])
(get-in row [:block/content]))
(or (get-in row [:block/properties column])
(get-in row [:block/properties-text-values column])
(get-in row [(keyword :block column)]))))
(rum/defcs result-table < rum/reactive
(rum/local false ::select?)
(rum/local false ::mouse-down?)
[state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text]
[state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text inline]
(when current-block
(let [select? (get state ::select?)
*mouse-down? (::mouse-down? state)
@@ -168,53 +181,65 @@
;; as user needs to know if there result is sorted
sort-state (get-sort-state current-block)
sort-result (sort-result result (assoc sort-state :page? page?))
property-separated-by-commas? (partial text/separated-by-commas? (state/get-config))]
[:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e))
:style {:width "100%"}
:class (when-not page? "query-table")}
[:table.table-auto
[:thead
[:tr.cursor
(for [column columns]
(let [title (if (and (= column :clock-time) (integer? clock-time-total))
(util/format "clock-time(total: %s)" (clock/seconds->days:hours:minutes:seconds
clock-time-total))
(name column))]
(sortable-title title column sort-state (:block/uuid current-block))))]]
[:tbody
(for [row sort-result]
(let [format (:block/format row)]
property-separated-by-commas? (partial text/separated-by-commas? (state/get-config))
table-version (get-shui-component-version :table config)
result-as-text (for [row sort-result]
(for [column columns]
(build-column-text row column)))
render-column-value (fn [row-format cell-format value]
(cond
;; elements should be rendered as they are provided
(= :element cell-format) value
;; collections are treated as a comma separated list of page-cps
(coll? value) (->> (map #(page-cp {} {:block/name %}) value)
(interpose [:span ", "]))
;; boolean values need to first be stringified
(boolean? value) (str value)
;; string values will attempt to be rendered as pages, falling back to
;; inline-text when no page entity is found
(string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])]
(page-cp {} page)
(inline-text row-format value))
;; anything else should just be rendered as provided
:else value))]
(case table-version
2 (shui/table-v2 {:data (conj [[columns]] result-as-text)}
(make-shui-context config inline))
1 [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e))
:style {:width "100%"}
:class (when-not page? "query-table")}
[:table.table-auto
[:thead
[:tr.cursor
(for [column columns]
(let [value (build-column-value row
column
{:page? page?
:->elem ->elem
:map-inline map-inline
:config config
:comma-separated-property? (property-separated-by-commas? column)})]
[:td.whitespace-nowrap {:on-mouse-down (fn []
(reset! *mouse-down? true)
(reset! select? false))
:on-mouse-move (fn [] (reset! select? true))
:on-mouse-up (fn []
(when (and @*mouse-down? (not @select?))
(state/sidebar-add-block!
(state/get-current-repo)
(:db/id row)
:block-ref)
(reset! *mouse-down? false)))}
(when value
(if (= :element (first value))
(second value)
(let [value (second value)]
(if (coll? value)
(let [vals (for [row value]
(page-cp {} {:block/name row}))]
(interpose [:span ", "] vals))
(cond
(boolean? value) (str value)
(string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])]
(page-cp {} page)
(inline-text format value))
:else value)))))]))]))]]])))
(let [title (if (and (= column :clock-time) (integer? clock-time-total))
(util/format "clock-time(total: %s)" (clock/seconds->days:hours:minutes:seconds
clock-time-total))
(name column))]
(sortable-title title column sort-state (:block/uuid current-block))))]]
[:tbody
(for [row sort-result]
(let [format (:block/format row)]
[:tr.cursor
(for [column columns]
(let [value (build-column-value row
column
{:page? page?
:->elem ->elem
:map-inline map-inline
:config config
:comma-separated-property? (property-separated-by-commas? column)})]
[:td.whitespace-nowrap {:on-mouse-down (fn []
(reset! *mouse-down? true)
(reset! select? false))
:on-mouse-move (fn [] (reset! select? true))
:on-mouse-up (fn []
(when (and @*mouse-down? (not @select?))
(state/sidebar-add-block!
(state/get-current-repo)
(:db/id row)
:block-ref)
(reset! *mouse-down? false)))}
(when value
(apply render-column-value format value))]))]))]]]))))

View File

@@ -668,14 +668,20 @@
[]
[:div.panel-wrap
[:div.text-sm.my-4
(ui/admonition
:tip
[:p "If you have Logseq Sync enabled, you can view a page's edit history directly. This section is for tech-savvy only."])
[:span.text-sm.opacity-50.my-4
"You can view a page's edit history by clicking the three horizontal dots "
"in the top-right corner and selecting \"View page history\". "
"Logseq uses "]
"To view page's edit history, click the three horizontal dots in the top-right corner and select \"View page history\"."]
[:br][:br]
[:span.text-sm.opacity-50.my-4
"For professional users, Logseq also supports using "]
[:a {:href "https://git-scm.com/" :target "_blank"}
"Git"]
[:span.text-sm.opacity-50.my-4
" for version control."]]
" for version control."]
[:span.text-sm.opacity-50.my-4
"Use Git at your own risk as general Git issues are not supported by the Logseq team"]]
[:br]
(switch-git-auto-commit-row t)
(git-auto-commit-seconds t)
@@ -878,9 +884,7 @@
[[:general "general" (t :settings-page/tab-general) (ui/icon "adjustments")]
[:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing")]
(when (and
(util/electron?)
(not (file-sync-handler/synced-file-graph? current-repo)))
(when (util/electron?)
[:git "git" (t :settings-page/tab-version-control) (ui/icon "history")])
;; (when (util/electron?)
@@ -890,7 +894,7 @@
[:ai "ai" "AI" (ui/icon "wand")]
[:features "features" (t :settings-page/tab-features) (ui/icon "square-asterisk")]
[:features "features" (t :settings-page/tab-features) (ui/icon "app-feature")]
(when plugins-of-settings
[:plugins-setting "plugins" (t :settings-of-plugins) (ui/icon "puzzle")])]]

View File

@@ -770,7 +770,11 @@ independent of format as format specific heading characters are stripped"
:include-start? true
:scoped-block-id scoped-block-id}))
(contains? #{:save-block :delete-blocks} outliner-op)
(and (= :delete-blocks outliner-op)
(<= (count @result) initial-blocks-length)) ; load more blocks
nil
(= :save-block outliner-op)
@result
(contains? #{:insert-blocks :collapse-expand-blocks :move-blocks} outliner-op)
@@ -845,6 +849,7 @@ independent of format as format specific heading characters are stripped"
(db-utils/pull repo-url pull-keys id))) block-eids)
(db-utils/pull-many repo-url pull-keys block-eids))
blocks (remove (fn [b] (nil? (:block/content b))) blocks)]
(map (fn [b] (assoc b :block/page bare-page-map)) blocks)))}
nil)
react)))))
@@ -957,15 +962,8 @@ independent of format as format specific heading characters are stripped"
"Doesn't include nested children."
[repo block-uuid]
(when-let [db (conn/get-db repo)]
(-> (d/q
'[:find [(pull ?b [*]) ...]
:in $ ?parent-id
:where
[?parent :block/uuid ?parent-id]
[?b :block/parent ?parent]]
db
block-uuid)
(sort-by-left (db-utils/entity [:block/uuid block-uuid])))))
(when-let [parent (db-utils/entity repo [:block/uuid block-uuid])]
(sort-by-left (:block/_parent parent) parent))))
(defn get-block-children
"Including nested children."

View File

@@ -16,7 +16,7 @@
;;; keywords specs for reactive query, used by `react/q` calls
;; ::block
;; pull-block react-query
(s/def ::block (s/tuple #(= ::block %) uuid?))
(s/def ::block (s/tuple #(= ::block %) int?))
;; ::page-blocks
;; get page-blocks react-query
(s/def ::page-blocks (s/tuple #(= ::page-blocks %) int?))

View File

@@ -372,6 +372,8 @@
:file-sync/other-user-graph "Current local graph is bound to other user's remote graph. So can't start syncing."
:file-sync/graph-deleted "The current remote graph has been deleted"
:file-sync/rsapi-cannot-upload-err "Unable to start synchronization, please check if the local time is correct."
:notification/clear-all "Clear all"}
@@ -1684,6 +1686,7 @@
:file-sync/other-user-graph "当前本地图谱绑定在其他用户的远程图谱上。因此无法启动同步。"
:file-sync/graph-deleted "当前远程图谱已经删除"
:file-sync/rsapi-cannot-upload-err "无法同步,请检查本机时间是否准确"
:notification/clear-all "清除全部通知"}
@@ -2728,7 +2731,116 @@
:asset/maximize "Maksimer bilde"
:asset/open-in-browser "Åpne bilde i nettleser"
:asset/show-in-folder "Vis bilde i mappe"
:linked-references/filter-search "Søk i lenkede referanser"}
:linked-references/filter-search "Søk i lenkede referanser"
:all-whiteboards "Alle whiteboard"
:auto-heading "Automatisk overskrift"
:heading "Overskrift {1}"
:new-whiteboard "Nytt whiteboard"
:remove-heading "Fjern overskrift"
:untitled "Uten navn"
:accessibility/skip-to-main-content "Hopp til hovedinnhold"
:color/blue "Blå"
:color/gray "Grå"
:color/green "Grønn"
:color/pink "Rosa"
:color/purple "Lilla"
:color/red "Rød"
:color/yellow "Gul"
:content/copy-block-url "Kopier blokk URL"
:content/copy-export-as "Kopier / Eksporter som.."
:content/copy-ref "Kopier denne referansen"
:content/delete-ref "Slett denne referansen"
:content/replace-with-embed "Erstatt med innebygging"
:content/replace-with-text "Erstatt med tekst"
:context-menu/input-template-name "Hva heter malen?"
:context-menu/make-a-flashcard "Lag et Flashcard"
:context-menu/make-a-template "Lag en Mal"
:context-menu/preview-flashcard "Forhåndsvis Flashcard"
:context-menu/template-exists-warning "Malen eksisterer allerde!"
:context-menu/template-include-parent-block "Inkluder overordnet blokk i malen?"
:context-menu/toggle-number-list "Veksle nummerliste"
:dev/show-block-ast "(Dev) Vis blokk AST"
:dev/show-block-data "(Dev) Vis blokk data"
:dev/show-page-ast "(Dev) Vis side AST"
:dev/show-page-data "(Dev) Vis side data"
:editor/collapse-block-children "Skjul alle"
:editor/cycle-todo "Roterer TODO statusen for gjeldende element"
:editor/delete-selection "Slett valgte blokker"
:editor/expand-block-children "Utvid alle"
:file/validate-existing-file-error "Siden eksisterer allerede i en annen fil: {1}, nåværen..."
:file-rn/all-action "Utfør alle Handlinger!"
:file-rn/apply-rename "Utfør omdøping av filen"
:file-rn/close-panel "Lukk Panel"
:file-rn/confirm-proceed "Oppdater format!"
:file-rn/filename-desc-1 "Denne innstillingen konfigurerer hvordan en side blir lagret til en ..."
:file-rn/filename-desc-2 "Noen tegn som \"/\" eller \"?\" er ikke gyldige for en..."
:file-rn/filename-desc-3 "Logseq erstatter ugyldige tegn med deres URL ..."
:file-rn/filename-desc-4 "Skilletegnet for navnerom \"/\" brukes også av \"_..."
:file-rn/format-deprecated "Du bruker for øyeblikket et utdatert format. Oppdat..."
:file-rn/instruct-1 "Det er en to-trinns prosess å oppdatere formatet for filnavn:"
:file-rn/instruct-2 "1. Klikk "
:file-rn/instruct-3 "2. Følg instruksjonene under for å gi filen et nytt navn..."
:file-rn/legend "🟢 Valgfri omdøping; 🟡 Omdøping kreves..."
:file-rn/need-action "Omdøping av fil er anbefalt for å matche de nye..."
:file-rn/no-action "Bra jobba! Well done! Ingen ytterligere tiltak kreves."
:file-rn/optional-rename "Forslag: "
:file-rn/or-select-actions " eller gi filer nytt navn individuelt under, så "
:file-rn/or-select-actions-2 ". Disse handlingene er ikke tilgjengelige når du lukker ..."
:file-rn/otherwise-breaking "Eller tittelen vil bli"
:file-rn/re-index "Re-indksering er sterkt anbefalt etter at filene er..."
:file-rn/rename "Omdøp fil \"{1}\" til \"{2}\""
:file-rn/select-confirm-proceed "Dev: skriv format"
:file-rn/select-format "(Uviklermodus Operasjon, Farlig!) Velg filenav..."
:file-rn/suggest-rename "Handling kreves: "
:file-rn/unreachable-title "Advarsel! Navnet på siden vil bli {1} under nåvære.."
:left-side-bar/create "Opprett"
:left-side-bar/new-whiteboard "Nytt whiteboard"
:notification/clear-all "Fjern alt"
:on-boarding/tour-whiteboard-home "{1} Hjem for dine whiteboards"
:on-boarding/tour-whiteboard-home-description "Whiteboards har sin egen seksjon i appen hvo..."
:on-boarding/tour-whiteboard-new "{1} Lag nytt whiteboard"
:on-boarding/tour-whiteboard-new-description "Det er mange måter å lage et nytt whiteboard på..."
:on-boarding/welcome-whiteboard-modal-description "Whiteboards er et fantastisk verktøy for brainstorming og ..."
:on-boarding/welcome-whiteboard-modal-skip "Hopp over"
:on-boarding/welcome-whiteboard-modal-start "Start med whiteboard"
:on-boarding/welcome-whiteboard-modal-title "Et nytt lerret for dine tanker."
:page/logseq-is-having-a-problem "Logseq har et problem. Prøver å få den tilbake ..."
:page/show-whiteboards "Vis whiteboards"
:page/something-went-wrong "Noe gikk galt"
:page/step "Steg {1}"
:page/try "Prøv"
:pdf/doc-metadata "Dokument metadata"
:pdf/hl-block-colored "Farget merkelapp for å label for utheve blokk"
:plugin/found-n-updates "Fant {1} oppdatering"
:plugin/found-updates "Nye oppateringer"
:plugin/update-all-selected "Oppdater alle valgte"
:plugin/updates-downloading "Laster ned oppdateringer"
:plugin.install-from-file/menu-title "Installer fra plugins.edn"
:plugin.install-from-file/notice "Følgende plugins vil erstatte dine plugins:"
:plugin.install-from-file/success "Alle plugins er installert!"
:plugin.install-from-file/title "Installer plugins fra plugins.edn"
:right-side-bar/history "(Dev) Angre/Gjør om logg"
:right-side-bar/whiteboards "Whiteboards"
:search/items "elementer"
:search-item/block "Blokk"
:search-item/file "Fil"
:search-item/page "Side"
:search-item/whiteboard "Whiteboard"
:select/default-select-multiple "Velg en eller flere"
:settings-page/alpha-features "Alpha funksjoner"
:settings-page/auto-expand-block-refs "Utvid blokkreferanser automatisk når zoomet inn..."
:settings-page/beta-features "Beta funksjoner"
:settings-page/clear-cache-warning "Tømming av hurtigbufferen vil forkaste dine åpne grafer. Du m..."
:settings-page/custom-date-format-warning "Re-indeksering kreves! Eksisterernde dagbokreferanse vi..."
:settings-page/disable-sentry-desc "Logseq vil aldri samle inn dine lokale graf sin databas..."
:settings-page/edit-setting "Rediger"
:settings-page/enable-whiteboards "Whiteboards"
:settings-page/filename-format "Filnavn format"
:settings-page/login-prompt "For å få tilgang til nye funksjoner før alle andre må du..."
:settings-page/preferred-pasting-file "Foretrekk innliming av fil"
:settings-page/show-full-blocks "Vis alle linjer av en blokkreferanse"
:settings-page/tab-assets "Ressurser"
:whiteboard/link-whiteboard-or-block "Lenk whiteboard/side/blokk"}
:pt-BR {:on-boarding/demo-graph "Esse é um grafo de demonstração, mudanças não serão salvas enquanto uma pasta local não for aberta."
:on-boarding/add-graph "Adicionar grafo"
@@ -2811,6 +2923,7 @@
:settings-page/spell-checker "Verificador ortográfico"
:settings-page/disable-sentry "Enviar dados de utilização e diagnósticos para Logseq"
:settings-page/preferred-outdenting "Ativar dedentação lógica"
:settings-page/auto-expand-block-refs "Expandir as referências de bloco automaticamente ao aumentar o zoom"
:settings-page/custom-date-format "Formato de data preferido"
:settings-page/preferred-file-format "Formato de Arquivo preferido"
:settings-page/preferred-workflow "Fluxo de trabalho preferido"
@@ -3138,6 +3251,10 @@
:left-side-bar/new-whiteboard "Novo quadro branco"
:left-side-bar/nav-favorites "Favoritos"
:left-side-bar/nav-recent-pages "Recente"
:page/something-went-wrong "Algo deu errado"
:page/logseq-is-having-a-problem "Logseq está tendo um problema. Para tentar colocá-lo de volta em um estado de funcionamento, por favor tente os seguintes passos seguros em ordem:"
:page/step "Passo {1}"
:page/try "Tentar"
:page/presentation-mode "Modo de apresentação"
:page/delete-confirmation "Tem a certeza de que quer apagar esta página e o respetivo ficheiro?"
:page/open-in-finder "Abrir em pasta"
@@ -3206,8 +3323,12 @@
:color/pink "Rosa"
:editor/copy "Copiar"
:editor/cut "Cortar"
:content/copy-export-as "Copiar / Exportar como.."
:content/copy-block-url "Copiar URL do bloco"
:content/copy-block-ref "Copiar referência do bloco"
:content/copy-block-emebed "Copiar bloco para incorporar"
:content/copy-ref "Copiar esta referência"
:content/delete-ref "Apagar esta referência"
:content/open-in-sidebar "Abrir na barra lateral"
:content/click-to-edit "Clicar para editar"
:settings-page/git-confirm "É necessário reiniciar a aplicação após atualizar as definições do Git."
@@ -3391,12 +3512,14 @@
:command-palette/prompt "Introduza um comando"
:select/default-prompt "Selecione um"
:select/default-select-multiple "Selecione um ou vários"
:select.graph/prompt "Selecione um grafo"
:select.graph/empty-placeholder-description "Sem grafos correspondentes. Quer adicionar outro?"
:select.graph/add-graph "Sim, adicionar outro grafo"
:file-sync/other-user-graph "O grafo local atual está ligado ao grafo remoto de outro utilizador. Portanto, a sincronização não pode ser iniciada."
:file-sync/graph-deleted "O grafo remoto atual foi apagado"
:file-sync/rsapi-cannot-upload-err "Não foi possível iniciar a sincronização, verifique se a hora local está correta."
:notification/clear-all "Limpar tudo"}
@@ -4410,6 +4533,7 @@
:content/open-in-sidebar "Kenar çubuğunda aç"
:content/click-to-edit "Düzenlemek için tıklayın"
:context-menu/make-a-flashcard "Bilgi Kartı Oluştur"
:context-menu/toggle-number-list "Numaralı liste olarak değiştir"
:context-menu/preview-flashcard "Bilgi Kartını Önizle"
:context-menu/make-a-template "Bir Şablon Oluştur"
:context-menu/input-template-name "Şablonun adı nedir?"

View File

@@ -9,7 +9,6 @@
[frontend.handler.notification :as notification]
[frontend.state :as state]
[logseq.graph-parser.block :as gp-block]
[logseq.graph-parser.config :as gp-config]
[logseq.graph-parser.property :as gp-property]
[logseq.graph-parser.mldoc :as gp-mldoc]
[lambdaisland.glogi :as log]))
@@ -23,7 +22,6 @@ and handles unexpected failure."
(gp-block/extract-blocks blocks content with-id? format
{:user-config (state/get-config)
:block-pattern (config/get-block-pattern format)
:supported-formats (gp-config/supported-formats)
:db (db/get-db (state/get-current-repo))
:date-formatter (state/get-date-formatter)
:page-name page-name})

View File

@@ -238,8 +238,7 @@
(when-not contents-matched?
(backup-file repo-dir :backup-dir fpath disk-content))
(db/set-file-last-modified-at! repo rpath mtime)
(p/let [content content]
(db/set-file-content! repo rpath content))
(db/set-file-content! repo rpath content)
(when ok-handler
(ok-handler repo fpath result))
result)

View File

@@ -1680,6 +1680,10 @@
[r]
(some->> (ex-cause r) str (re-find #"graph-not-exist")))
(defn- stop-sync-by-rsapi-response?
[r]
(some->> (ex-cause r) str (re-find #"Request is not yet valid")))
;; type = "change" | "add" | "unlink"
(deftype FileChangeEvent [type dir path stat checksum]
@@ -2594,10 +2598,15 @@
(do (println :graph-has-been-deleted r*)
{:graph-has-been-deleted true})
(stop-sync-by-rsapi-response? r*)
(do (println :stop-sync-caused-by-rsapi-err-response r*)
(notification/show! (t :file-sync/rsapi-cannot-upload-err) :warning false)
{:stop true})
paused?
{:pause true}
succ? ; succ
succ? ; succ
(do
(println "sync-local->remote! update txid" r*)
;; persist txid

View File

@@ -6,7 +6,6 @@
[frontend.db :as db]
[frontend.db.model :as db-model]
[frontend.db.react :as react]
[frontend.db.utils :as db-utils]
[frontend.mobile.haptics :as haptics]
[frontend.modules.outliner.core :as outliner-core]
[frontend.modules.outliner.transaction :as outliner-tx]
@@ -70,14 +69,9 @@
(util/distinct-by :db/id))))))
(defn indentable?
[{:block/keys [parent] :as block}]
[{:block/keys [parent left]}]
(when parent
(let [parent-block (db-utils/pull (:db/id parent))
first-child (first
(db-model/get-block-immediate-children
(state/get-current-repo)
(:block/uuid parent-block)))]
(not= (:db/id block) (:db/id first-child)))))
(not= parent left)))
(defn outdentable?
[{:block/keys [level] :as _block}]

View File

@@ -5,7 +5,6 @@
[frontend.db :as db]
[logseq.graph-parser :as graph-parser]
[logseq.graph-parser.util :as gp-util]
[logseq.graph-parser.config :as gp-config]
[frontend.fs.diff-merge :as diff-merge]
[frontend.fs :as fs]
[frontend.context.i18n :refer [t]]
@@ -75,13 +74,13 @@
:fs/reset-event - the event that triggered the file update
:fs/local-file-change - file changed on local disk
:fs/remote-file-change - file changed on remote"
[repo-url file content {:fs/keys [event] :as options}]
[repo-url file-path content {:fs/keys [event] :as options}]
(let [db-conn (db/get-db repo-url false)]
(case event
;; the file is already in db, so we can use the existing file's blocks
;; to do the diff-merge
:fs/local-file-change
(graph-parser/parse-file db-conn file content (assoc-in options [:extract-options :resolve-uuid-fn] diff-merge-uuids-2ways))
(graph-parser/parse-file db-conn file-path content (assoc-in options [:extract-options :resolve-uuid-fn] diff-merge-uuids-2ways))
;; TODO Junyi: 3 ways to handle remote file change
;; The file is on remote, so we should have
@@ -91,7 +90,7 @@
;; 2. a "remote version" just fetched from remote
;; default to parse the file
(graph-parser/parse-file db-conn file content options))))
(graph-parser/parse-file db-conn file-path content options))))
(defn reset-file!
"Main fn for updating a db with the results of a parsed file"
@@ -107,7 +106,6 @@
{:user-config (state/get-config)
:date-formatter (state/get-date-formatter)
:block-pattern (config/get-block-pattern (gp-util/get-format file-path))
:supported-formats (gp-config/supported-formats)
:filename-format (state/get-filename-format repo-url)}
;; To avoid skipping the `:or` bounds for keyword destructuring
(when (some? extracted-block-ids) {:extracted-block-ids extracted-block-ids})

View File

@@ -426,7 +426,7 @@
(not has-children?))]
(outliner-tx/transact!
{:outliner-op :insert-blocks}
(save-current-block! {:current-block current-block})
(save-current-block! {:current-block current-block})
(outliner-core/insert-blocks! [new-block] current-block {:sibling? sibling?
:keep-uuid? keep-uuid?
:replace-empty-target? replace-empty-target?}))))
@@ -753,30 +753,28 @@
(outliner-core/delete-blocks! [block] {:children? children?})))))
(defn- move-to-prev-block
([repo sibling-block format id value]
(move-to-prev-block repo sibling-block format id value true))
([repo sibling-block format id value edit?]
(when (and repo sibling-block)
(when-let [sibling-block-id (dom/attr sibling-block "blockid")]
(when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])]
(let [original-content (util/trim-safe (:block/content block))
value' (-> (property/remove-built-in-properties format original-content)
(drawer/remove-logbook))
new-value (str value' value)
tail-len (count value)
pos (max
(if original-content
(gobj/get (utf8/encode original-content) "length")
0)
0)]
(when edit?
(edit-block! block pos id
{:custom-content new-value
:tail-len tail-len
:move-cursor? false}))
{:prev-block block
:new-content new-value
:pos pos}))))))
[repo sibling-block format id value move?]
(when (and repo sibling-block)
(when-let [sibling-block-id (dom/attr sibling-block "blockid")]
(when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])]
(let [original-content (util/trim-safe (:block/content block))
value' (-> (property/remove-built-in-properties format original-content)
(drawer/remove-logbook))
new-value (str value' value)
tail-len (count value)
pos (max
(if original-content
(gobj/get (utf8/encode original-content) "length")
0)
0)
f (fn [] (edit-block! block pos id
{:custom-content new-value
:tail-len tail-len
:move-cursor? false}))]
(when move? (f))
{:prev-block block
:new-content new-value
:move-fn f})))))
(declare save-block!)
@@ -802,7 +800,7 @@
(when block-parent-id
(let [block-parent (gdom/getElement block-parent-id)
sibling-block (util/get-prev-block-non-collapsed-non-embed block-parent)
{:keys [prev-block new-content]} (move-to-prev-block repo sibling-block format id value)
{:keys [prev-block new-content move-fn]} (move-to-prev-block repo sibling-block format id value false)
concat-prev-block? (boolean (and prev-block new-content))
transact-opts (cond->
{:outliner-op :delete-block}
@@ -812,7 +810,8 @@
(outliner-tx/transact! transact-opts
(when concat-prev-block?
(save-block! repo prev-block new-content))
(delete-block-aux! block delete-children?))))))))))
(delete-block-aux! block delete-children?))
(move-fn)))))))))
(state/set-editor-op! nil)))
(defn delete-blocks!
@@ -829,7 +828,8 @@
(move-to-prev-block repo sibling-block
(:block/format block)
(dom/attr sibling-block "id")
"")))))
""
true)))))
(defn- set-block-property-aux!
[block-or-id key value]
@@ -1231,10 +1231,17 @@
(defn save-block!
([repo block-or-uuid content]
(save-block! repo block-or-uuid content {}))
([repo block-or-uuid content {:keys [properties] :or {}}]
(let [block (if (or (uuid? block-or-uuid)
(string? block-or-uuid))
(db-model/query-block-by-uuid block-or-uuid) block-or-uuid)]
(save-block! {:block block :repo repo} content)))
(save-block!
{:block block :repo repo}
(if (seq properties)
(property/insert-properties (:block/format block) content properties)
content)
)))
([{:keys [block repo] :as _state} value]
(let [repo (or repo (state/get-current-repo))]
(when (db/entity repo [:block/uuid (:block/uuid block)])
@@ -1244,8 +1251,8 @@
[blocks]
(outliner-tx/transact!
{:outliner-op :save-block}
(doseq [[block value] blocks]
(save-block-if-changed! block value))))
(doseq [[block value] blocks]
(save-block-if-changed! block value))))
(defn save-current-block!
"skip-properties? if set true, when editing block is likely be properties, skip saving"
@@ -1832,8 +1839,9 @@
(and (= content "1. ") (= last-input-char " ") input-id edit-block
(not (own-order-number-list? edit-block)))
(do
(state/pub-event! [:editor/toggle-own-number-list edit-block])
(state/set-edit-content! input-id ""))
(state/set-edit-content! input-id "")
(-> (p/delay 10)
(p/then #(state/pub-event! [:editor/toggle-own-number-list edit-block]))))
(and (= last-input-char (state/get-editor-command-trigger))
(or (re-find #"(?m)^/" (str (.-value input))) (start-of-new-word? input pos)))
@@ -1964,7 +1972,7 @@
:or {exclude-properties []
edit? true}}]
(let [editing-block (when-let [editing-block (state/get-edit-block)]
(some-> (db/pull (:db/id editing-block))
(some-> (db/pull [:block/uuid (:block/uuid editing-block)])
(assoc :block/content (state/get-edit-content))))
has-unsaved-edits (and editing-block
(not= (:block/content (db/pull (:db/id editing-block)))
@@ -2455,8 +2463,9 @@
:else
(profile
"Insert block"
(do (save-current-block!)
(insert-new-block! state)))))))))
(outliner-tx/transact! {:outliner-op :insert-blocks}
(save-current-block!)
(insert-new-block! state)))))))))
(defn- inside-of-single-block
"When we are in a single block wrapper, we should always insert a new line instead of new block"
@@ -2610,15 +2619,18 @@
^js input (state/get-input)
current-pos (cursor/pos input)
value (gobj/get input "value")
right (outliner-core/get-right-node (outliner-core/block current-block))
right (outliner-core/get-right-sibling (:db/id current-block))
current-block-has-children? (db/has-children? (:block/uuid current-block))
collapsed? (util/collapsed? current-block)
first-child (:data (tree/-get-down (outliner-core/block current-block)))
next-block (if (or collapsed? (not current-block-has-children?))
(:data right)
(when right (db/pull (:db/id right)))
first-child)]
(cond
(and collapsed? right (db/has-children? (tree/-get-id right)))
(nil? next-block)
nil
(and collapsed? right (db/has-children? (:block/uuid right)))
nil
(and (not collapsed?) first-child (db/has-children? (:block/uuid first-child)))
@@ -2760,7 +2772,7 @@
(outliner-tx/transact!
{:outliner-op :move-blocks
:real-outliner-op :indent-outdent}
(outliner-core/indent-outdent-blocks! [block] indent?)))
(outliner-core/indent-outdent-blocks! [block] indent?)))
(state/set-editor-op! :nil)))
(defn keydown-tab-handler
@@ -3148,7 +3160,7 @@
(state/selection?)
(shortcut-delete-selection e)
(whiteboard?)
(and (whiteboard?) (not (state/editing?)))
(.deleteShapes (.-api ^js (state/active-tldraw-app)))
:else
@@ -3203,9 +3215,9 @@
;; if the move is to cross block boundary, select the whole block
(or (and (= direction :up) (cursor/textarea-cursor-rect-first-row? cursor-rect))
(and (= direction :down) (cursor/textarea-cursor-rect-last-row? cursor-rect)))
(select-block-up-down direction)
(select-block-up-down direction)
;; simulate text selection
(cursor/select-up-down input direction anchor cursor-rect)))
(cursor/select-up-down input direction anchor cursor-rect)))
(select-block-up-down direction))))
(defn open-selected-block!

View File

@@ -70,8 +70,7 @@
[logseq.db.schema :as db-schema]
[logseq.graph-parser.config :as gp-config]
[promesa.core :as p]
[rum.core :as rum]
[logseq.common.path :as path]))
[rum.core :as rum]))
;; TODO: should we move all events here?
@@ -609,10 +608,9 @@
(plugin/open-waiting-updates-modal!))
(plugin-handler/set-auto-checking! false))))))
(defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data tx-meta] :as payload}]]
(defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data] :as payload}]]
(when-let [payload (and (seq blocks)
(merge payload {:tx-data (map #(into [] %) tx-data)
:tx-meta (dissoc tx-meta :editor-cursor)}))]
(merge payload {:tx-data (map #(into [] %) tx-data)}))]
(plugin-handler/hook-plugin-db :changed payload)
(plugin-handler/hook-plugin-block-changes payload)))
@@ -624,13 +622,7 @@
(defmethod handle :mobile-file-watcher/changed [[_ ^js event]]
(let [type (.-event event)
payload (js->clj event :keywordize-keys true)
dir (:dir payload)
payload (-> payload
(update :path
(fn [path]
(when (string? path)
(path/relative-path dir path)))))]
payload (js->clj event :keywordize-keys true)]
(fs-watcher/handle-changed! type payload)
(when (file-sync-handler/enable-sync?)
(sync/file-watch-handler type payload))))

View File

@@ -164,33 +164,32 @@
(defn- block-table
[{:keys [header groups]}]
(when (seq header)
(let [level (dec (get *state* :current-level 1))
sep-line (raw-text "|" (string/join "|" (repeat (count header) "---")) "|")
header-line
(concatv (mapcatv
(fn [h] (concatv [space (raw-text "|") space] (mapcatv inline-ast->simple-ast h)))
header)
[space (raw-text "|")])
group-lines
(mapcatv
(fn [group]
(mapcatv
(fn [row]
(concatv [(indent-with-2-spaces level)]
(mapcatv
(fn [col]
(concatv [(raw-text "|") space]
(mapcatv inline-ast->simple-ast col)
[space]))
row)
[(raw-text "|") (newline* 1)]))
group))
groups)]
(concatv [(newline* 1) (indent-with-2-spaces level)]
header-line
[(newline* 1) (indent-with-2-spaces level) sep-line (newline* 1)]
group-lines))))
(let [level (dec (get *state* :current-level 1))
sep-line (raw-text "|" (string/join "|" (repeat (count header) "---")) "|")
header-line
(concatv (mapcatv
(fn [h] (concatv [space (raw-text "|") space] (mapcatv inline-ast->simple-ast h)))
header)
[space (raw-text "|")])
group-lines
(mapcatv
(fn [group]
(mapcatv
(fn [row]
(concatv [(indent-with-2-spaces level)]
(mapcatv
(fn [col]
(concatv [(raw-text "|") space]
(mapcatv inline-ast->simple-ast col)
[space]))
row)
[(raw-text "|") (newline* 1)]))
group))
groups)]
(concatv [(newline* 1) (indent-with-2-spaces level)]
(when (seq header) header-line)
(when (seq header) [(newline* 1) (indent-with-2-spaces level) sep-line (newline* 1)])
group-lines)))
(defn- block-comment
[s]

View File

@@ -16,7 +16,6 @@
[cljs-time.coerce :as tc]
[cljs-time.core :as t]
[frontend.storage :as storage]
[logseq.graph-parser.util :as gp-util]
[lambdaisland.glogi :as log]))
(def *beta-unavailable? (volatile! false))
@@ -163,24 +162,19 @@
version-file-paths)
(remove nil?))))))))
(defn fetch-page-file-versions [graph-uuid page]
(defn <fetch-page-file-versions [graph-uuid page]
[]
(let [file-id (:db/id (:block/file page))]
(when-let [path (:file/path (db/entity file-id))]
(let [base-path (config/get-repo-dir (state/get-current-repo))
base-path (if (string/starts-with? base-path "file://")
(gp-util/safe-decode-uri-component base-path)
base-path)
path* (string/replace-first (string/replace-first path base-path "") #"^/" "")]
(go
(let [version-list (:VersionList
(<! (sync/<get-remote-file-versions sync/remoteapi graph-uuid path*)))
local-version-list (<! (<list-file-local-versions page))
all-version-list (->> (concat version-list local-version-list)
(sort-by #(or (:CreateTime %)
(:create-time %))
>))]
all-version-list))))))
(go
(when-let [path (:file/path (db/entity file-id))]
(let [version-list (:VersionList
(<! (sync/<get-remote-file-versions sync/remoteapi graph-uuid path)))
local-version-list (<! (<list-file-local-versions page))
all-version-list (->> (concat version-list local-version-list)
(sort-by #(or (:CreateTime %)
(:create-time %))
>))]
all-version-list)))))
(defn init-remote-graph

View File

@@ -87,7 +87,9 @@
;; See https://developer.chrome.com/blog/web-custom-formats-for-the-async-clipboard-api/
;; for a similar example
(defn get-copied-blocks []
(p/let [clipboard-items (when (and js/window (gobj/get js/window "navigator") js/navigator.clipboard)
;; NOTE: Avoid using navigator clipboard API on Android, it will report a permission error
(p/let [clipboard-items (when (and (not (mobile-util/native-android?))
js/window (gobj/get js/window "navigator") js/navigator.clipboard)
(js/navigator.clipboard.read))
blocks-blob ^js (when clipboard-items
(let [types (.-types ^js (first clipboard-items))]

View File

@@ -89,11 +89,12 @@
(let [assets (js->clj-keywordize (.getCleanUpAssets app))
new-shapes (.-shapes tl-page)
shapes-index (map #(gobj/get % "id") new-shapes)
shape-id->index (zipmap shapes-index (range (.-length new-shapes)))
upsert-shapes (->> (set/difference new-id-nonces db-id-nonces)
(map (fn [{:keys [id]}]
(-> (.-serialized ^js (.getShapeById tl-page id))
js->clj-keywordize
(assoc :index (.indexOf shapes-index id)))))
(assoc :index (get shape-id->index id)))))
(set))
old-ids (set (map :id db-id-nonces))
new-ids (set (map :id new-id-nonces))
@@ -134,13 +135,15 @@
(defn transact-tldr-delta! [page-name ^js app replace?]
(let [tl-page ^js (second (first (.-pages app)))
shapes (.-shapes ^js tl-page)
shapes-index (map #(gobj/get % "id") shapes)
new-id-nonces (set (map (fn [shape]
page-block (model/get-page page-name)
prev-shapes-index (get-in page-block [:block/properties :logseq.tldraw.page :shapes-index])
shape-id->prev-index (zipmap prev-shapes-index (range (count prev-shapes-index)))
new-id-nonces (set (map-indexed (fn [idx shape]
(let [id (.-id shape)]
{:id id
:nonce (if (= shape.id (.indexOf shapes-index id))
(.-nonce shape)
(.getTime (js/Date.)))})) shapes))
{:id id
:nonce (if (= idx (get shape-id->prev-index id))
(.-nonce shape)
(js/Date.now))})) shapes))
repo (state/get-current-repo)
db-id-nonces (or
(get-in @*last-shapes-nonce [repo page-name])

View File

@@ -44,7 +44,7 @@
[txs]
(filterv (fn [[_ a & y]]
(= :block/content a))
txs))
txs))
(defn get-content-from-stack
"For test."
@@ -60,22 +60,21 @@
(when-let [stack @undo-stack]
(when (seq stack)
(let [removed-e (peek stack)
popped-stack (pop stack)
prev-e (peek popped-stack)]
popped-stack (pop stack)]
(reset! undo-stack popped-stack)
[removed-e prev-e])))))
removed-e)))))
(defn push-redo
[txs]
(let [redo-stack (get-redo-stack)]
(swap! redo-stack conj txs)))
(swap! redo-stack conj txs)))
(defn pop-redo
[]
(let [redo-stack (get-redo-stack)]
(when-let [removed-e (peek @redo-stack)]
(swap! redo-stack pop)
removed-e)))
(when-let [removed-e (peek @redo-stack)]
(swap! redo-stack pop)
removed-e)))
(defn page-pop-redo
[page-id]
@@ -119,7 +118,7 @@
(and redo? (not add?)) :db/retract
(and (not redo?) (not add?)) :db/add)]
[op id attr value tx]))
txs)))
txs)))
;;;; Invokes
@@ -128,7 +127,7 @@
(let [conn (conn/get-db false)]
(d/transact! conn txs tx-meta)))
(defn page-pop-undo
(defn- page-pop-undo
[page-id]
(let [undo-stack (get-undo-stack)]
(when-let [stack @undo-stack]
@@ -144,7 +143,7 @@
others (vec (concat before after))]
(reset! undo-stack others)
(prn "[debug] undo remove: " (nth stack idx'))
[(nth stack idx') others])))))))
(nth stack idx'))))))))
(defn- smart-pop-undo
[]
@@ -154,56 +153,77 @@
(pop-undo))
(pop-undo)))
(defn- set-editor-content!
"Prevent block auto-save during undo/redo."
[]
(when-let [block (state/get-edit-block)]
(state/set-edit-content! (state/get-edit-input-id)
(:block/content (db/entity (:db/id block))))))
(defn- get-next-tx-editor-cursor
[tx-id]
(let [result (->> (sort (keys (:history/tx->editor-cursor @state/state)))
(split-with #(not= % tx-id))
second)]
(when (> (count result) 1)
(when-let [next-tx-id (nth result 1)]
(get-in @state/state [:history/tx->editor-cursor next-tx-id])))))
(defn- get-previous-tx-id
[tx-id]
(let [result (->> (sort (keys (:history/tx->editor-cursor @state/state)))
(split-with #(not= % tx-id))
first)]
(when (>= (count result) 1)
(last result))))
(defn- get-previous-tx-editor-cursor
[tx-id]
(when-let [prev-tx-id (get-previous-tx-id tx-id)]
(get-in @state/state [:history/tx->editor-cursor prev-tx-id])))
(defn undo
[]
(let [[e prev-e] (smart-pop-undo)]
(when e
(let [{:keys [txs tx-meta]} e
new-txs (get-txs false txs)
undo-delete-concat-block? (and (= :delete-block (:outliner-op tx-meta))
(seq (:concat-data tx-meta)))
editor-cursor (cond
undo-delete-concat-block?
(let [data (:concat-data tx-meta)]
(assoc (:editor-cursor e)
:last-edit-block {:block/uuid (:last-edit-block data)}
:pos (if (:end? data) :max 0)))
;; same block
(= (get-in e [:editor-cursor :last-edit-block :block/uuid])
(get-in prev-e [:editor-cursor :last-edit-block :block/uuid]))
(:editor-cursor prev-e)
:else
(:editor-cursor e))]
(push-redo e)
(transact! new-txs (merge {:undo? true}
tx-meta
(select-keys e [:pagination-blocks-range])))
(when undo-delete-concat-block?
(when-let [block (state/get-edit-block)]
(state/set-edit-content! (state/get-edit-input-id)
(:block/content (db/entity (:db/id block))))))
(when (:whiteboard/transact? tx-meta)
(state/pub-event! [:whiteboard/undo e]))
(assoc e
:txs-op new-txs
:editor-cursor editor-cursor)))))
(when-let [e (smart-pop-undo)]
(let [{:keys [txs tx-meta tx-id]} e
new-txs (get-txs false txs)
current-editor-cursor (get-in @state/state [:history/tx->editor-cursor tx-id])
save-block? (= (:outliner-op tx-meta) :save-block)
prev-editor-cursor (get-previous-tx-editor-cursor tx-id)
editor-cursor (if (and save-block?
(= (:block/uuid (:last-edit-block prev-editor-cursor))
(:block/uuid (state/get-edit-block))))
prev-editor-cursor
current-editor-cursor)]
(push-redo e)
(transact! new-txs (merge {:undo? true}
tx-meta
(select-keys e [:pagination-blocks-range])))
(set-editor-content!)
(when (:whiteboard/transact? tx-meta)
(state/pub-event! [:whiteboard/undo e]))
(assoc e
:txs-op new-txs
:editor-cursor editor-cursor))))
(defn redo
[]
(when-let [{:keys [txs tx-meta] :as e} (smart-pop-redo)]
(let [new-txs (get-txs true txs)]
(when-let [{:keys [txs tx-meta tx-id] :as e} (smart-pop-redo)]
(let [new-txs (get-txs true txs)
current-editor-cursor (get-in @state/state [:history/tx->editor-cursor tx-id])
editor-cursor (if (= (:outliner-op tx-meta) :save-block)
current-editor-cursor
(get-next-tx-editor-cursor tx-id))]
(push-undo e)
(transact! new-txs (merge {:redo? true}
tx-meta
(select-keys e [:pagination-blocks-range])))
(set-editor-content!)
(when (:whiteboard/transact? tx-meta)
(state/pub-event! [:whiteboard/redo e]))
(assoc e :txs-op new-txs))))
(assoc e
:txs-op new-txs
:editor-cursor editor-cursor))))
(defn toggle-undo-redo-mode!
[]
@@ -231,14 +251,14 @@
#{:block/created-at :block/updated-at})))
(reset-redo)
(if (:replace? tx-meta)
(let [[removed-e _prev-e] (pop-undo)
(let [removed-e (pop-undo)
entity (update removed-e :txs concat tx-data)]
(push-undo entity))
(let [updated-blocks (db-report/get-blocks tx-report)
entity {:blocks updated-blocks
entity {:tx-id (get-in tx-report [:tempids :db/current-tx])
:blocks updated-blocks
:txs tx-data
:tx-meta tx-meta
:editor-cursor (:editor-cursor tx-meta)
:pagination-blocks-range (get-in [:ui/pagination-blocks-range (get-in tx-report [:db-after :max-tx])] @state/state)
:app-state (select-keys @state/state
[:route-match

View File

@@ -16,8 +16,7 @@
[logseq.graph-parser.util :as gp-util]
[cljs.spec.alpha :as s]))
(s/def ::block-map (s/keys :req [:db/id]
:opt [:block/page :block/left :block/parent]))
(s/def ::block-map (s/keys :opt [:db/id :block/uuid :block/page :block/left :block/parent]))
(s/def ::block-map-or-entity (s/or :entity de/entity?
:map ::block-map))
@@ -26,8 +25,14 @@
(defn block
[m]
(assert (map? m) (util/format "block data must be map, got: %s %s" (type m) m))
(->Block m))
(assert (or (map? m) (de/entity? m)) (util/format "block data must be map or entity, got: %s %s" (type m) m))
(if (de/entity? m)
(->Block {:db/id (:db/id m)
:block/uuid (:block/uuid m)
:block/page (:block/page m)
:block/left (:block/left m)
:block/parent (:block/parent m)})
(->Block m)))
(defn get-data
[block]
@@ -145,42 +150,49 @@
m)
other-tx (:db/other-tx m)
id (:db/id (:data this))
block-entity (db/entity id)
remove-self-page #(remove (fn [b]
(= (:db/id b) (:db/id (:block/page block-entity)))) %)
old-refs (remove-self-page (:block/refs block-entity))
new-refs (remove-self-page (:block/refs m))]
block-entity (db/entity id)]
(when (seq other-tx)
(swap! txs-state (fn [txs]
(vec (concat txs other-tx)))))
(when id
;; Retract attributes to prepare for tx which rewrites block attributes
(swap! txs-state (fn [txs]
(vec
(concat txs
(map (fn [attribute]
[:db/retract id attribute])
db-schema/retract-attributes)))))
db-schema/retract-attributes)))))
;; Update block's page attributes
(when-let [e (:block/page block-entity)]
(let [m' {:db/id (:db/id e)
:block/updated-at (util/time-ms)}
m' (if (:block/created-at e)
m'
(assoc m' :block/created-at (util/time-ms)))
m' (if (or (:block/pre-block? block-entity)
(:block/pre-block? m))
(let [properties (:block/properties m)
alias (set (:alias properties))
tags (set (:tags properties))
alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias)
tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags)]
(assoc m'
:block/alias alias
:block/tags tags
:block/properties properties))
m')]
(swap! txs-state conj m'))
(let [m' (cond-> {:db/id (:db/id e)
:block/updated-at (util/time-ms)}
(not (:block/created-at e))
(assoc :block/created-at (util/time-ms)))
txs (if (or (:block/pre-block? block-entity)
(:block/pre-block? m))
(let [properties (:block/properties m)
alias (set (:alias properties))
tags (set (:tags properties))
alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias)
tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags)
deleteable-page-attributes {:block/alias alias
:block/tags tags
:block/properties properties
:block/properties-text-values (:block/properties-text-values m)}
;; Retract page attributes to allow for deletion of page attributes
page-retractions
(mapv #(vector :db/retract (:db/id e) %) (keys deleteable-page-attributes))]
(conj page-retractions (merge m' deleteable-page-attributes)))
[m'])]
(swap! txs-state into txs)))
;; Remove orphaned refs from block
(let [remove-self-page #(remove (fn [b]
(= (:db/id b) (:db/id (:block/page block-entity)))) %)
old-refs (remove-self-page (:block/refs block-entity))
new-refs (remove-self-page (:block/refs m))]
(remove-orphaned-page-refs! (:db/id block-entity) txs-state old-refs new-refs)))
(swap! txs-state conj (dissoc m :db/other-tx))
@@ -228,11 +240,6 @@
children (db-model/get-block-immediate-children (state/get-current-repo) parent-id)]
(map block children))))
(defn get-right-node
[node]
{:pre [(tree/satisfied-inode? node)]}
(tree/-get-right node))
(defn get-right-sibling
[db-id]
(when db-id
@@ -404,7 +411,7 @@
(let [level-blocks (blocks-with-level blocks)]
(filter (fn [b] (= 1 (:block/level b))) level-blocks)))
(defn get-right-siblings
(defn- get-right-siblings
"Get `node`'s right siblings."
[node]
{:pre [(tree/satisfied-inode? node)]}
@@ -474,7 +481,7 @@
(:db/id target-block))
get-new-id (fn [block lookup]
(cond
(or (map? lookup) (vector? lookup))
(or (map? lookup) (vector? lookup) (de/entity? lookup))
(when-let [uuid (if (and (vector? lookup) (= (first lookup) :block/uuid))
(get uuids (last lookup))
(get id->new-uuid (:db/id lookup)))]
@@ -507,6 +514,13 @@
(dissoc :db/id)))))
blocks)))
(defn- get-target-block
[target-block]
(if (:db/id target-block)
(db/pull (:db/id target-block))
(when (:block/uuid target-block)
(db/pull [:block/uuid (:block/uuid target-block)]))))
(defn insert-blocks
"Insert blocks as children (or siblings) of target-node.
Args:
@@ -524,7 +538,7 @@
[blocks target-block {:keys [sibling? keep-uuid? outliner-op replace-empty-target?] :as opts}]
{:pre [(seq blocks)
(s/valid? ::block-map-or-entity target-block)]}
(let [target-block' (db/pull (:db/id target-block))
(let [target-block' (get-target-block target-block)
_ (assert (some? target-block') (str "Invalid target: " target-block))
sibling? (if (page-block? target-block') false sibling?)
move? (contains? #{:move-blocks :move-blocks-up-down :indent-outdent-blocks} outliner-op)
@@ -710,7 +724,9 @@
[blocks target-block {:keys [sibling? outliner-op]}]
[:pre [(seq blocks)
(s/valid? ::block-map-or-entity target-block)]]
(let [non-consecutive-blocks? (seq (db-model/get-non-consecutive-blocks blocks))
(let [target-block (get-target-block target-block)
_ (assert (some? target-block) (str "Invalid target: " target-block))
non-consecutive-blocks? (seq (db-model/get-non-consecutive-blocks blocks))
original-position? (move-to-original-position? blocks target-block sibling? non-consecutive-blocks?)]
(when (and (not (contains? (set (map :db/id blocks)) (:db/id target-block)))
(not original-position?))

View File

@@ -3,6 +3,7 @@
#?(:cljs (:require-macros [frontend.modules.outliner.datascript]))
#?(:cljs (:require [datascript.core :as d]
[frontend.db.conn :as conn]
[frontend.db :as db]
[frontend.modules.outliner.pipeline :as pipelines]
[frontend.modules.editor.undo-redo :as undo-redo]
[frontend.state :as state]
@@ -45,9 +46,14 @@
v)))
x))))))
#?(:cljs
(defn get-tx-id
[tx-report]
(get-in tx-report [:tempids :db/current-tx])))
#?(:cljs
(defn transact!
[txs opts]
[txs opts before-editor-cursor]
(let [txs (remove-nil-from-transaction txs)
txs (map (fn [m] (if (map? m)
(dissoc m
@@ -65,9 +71,15 @@
(try
(let [repo (get opts :repo (state/get-current-repo))
conn (conn/get-db repo false)
editor-cursor (state/get-current-edit-block-and-position)
meta (merge opts {:editor-cursor editor-cursor})
rs (d/transact! conn txs (assoc meta :outliner/transact? true))]
rs (d/transact! conn txs (assoc opts :outliner/transact? true))
tx-id (get-tx-id rs)]
(swap! state/state assoc-in [:history/tx->editor-cursor tx-id] before-editor-cursor)
;; update the current edit block to include full information
(when-let [block (state/get-edit-block)]
(when (and (:block/uuid block) (not (:db/id block)))
(state/set-state! :editor/block (db/pull [:block/uuid (:block/uuid block)]))))
(when true ; TODO: add debug flag
(let [eids (distinct (mapv first (:tx-data rs)))
left&parent-list (->>

View File

@@ -27,7 +27,8 @@
`(let [transact-data# frontend.modules.outliner.core/*transaction-data*
opts# (if transact-data#
(assoc ~opts :nested-transaction? true)
~opts)]
~opts)
before-editor-cursor# (frontend.state/get-current-edit-block-and-position)]
(if transact-data#
(do ~@body)
(binding [frontend.modules.outliner.core/*transaction-data* (transient [])]
@@ -40,7 +41,7 @@
opts## (merge (dissoc opts# :additional-tx) tx-meta#)]
(when (seq all-tx#) ;; If it's empty, do nothing
(when-not (:nested-transaction? opts#) ; transact only for the whole transaction
(let [result# (frontend.modules.outliner.datascript/transact! all-tx# opts##)]
(let [result# (frontend.modules.outliner.datascript/transact! all-tx# opts## before-editor-cursor#)]
{:tx-report result#
:tx-data all-tx#
:tx-meta tx-meta#}))))))))

View File

@@ -72,34 +72,34 @@
:pdf/find {:binding "alt+f"
:fn pdf-utils/open-finder}
:whiteboard/select {:binding ["1" "s"]
:whiteboard/select {:binding ["1" "w s"]
:fn #(.selectTool ^js (state/active-tldraw-app) "select")}
:whiteboard/pan {:binding ["2" "p"]
:whiteboard/pan {:binding ["2" "w p"]
:fn #(.selectTool ^js (state/active-tldraw-app) "move")}
:whiteboard/portal {:binding "3"
:whiteboard/portal {:binding ["3" "w b"]
:fn #(.selectTool ^js (state/active-tldraw-app) "logseq-portal")}
:whiteboard/pencil {:binding ["4" "d"]
:whiteboard/pencil {:binding ["4" "w d"]
:fn #(.selectTool ^js (state/active-tldraw-app) "pencil")}
:whiteboard/highlighter {:binding ["5" "h"]
:whiteboard/highlighter {:binding ["5" "w h"]
:fn #(.selectTool ^js (state/active-tldraw-app) "highlighter")}
:whiteboard/eraser {:binding ["6" "e"]
:whiteboard/eraser {:binding ["6" "w e"]
:fn #(.selectTool ^js (state/active-tldraw-app) "erase")}
:whiteboard/connector {:binding ["7" "c"]
:whiteboard/connector {:binding ["7" "w c"]
:fn #(.selectTool ^js (state/active-tldraw-app) "line")}
:whiteboard/text {:binding ["8" "t"]
:whiteboard/text {:binding ["8" "w t"]
:fn #(.selectTool ^js (state/active-tldraw-app) "text")}
:whiteboard/rectangle {:binding ["9" "r"]
:whiteboard/rectangle {:binding ["9" "w r"]
:fn #(.selectTool ^js (state/active-tldraw-app) "box")}
:whiteboard/ellipse {:binding "o"
:whiteboard/ellipse {:binding ["o" "w o"]
:fn #(.selectTool ^js (state/active-tldraw-app) "ellipse")}
:whiteboard/reset-zoom {:binding "shift+0"
@@ -141,7 +141,7 @@
:whiteboard/ungroup {:binding "mod+shift+g"
:fn #(.unGroup (.-api ^js (state/active-tldraw-app)))}
:whiteboard/toggle-grid {:binding "shift+g"
:whiteboard/toggle-grid {:binding "t g"
:fn #(.toggleGrid (.-api ^js (state/active-tldraw-app)))}
:auto-complete/complete {:binding "enter"

View File

@@ -1140,7 +1140,47 @@
:command.ui/goto-plugins "Gå til dashbord for utvidelser"
;; :command.ui/open-new-window "Åpne et nytt vindu"
:command.ui/select-theme-color "Velg tilgjengelige temafarger"
:command.ui/toggle-cards "Veksle kort"}
:command.ui/toggle-cards "Veksle kort"
:command.dev/show-block-ast "(Dev) Vis blokk AST"
:command.dev/show-block-data "(Dev) Vis blokk data"
:command.dev/show-page-ast "(Dev) Vis side AST"
:command.dev/show-page-data "(Dev) Vis side data"
:command.editor/copy-page-url "Kopier side url"
:command.editor/new-whiteboard "Nytt whiteboard"
:command.editor/select-parent "Velg overordnet blokk"
:command.editor/toggle-number-list "Veksle nummerliste"
:command.editor/toggle-undo-redo-mode "Veksle angremodus (global eller kun side)"
:command.go/whiteboards "Gå til whiteboards"
:command.graph/export-as-html "Eksporter offentlig graf som html"
:command.pdf/find "Pdf: Søk tekst i nåværende pdf doc"
:command.sidebar/close-top "Lukker øverste objekt i høyre sidestolpe"
:command.ui/clear-all-notifications "Fjern alle varsler"
:command.ui/install-plugins-from-file "Installer plugins fra plugins.edn"
:command.whiteboard/bring-forward "Flytt fremover"
:command.whiteboard/bring-to-front "Flytt fremst"
:command.whiteboard/connector "Koblingsverktøy"
:command.whiteboard/ellipse "Ellipseverktøy"
:command.whiteboard/eraser "Sletteverktøy"
:command.whiteboard/group "Velg gruppe"
:command.whiteboard/highlighter "Merkepenn"
:command.whiteboard/lock "Lås seleksjon"
:command.whiteboard/pan "Panoreringsverktøy"
:command.whiteboard/pencil "Blyantverktøy"
:command.whiteboard/portal "Portalverktøy"
:command.whiteboard/rectangle "Rektangelverktøy"
:command.whiteboard/reset-zoom "Tilbakestill zoom"
:command.whiteboard/select "Valg-verktøy"
:command.whiteboard/send-backward "Flytt bakover"
:command.whiteboard/send-to-back "Flytt bakerst"
:command.whiteboard/text "Tekst-verktøy"
:command.whiteboard/toggle-grid "Veksle rutenett på lerretet"
:command.whiteboard/ungroup "Del opp gruppe"
:command.whiteboard/unlock "Lås opp seleksjon"
:command.whiteboard/zoom-in "Zoom inn"
:command.whiteboard/zoom-out "Zoom ut"
:command.whiteboard/zoom-to-fit "Zoom til tegning"
:command.whiteboard/zoom-to-selection "Zoom for å passe seleksjonen"
:shortcut.category/whiteboard "Whiteboard"}
:pt-PT {:shortcut.category/formatting "Formatação"
:shortcut.category/basics "Básico"
@@ -1660,6 +1700,7 @@
:shortcut.category/block-command-editing "Blok düzenleme komutuları"
:shortcut.category/block-selection "Blok seçimi (seçimden çıkmak için Esc tuşuna basın)"
:shortcut.category/toggle "Aç/Kapat"
:shortcut.category/whiteboard "Beyaz tahta"
:shortcut.category/others "Diğer"
:command.date-picker/complete "Tarih seçici: Seçilen günü seç"
:command.date-picker/prev-day "Tarih seçici: Önceki günü seç"
@@ -1732,6 +1773,31 @@
:command.editor/zoom-in "Düzenlenen bloğu yakınlaştır / Aksi takdirde ileri git"
:command.editor/zoom-out "Düzenlenen bloğu uzaklaştır / Aksi takdirde geri git"
:command.editor/toggle-undo-redo-mode "Geri alma / yineleme modunu değiştir (yalnızca sayfa veya genel)"
:command.editor/toggle-number-list "Numaralı liste olarak değiştir"
:command.whiteboard/select "Seçim aracı"
:command.whiteboard/pan "Kaydırma aracı"
:command.whiteboard/portal "Portal aracı"
:command.whiteboard/pencil "Kalem aracı"
:command.whiteboard/highlighter "Vurgulayıcı aracı"
:command.whiteboard/eraser "Silgi aracı"
:command.whiteboard/connector "Bağlayıcı aracı"
:command.whiteboard/text "Metin aracı"
:command.whiteboard/rectangle "Dikdörtgen aracı"
:command.whiteboard/ellipse "Elips aracı"
:command.whiteboard/reset-zoom "Yakınlaştırmayı sıfırla"
:command.whiteboard/zoom-to-fit "Çizimi yakınlaştır"
:command.whiteboard/zoom-to-selection "Seçimi sığacak kadar yakınlaştır"
:command.whiteboard/zoom-out "Uzaklaştır"
:command.whiteboard/zoom-in "Yakınlaştır"
:command.whiteboard/send-backward "Geriye git"
:command.whiteboard/send-to-back "Geriye taşı"
:command.whiteboard/bring-forward "İleriye git"
:command.whiteboard/bring-to-front "Öne taşı"
:command.whiteboard/lock "Seçimi kilitle"
:command.whiteboard/unlock "Seçimin Kilidini aç"
:command.whiteboard/group "Seçimi gruplandır"
:command.whiteboard/ungroup "Seçimi gruptan çıkar"
:command.whiteboard/toggle-grid "Tuval ızgarasını değiştir"
:command.ui/toggle-brackets "Köşeli ayraçların görüntülenip görüntülenmeyeceğini değiştir"
:command.go/search-in-page "Geçerli sayfada ara"
:command.go/electron-find-in-page "Sayfada bul"

View File

@@ -52,11 +52,11 @@
[:div.flex.flex-col.items-start
[:div.text-2xs.font-bold.uppercase.toned-down (t :page/step "1")]
[:div [:span.highlighted.font-bold "Rebuild"] [:span.toned-down " search index"]]]
[:div
(ui/button (t :page/try)
:small? true
:on-click (fn []
(search-handler/rebuild-indices! true)))]]
[:div
(ui/button (t :page/try)
:small? true
:on-click (fn []
(search-handler/rebuild-indices! true)))]]
[:div.flex.flex-row.justify-between.align-items.mb-2.items-center.separator-top.py-4
[:div.flex.flex-col.items-start
[:div.text-2xs.font-bold.uppercase.toned-down (t :page/step "2")]
@@ -92,7 +92,7 @@
(ui/inject-dynamic-style-node!)
(quick-tour/init)
(plugin-handler/host-mounted!)
(assoc state ::teardown (setup-fns!) ))
(assoc state ::teardown (setup-fns!)))
:will-unmount (fn [state]
(when-let [teardown (::teardown state)]
(teardown)))}

View File

@@ -92,7 +92,7 @@
(fn []
(rum/set-ref! *mounted true)
#(rum/set-ref! *mounted false))
[])
[])
#(rum/deref *mounted)))
(defn use-bounding-client-rect

View File

@@ -62,6 +62,7 @@
:string]]
[:ref/default-open-blocks-level :int]
[:ref/linked-references-collapsed-threshold :int]
[:graph/settings [:map-of :keyword :boolean]]
[:favorites [:vector :string]]
;; There isn't a :float yet
[:srs/learning-fraction float?]

View File

@@ -0,0 +1,25 @@
(ns frontend.shui
"Glue between frontend code and deps/shui for convenience"
(:require
[frontend.date :refer [int->local-time-2]]
[frontend.state :as state]
[logseq.shui.context :refer [make-context]]))
(def default-versions {:logseq.table.version 1})
(defn get-shui-component-version
"Returns the version of the shui component, checking first
the block properties, then the global config, then the defaults."
[component-name block-config]
(let [version-key (keyword (str "logseq." (name component-name) ".version"))]
(js/parseFloat
(or (get-in block-config [:block :block/properties version-key])
(get-in (state/get-config) [version-key])
(get-in default-versions [version-key])
1))))
(defn make-shui-context [block-config inline]
(make-context {:block-config block-config
:app-config (state/get-config)
:inline inline
:int->local-time-2 int->local-time-2}))

View File

@@ -259,9 +259,9 @@
;; :file-sync/progress {}
;; :file-sync/start-time {}
;; :file-sync/last-synced-at {}}
:file-sync/graph-state {:current-graph-uuid nil
:file-sync/graph-state {:current-graph-uuid nil}
;; graph-uuid -> ...
}
:user/info {:UserGroups (storage/get :user-groups)}
:encryption/graph-parsing? false
@@ -285,7 +285,10 @@
:chat/current-conversation nil
:ai/preferred-translate-target-lang (storage/get :ai/preferred-translate-target-lang)
:ai/engines {}
:ai/current-service "Built-in OpenAI"})))
:ai/current-service "Built-in OpenAI"
;; db tx-id -> editor cursor
:history/tx->editor-cursor {}})))
;; Block ast state
;; ===============

View File

@@ -730,26 +730,26 @@
[state {:keys [on-mouse-down header title-trigger? collapsed?]}]
(let [control? (get state ::control?)]
[:div.content
[:div.flex-1.flex-row.foldable-title (cond->
{:on-mouse-over #(reset! control? true)
:on-mouse-out #(reset! control? false)}
title-trigger?
(assoc :on-mouse-down on-mouse-down
:class "cursor"))
[:div.flex.flex-row.items-center
(when-not (mobile-util/native-platform?)
[:a.block-control.opacity-50.hover:opacity-100.mr-2
(cond->
{:style {:width 14
:height 16
:margin-left -30}}
(not title-trigger?)
(assoc :on-mouse-down on-mouse-down))
[:span {:class (if (or @control? @collapsed?) "control-show cursor-pointer" "control-hide")}
(rotating-arrow @collapsed?)]])
(if (fn? header)
(header @collapsed?)
header)]]]))
[:div.flex-1.flex-row.foldable-title (cond->
{:on-mouse-over #(reset! control? true)
:on-mouse-out #(reset! control? false)}
title-trigger?
(assoc :on-mouse-down on-mouse-down
:class "cursor"))
[:div.flex.flex-row.items-center
(when-not (mobile-util/native-platform?)
[:a.block-control.opacity-50.hover:opacity-100.mr-2
(cond->
{:style {:width 14
:height 16
:margin-left -30}}
(not title-trigger?)
(assoc :on-mouse-down on-mouse-down))
[:span {:class (if (or @control? @collapsed?) "control-show cursor-pointer" "control-hide")}
(rotating-arrow @collapsed?)]])
(if (fn? header)
(header @collapsed?)
header)]]]))
(rum/defcs foldable < db-mixins/query rum/reactive
(rum/local false ::collapsed?)
@@ -852,10 +852,10 @@
[:option (cond->
{:key label
:value (or value label)} ;; NOTE: value might be an empty string, `or` is safe here
disabled
(assoc :disabled disabled)
selected
(assoc :selected selected))
disabled
(assoc :disabled disabled)
selected
(assoc :selected selected))
label])]))
(rum/defc radio-list

View File

@@ -1274,7 +1274,7 @@
#?(: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 (mobile-util/native-platform?) (mobile?)))
(let [box-rect (.getBoundingClientRect el)
box-top (.-top box-rect)
box-bottom (.-bottom box-rect)

View File

@@ -226,7 +226,7 @@
(defn- move-cursor-up-down
[input direction]
(move-cursor-to input (next-cursor-pos-up-down direction (get-caret-pos input))))
(move-cursor-to input (next-cursor-pos-up-down direction (get-caret-pos input))))
(defn move-cursor-up [input]
(move-cursor-up-down input :up))

View File

@@ -3,7 +3,8 @@
a good ns to be in yet"
(:require [clojure.string :as string]
[goog.string :as gstring]
[frontend.util :as util]))
[frontend.util :as util]
[logseq.common.path :as path]))
(defonce between-re #"\(between ([^\)]+)\)")
@@ -142,10 +143,11 @@
;; FIXME: distinguish from get-repo-name
(defn get-graph-name-from-path
[path]
(when (string? path)
(let [parts (->> (string/split path #"/")
(take-last 2))]
(-> (if (not= (first parts) "0")
(util/string-join-path parts)
(last parts))
js/decodeURIComponent))))
(let [path (if (path/is-file-url? path)
(path/url-to-path path)
path)
parts (->> (string/split path #"/")
(take-last 2))]
(if (not= (first parts) "0")
(util/string-join-path parts)
(last parts))))

View File

@@ -1,3 +1,3 @@
(ns ^:no-doc frontend.version)
(defonce version "0.9.4")
(defonce version "0.9.6")

View File

@@ -43,7 +43,8 @@
[frontend.handler.shell :as shell]
[frontend.modules.layout.core]
[frontend.handler.code :as code-handler]
[frontend.handler.search :as search-handler]))
[frontend.handler.search :as search-handler]
[logseq.api.block :as api-block]))
;; Alert: this namespace shouldn't invoke any reactive queries
@@ -651,13 +652,13 @@
nil)))
(def ^:export update_block
(fn [block-uuid content ^js _opts]
(fn [block-uuid content ^js opts]
(let [repo (state/get-current-repo)
edit-input (state/get-edit-input-id)
editing? (and edit-input (string/ends-with? edit-input (str block-uuid)))]
(if editing?
(state/set-edit-content! edit-input content)
(editor-handler/save-block! repo (sdk-utils/uuid-or-throw-error block-uuid) content))
(editor-handler/save-block! repo (sdk-utils/uuid-or-throw-error block-uuid) content (bean/->clj opts)))
nil)))
(def ^:export move_block
@@ -676,24 +677,7 @@
target-block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error target-block-uuid))]
(editor-dnd-handler/move-blocks nil [src-block] target-block move-to) nil)))
(def ^:export get_block
(fn [id-or-uuid ^js opts]
(when-let [block (cond
(number? id-or-uuid) (db-utils/pull id-or-uuid)
(string? id-or-uuid) (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error id-or-uuid)))]
(when-not (contains? block :block/name)
(when-let [uuid (:block/uuid block)]
(let [{:keys [includeChildren]} (bean/->clj opts)
repo (state/get-current-repo)
block (if includeChildren
;; nested children results
(first (outliner-tree/blocks->vec-tree
(db-model/get-block-and-children repo uuid) uuid))
;; attached shallow children
(assoc block :block/children
(map #(list :uuid (get-in % [:data :block/uuid]))
(db/get-block-immediate-children repo uuid))))]
(bean/->js (sdk-utils/normalize-keyword-for-json block))))))))
(def ^:export get_block api-block/get_block)
(def ^:export get_current_block
(fn [^js opts]
@@ -703,7 +687,7 @@
(gdom/getElement (state/get-editing-block-dom-id)))
(.getAttribute "blockid")
(db-model/get-block-by-uuid)))]
(get_block (:db/id block) opts))))
(get_block (:block/uuid block) opts))))
(def ^:export get_previous_sibling_block
(fn [block-uuid]
@@ -715,8 +699,9 @@
(def ^:export get_next_sibling_block
(fn [block-uuid]
(when-let [block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error block-uuid))]
(when-let [right-siblings (outliner/get-right-siblings (outliner/->Block block))]
(bean/->js (sdk-utils/normalize-keyword-for-json (:data (first right-siblings))))))))
(when-let [right-sibling (outliner/get-right-sibling (:db/id block))]
(let [block (db/pull (:id right-sibling))]
(bean/->js (sdk-utils/normalize-keyword-for-json block)))))))
(def ^:export set_block_collapsed
(fn [block-uuid ^js opts]

View File

@@ -0,0 +1,28 @@
(ns logseq.api.block
"Block related apis"
(:require [frontend.db.model :as db-model]
[frontend.db.utils :as db-utils]
[cljs-bean.core :as bean]
[frontend.state :as state]
[frontend.modules.outliner.tree :as outliner-tree]
[frontend.db :as db]
[logseq.sdk.utils :as sdk-utils]))
(defn get_block
[id-or-uuid ^js opts]
(when-let [block (if (number? id-or-uuid)
(db-utils/pull id-or-uuid)
(db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error id-or-uuid)))]
(when-not (contains? block :block/name)
(when-let [uuid (:block/uuid block)]
(let [{:keys [includeChildren]} (bean/->clj opts)
repo (state/get-current-repo)
block (if includeChildren
;; nested children results
(first (outliner-tree/blocks->vec-tree
(db-model/get-block-and-children repo uuid) uuid))
;; attached shallow children
(assoc block :block/children
(map #(list :uuid (:block/uuid %))
(db/get-block-immediate-children repo uuid))))]
(bean/->js (sdk-utils/normalize-keyword-for-json block)))))))

View File

@@ -163,6 +163,22 @@ foo:: bar"}])
(catch :default e
(ex-message e)))))))
(deftest get-block-immediate-children
(load-test-files [{:file/path "pages/page1.md"
:file/content "\n
- parent
- child 1
- grandchild 1
- child 2
- grandchild 2
- child 3"}])
(let [parent (-> (d/q '[:find (pull ?b [*]) :where [?b :block/content "parent"]]
(conn/get-db test-helper/test-db))
ffirst)]
(is (= ["child 1" "child 2" "child 3"]
(map :block/content
(model/get-block-immediate-children test-helper/test-db (:block/uuid parent)))))))
(deftest get-property-values
(load-test-files [{:file/path "pages/Feature.md"
:file/content "type:: [[Class]]"}

View File

@@ -2,6 +2,7 @@
(:require [clojure.test :refer [is use-fixtures]]
[frontend.test.fixtures :as fixtures]
[frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]]
[frontend.test.node-helper :as test-node-helper]
[frontend.fs :as fs]
[promesa.core :as p]
["fs" :as fs-node]
@@ -11,7 +12,7 @@
(deftest-async create-if-not-exists-creates-correctly
;; dir needs to be an absolute path for fn to work correctly
(let [dir (node-path/resolve (test-helper/create-tmp-dir))
(let [dir (node-path/resolve (test-node-helper/create-tmp-dir))
some-file (node-path/join dir "something.txt")]
(->
@@ -29,7 +30,7 @@
(fs-node/rmdirSync dir))))))
(deftest-async create-if-not-exists-does-not-create-correctly
(let [dir (node-path/resolve (test-helper/create-tmp-dir))
(let [dir (node-path/resolve (test-node-helper/create-tmp-dir))
some-file (node-path/join dir "something.txt")]
(fs-node/writeFileSync some-file "OLD")

View File

@@ -1,9 +1,15 @@
(ns frontend.handler.editor-test
(:require [frontend.handler.editor :as editor]
[clojure.test :refer [deftest is testing are]]
[frontend.db :as db]
[clojure.test :refer [deftest is testing are use-fixtures]]
[datascript.core :as d]
[frontend.test.helper :as test-helper :refer [load-test-files]]
[frontend.db.model :as model]
[frontend.state :as state]
[frontend.util.cursor :as cursor]))
(use-fixtures :each test-helper/start-and-destroy-db)
(deftest extract-nearest-link-from-text-test
(testing "Page, block and tag links"
(is (= "page1"
@@ -213,3 +219,39 @@
"No page search within backticks"))
;; Reset state
(state/set-editor-action! nil))
(deftest save-block-aux!
(load-test-files [{:file/path "pages/page1.md"
:file/content "\n
- b1 #foo"}])
(testing "updating block's content changes content and preserves path-refs"
(let [conn (db/get-db test-helper/test-db false)
block (->> (d/q '[:find (pull ?b [* {:block/path-refs [:block/name]}])
:where [?b :block/content "b1 #foo"]]
@conn)
ffirst)
prev-path-refs (set (map :block/name (:block/path-refs block)))
_ (assert (= #{"page1" "foo"} prev-path-refs)
"block has expected :block/path-refs")
;; Use same options as edit-box-on-change!
_ (editor/save-block-aux! block "b12 #foo" {:skip-properties? true})
updated-block (d/pull @conn '[* {:block/path-refs [:block/name]}] [:block/uuid (:block/uuid block)])]
(is (= "b12 #foo" (:block/content updated-block)) "Content updated correctly")
(is (= prev-path-refs
(set (map :block/name (:block/path-refs updated-block))))
"Path-refs remain the same"))))
(deftest save-block!
(testing "Saving blocks with and without properties"
(test-helper/load-test-files [{:file/path "foo.md"
:file/content "# foo"}])
(let [repo test-helper/test-db
block-uuid (:block/uuid (model/get-block-by-page-name-and-block-route-name repo "foo" "foo"))]
(editor/save-block! repo block-uuid "# bar")
(is (= "# bar" (:block/content (model/query-block-by-uuid block-uuid))))
(editor/save-block! repo block-uuid "# foo" {:properties {:foo "bar"}})
(is (= "# foo\nfoo:: bar" (:block/content (model/query-block-by-uuid block-uuid))))
(editor/save-block! repo block-uuid "# bar")
(is (= "# bar" (:block/content (model/query-block-by-uuid block-uuid)))))))

View File

@@ -1,6 +1,7 @@
(ns frontend.handler.plugin-config-test
(:require [clojure.test :refer [is use-fixtures testing deftest]]
[frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]]
[frontend.test.node-helper :as test-node-helper]
[frontend.test.fixtures :as fixtures]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.handler.global-config :as global-config-handler]
@@ -17,7 +18,7 @@
(defn- create-global-config-dir
[]
(let [dir (test-helper/create-tmp-dir "config")
(let [dir (test-node-helper/create-tmp-dir "config")
root-dir (node-path/dirname dir)]
(reset! global-config-handler/root-dir root-dir)
dir))

View File

@@ -98,7 +98,7 @@
;; only increase over time as the docs graph rarely has deletions
(testing "Counts"
(is (= 211 (count files)) "Correct file count")
(is (= 42312 (count (d/datoms db :eavt))) "Correct datoms count")
(is (= 42304 (count (d/datoms db :eavt))) "Correct datoms count")
(is (= 3600
(ffirst

View File

@@ -2,7 +2,6 @@
(:require [cljs.test :refer [deftest use-fixtures testing is]]
[frontend.handler.repo :as repo-handler]
[frontend.test.helper :as test-helper :refer [load-test-files]]
[frontend.state :as state]
[logseq.graph-parser.cli :as gp-cli]
[logseq.graph-parser.test.docs-graph-helper :as docs-graph-helper]
[logseq.graph-parser.util.block-ref :as block-ref]
@@ -12,13 +11,7 @@
["path" :as node-path]
["fs" :as fs]))
(use-fixtures :each {:before (fn []
;; Set current-repo explicitly since it's not the default
(state/set-current-repo! test-helper/test-db)
(test-helper/start-test-db!))
:after (fn []
(state/set-current-repo! nil)
(test-helper/destroy-test-db!))})
(use-fixtures :each test-helper/start-and-destroy-db)
(deftest ^:integration parse-and-load-files-to-db
(let [graph-dir "src/test/docs-0.9.2"

View File

@@ -10,7 +10,7 @@
[clojure.walk :as walk]
[logseq.graph-parser.block :as gp-block]
[datascript.core :as d]
[frontend.test.helper :as test-helper]
[frontend.test.helper :as test-helper :refer [load-test-files]]
[clojure.set :as set]))
(def test-db test-helper/test-db)
@@ -440,6 +440,63 @@
'(16 17)
(map :block/uuid (tree/get-sorted-block-and-children test-db (:db/id (get-block 16))))))))
(defn- save-block!
[block]
(outliner-tx/transact! {:graph test-db}
(outliner-core/save-block! block)))
(deftest save-test
(load-test-files [{:file/path "pages/page1.md"
:file/content "alias:: foo, bar
tags:: tag1, tag2
- block #blarg #bar"}])
(testing "save deletes a page's tags"
(let [conn (db/get-db test-helper/test-db false)
pre-block (->> (d/q '[:find (pull ?b [*])
:where [?b :block/pre-block? true]]
@conn)
ffirst)
_ (save-block! (-> pre-block
(update :block/properties dissoc :tags)
(update :block/properties-text-values dissoc :tags)))
updated-page (-> (d/q '[:find (pull ?bp [* {:block/alias [*]}])
:where [?b :block/pre-block? true]
[?b :block/page ?bp]]
@conn)
ffirst)]
(is (nil? (:block/tags updated-page))
"Page's tags are deleted")
(is (= #{"foo" "bar"} (set (map :block/name (:block/alias updated-page))))
"Page's aliases remain the same")
(is (= {:block/properties {:alias #{"foo" "bar"}}
:block/properties-text-values {:alias "foo, bar"}}
(select-keys updated-page [:block/properties :block/properties-text-values]))
"Page property attributes are correct")
(is (= {:block/properties {:alias #{"foo" "bar"}}
:block/properties-text-values {:alias "foo, bar"}}
(-> (d/q '[:find (pull ?b [*])
:where [?b :block/pre-block? true]]
@conn)
ffirst
(select-keys [:block/properties :block/properties-text-values])))
"Pre-block property attributes are correct")))
(testing "save deletes orphaned pages when a block's refs change"
(let [conn (db/get-db test-helper/test-db false)
pages (set (map first (d/q '[:find ?bn :where [?b :block/name ?bn]] @conn)))
_ (assert (set/subset? #{"blarg" "bar"} pages) "Pages from block exist")
block-with-refs (ffirst (d/q '[:find (pull ?b [* {:block/refs [*]}])
:where [?b :block/content "block #blarg #bar"]]
@conn))
_ (save-block! (-> block-with-refs
(assoc :block/content "block"
:block/refs [])))
updated-pages (set (map first (d/q '[:find ?bn :where [?b :block/name ?bn]] @conn)))]
(is (not (contains? updated-pages "blarg"))
"Deleted, orphaned page no longer exists")
(is (contains? updated-pages "bar")
"Deleted but not orphaned page still exists"))))
;;; Fuzzy tests
(def init-id (atom 100))

View File

@@ -1,18 +1,11 @@
(ns frontend.modules.outliner.pipeline-test
(:require [cljs.test :refer [deftest is use-fixtures testing]]
[datascript.core :as d]
[frontend.state :as state]
[frontend.db :as db]
[frontend.modules.outliner.pipeline :as pipeline]
[frontend.test.helper :as test-helper :refer [load-test-files]]))
(use-fixtures :each {:before (fn []
;; Set current-repo explicitly since it's not the default
(state/set-current-repo! test-helper/test-db)
(test-helper/start-test-db!))
:after (fn []
(state/set-current-repo! nil)
(test-helper/destroy-test-db!))})
(use-fixtures :each test-helper/start-and-destroy-db)
(defn- get-blocks [db]
(->> (d/q '[:find (pull ?b [* {:block/path-refs [:block/name :db/id]}])

View File

@@ -1,9 +1,8 @@
(ns frontend.test.helper
"Common helper fns for tests"
(:require [frontend.handler.repo :as repo-handler]
[frontend.db.conn :as conn]
["path" :as node-path]
["fs" :as fs-node]))
[frontend.state :as state]
[frontend.db.conn :as conn]))
(defonce test-db "test-db")
@@ -25,15 +24,14 @@ This can be called in synchronous contexts as no async fns should be invoked"
;; Set :refresh? to avoid creating default files in after-parse
{:re-render? false :verbose false :refresh? true}))
(defn create-tmp-dir
"Creates a temporary directory under tmp/. If a subdir is given, creates an
additional subdirectory under the newly created temp directory."
([] (create-tmp-dir nil))
([subdir]
(when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
(let [dir (fs-node/mkdtempSync (node-path/join "tmp" "unit-test-"))]
(if subdir
(do
(fs-node/mkdirSync (node-path/join dir subdir))
(node-path/join dir subdir))
dir))))
(defn start-and-destroy-db
"Sets up a db connection and current repo like fixtures/reset-datascript. It
also seeds the db with the same default data that the app does and destroys a db
connection when done with it."
[f]
;; Set current-repo explicitly since it's not the default
(state/set-current-repo! test-db)
(start-test-db!)
(f)
(state/set-current-repo! nil)
(destroy-test-db!))

View File

@@ -0,0 +1,17 @@
(ns frontend.test.node-helper
"Common helper fns for node tests"
(:require ["path" :as node-path]
["fs" :as fs-node]))
(defn create-tmp-dir
"Creates a temporary directory under tmp/. If a subdir is given, creates an
additional subdirectory under the newly created temp directory."
([] (create-tmp-dir nil))
([subdir]
(when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp"))
(let [dir (fs-node/mkdtempSync (node-path/join "tmp" "unit-test-"))]
(if subdir
(do
(fs-node/mkdirSync (node-path/join dir subdir))
(node-path/join dir subdir))
dir))))

View File

@@ -0,0 +1,40 @@
(ns logseq.api-test
(:require [cljs.test :refer [use-fixtures deftest is]]
[frontend.test.helper :as test-helper]
[frontend.db :as db]
[logseq.api.block :as api-block]
[frontend.state :as state]
[cljs-bean.core :as bean]))
(use-fixtures :each {:before test-helper/start-test-db!
:after test-helper/destroy-test-db!})
(deftest get-block
(with-redefs [state/get-current-repo (constantly test-helper/test-db)]
(db/transact! test-helper/test-db
[{:db/id 10000
:block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0"
:block/content "1"}
{:db/id 10001
:block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172"
:block/content "2"}
{:db/id 10002
:block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556"
:block/parent 10001
:block/left 10001
:block/content "3"}
{:db/id 10003
:block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d"
:block/parent 10002
:block/left 10002
:block/content "4"}])
(is (= (:content (bean/->clj (api-block/get_block 10000 #js {}))) "1"))
(is (= (:content (bean/->clj (api-block/get_block "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2"))
(is (= (:content (bean/->clj (api-block/get_block #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2"))
(is (= {:id 10001, :content "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :children [["uuid" "adae3006-f03e-4814-a1f5-f17f15b86556"]]}
(bean/->clj (api-block/get_block 10001 #js {:includeChildren false}))))
(is (= {:content "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :id 10001, :children [{:content "3", :left {:id 10001}, :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :id 10002, :level 1, :children [{:content "4", :left {:id 10002}, :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :id 10003, :level 2, :children []}]}]}
(bean/->clj (api-block/get_block 10001 #js {:includeChildren true}))))))
#_(cljs.test/run-tests)