mirror of https://github.com/logseq/logseq
Merge remote-tracking branch 'upstream/master' into whiteboards
commit
37d0ad2524
|
@ -75,7 +75,8 @@ frontend.util/trace!
|
|||
frontend.util.pool/terminate-pool!
|
||||
;; Repl fn
|
||||
frontend.util.property/add-page-properties
|
||||
;; Test runner used by shadow
|
||||
;; Test runners used by shadow
|
||||
frontend.test.node-test-runner/main
|
||||
frontend.test.frontend-node-test-runner/main
|
||||
;; Test runner for nbb
|
||||
logseq.graph-parser.nbb-test-runner/run-tests
|
||||
|
|
|
@ -6,8 +6,8 @@ android {
|
|||
applicationId "com.logseq.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 35
|
||||
versionName "0.8.1"
|
||||
versionCode 36
|
||||
versionName "0.8.2"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
|
|
@ -18,3 +18,7 @@ logseq.graph-parser.util.page-ref/left-and-right-brackets
|
|||
logseq.graph-parser.util.page-ref/->page-ref
|
||||
;; API
|
||||
logseq.graph-parser.util.page-ref/get-page-name!
|
||||
;; API
|
||||
logseq.graph-parser.property/->block-content
|
||||
;; API
|
||||
logseq.graph-parser.property/property-value-from-content
|
||||
|
|
|
@ -157,6 +157,8 @@
|
|||
distinct)
|
||||
[]))
|
||||
|
||||
;; TODO: Use text/parse-property to determine refs rather than maintain this similar
|
||||
;; implementation to parse-property
|
||||
(defn- get-page-ref-names-from-properties
|
||||
[format properties user-config]
|
||||
(let [page-refs (->>
|
||||
|
@ -174,7 +176,11 @@
|
|||
(and (string? v)
|
||||
(not (gp-mldoc/link? format v)))
|
||||
(let [v (string/trim v)
|
||||
result (text/split-page-refs-without-brackets v {:un-brackets? false})]
|
||||
result (if (:rich-property-values? user-config)
|
||||
(if (gp-util/wrapped-by-quotes? v)
|
||||
[]
|
||||
(text/extract-page-refs-and-tags v))
|
||||
(text/split-page-refs-without-brackets v {:un-brackets? false}))]
|
||||
(if (coll? result)
|
||||
(map text/page-ref-un-brackets! result)
|
||||
[]))
|
||||
|
|
|
@ -44,7 +44,8 @@ TODO: Fail fast when process exits 1"
|
|||
|
||||
(defn- parse-files
|
||||
[conn files {:keys [config] :as options}]
|
||||
(let [extract-options (merge {:date-formatter (gp-config/get-date-formatter config)}
|
||||
(let [extract-options (merge {:date-formatter (gp-config/get-date-formatter config)
|
||||
:user-config config}
|
||||
(select-keys options [:verbose]))]
|
||||
(mapv
|
||||
(fn [{:file/keys [path content]}]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
(ns logseq.graph-parser.config
|
||||
"Config that is shared between graph-parser and rest of app"
|
||||
(:require [logseq.graph-parser.util :as gp-util]
|
||||
[clojure.set :as set]
|
||||
(:require [clojure.set :as set]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(def app-name
|
||||
|
@ -12,7 +11,8 @@
|
|||
|
||||
(defn local-asset?
|
||||
[s]
|
||||
(gp-util/safe-re-find (re-pattern (str "^[./]*" local-assets-dir)) s))
|
||||
(and (string? s)
|
||||
(re-find (re-pattern (str "^[./]*" local-assets-dir)) s)))
|
||||
|
||||
(defonce default-draw-directory "draws")
|
||||
;; TODO read configurable value?
|
||||
|
|
|
@ -154,7 +154,8 @@
|
|||
(remove string/blank?)))
|
||||
tags (:tags properties)
|
||||
tags (->> (->vec-concat tags filetags)
|
||||
(remove string/blank?))
|
||||
(remove string/blank?)
|
||||
vec)
|
||||
properties (assoc properties :tags tags :alias alias)
|
||||
properties (-> properties
|
||||
(update :filetags (constantly filetags)))
|
||||
|
|
|
@ -8,6 +8,19 @@
|
|||
|
||||
(def colons "Property delimiter for markdown mode" "::")
|
||||
|
||||
(defn ->block-content
|
||||
"Creates a block content string from properties map"
|
||||
[properties]
|
||||
(->> properties
|
||||
(map #(str (name (key %)) (str colons " ") (val %)))
|
||||
(string/join "\n")))
|
||||
|
||||
(defn property-value-from-content
|
||||
"Extracts full property value from block content"
|
||||
[property content]
|
||||
(second (re-find (re-pattern (str property colons "\\s+(.*)"))
|
||||
content)))
|
||||
|
||||
(defn properties-ast?
|
||||
[block]
|
||||
(and
|
||||
|
@ -60,7 +73,7 @@
|
|||
[content]
|
||||
(when content
|
||||
(and (string/includes? content properties-start)
|
||||
(gp-util/safe-re-find properties-end-pattern content))))
|
||||
(re-find properties-end-pattern content))))
|
||||
|
||||
(defn ->new-properties
|
||||
"New syntax: key:: value"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[clojure.set :as set]
|
||||
[logseq.graph-parser.mldoc :as gp-mldoc]
|
||||
[logseq.graph-parser.util :as gp-util]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
[logseq.graph-parser.util.page-ref :as page-ref :refer [right-brackets]]))
|
||||
|
||||
(defn get-file-basename
|
||||
|
@ -109,8 +110,8 @@
|
|||
|
||||
(and (string? s)
|
||||
;; Either a page ref, a tag or a comma separated collection
|
||||
(or (gp-util/safe-re-find page-ref/page-ref-re s)
|
||||
(gp-util/safe-re-find #"[\,|,|#|\"]+" s)))
|
||||
(or (re-find page-ref/page-ref-re s)
|
||||
(re-find #"[\,|,|#|\"]+" s)))
|
||||
(let [result (->> (sep-by-quotes s)
|
||||
(mapcat
|
||||
(fn [s]
|
||||
|
@ -199,7 +200,35 @@
|
|||
(defonce non-parsing-properties
|
||||
(atom #{"background-color" "background_color"}))
|
||||
|
||||
(defn parse-non-string-property-value
|
||||
"Return parsed non-string property value or nil if none is found"
|
||||
[v]
|
||||
(cond
|
||||
(= v "true")
|
||||
true
|
||||
|
||||
(= v "false")
|
||||
false
|
||||
|
||||
(re-find #"^\d+$" v)
|
||||
(parse-long v)))
|
||||
|
||||
(def ^:private page-ref-or-tag-re
|
||||
(re-pattern (str "#?" (page-ref/->page-ref-re-str "(.*?)") "|"
|
||||
;; Don't capture punctuation at end of a tag
|
||||
"#([\\S]+[^\\s.!,])")))
|
||||
|
||||
(defn extract-page-refs-and-tags
|
||||
"Returns set of page-refs and tags in given string or returns string if none
|
||||
are found"
|
||||
[string]
|
||||
(let [refs (map #(or (second %) (get % 2))
|
||||
(re-seq page-ref-or-tag-re string))]
|
||||
(if (seq refs) (set refs) string)))
|
||||
|
||||
(defn parse-property
|
||||
"Property value parsing that takes into account built-in properties, format
|
||||
and user config"
|
||||
([k v config-state]
|
||||
(parse-property :markdown k v config-state))
|
||||
([format k v config-state]
|
||||
|
@ -212,14 +241,6 @@
|
|||
(get config-state :ignored-page-references-keywords)) k)
|
||||
v
|
||||
|
||||
(= v "true")
|
||||
true
|
||||
(= v "false")
|
||||
false
|
||||
|
||||
(and (not= k "alias") (gp-util/safe-re-find #"^\d+$" v))
|
||||
(parse-long v)
|
||||
|
||||
(gp-util/wrapped-by-quotes? v) ; wrapped in ""
|
||||
v
|
||||
|
||||
|
@ -229,5 +250,12 @@
|
|||
(gp-mldoc/link? format v)
|
||||
v
|
||||
|
||||
(contains? gp-property/editable-linkable-built-in-properties (keyword k))
|
||||
(split-page-refs-without-brackets v)
|
||||
|
||||
:else
|
||||
(split-page-refs-without-brackets v)))))
|
||||
(if-some [res (parse-non-string-property-value v)]
|
||||
res
|
||||
(if (:rich-property-values? config-state)
|
||||
(extract-page-refs-and-tags v)
|
||||
(split-page-refs-without-brackets v)))))))
|
||||
|
|
|
@ -6,12 +6,6 @@
|
|||
[logseq.graph-parser.log :as log]
|
||||
[cljs.reader :as reader]))
|
||||
|
||||
(defn safe-re-find
|
||||
"Copy of frontend.util/safe-re-find. Too basic to couple to main app"
|
||||
[pattern s]
|
||||
(when (string? s)
|
||||
(re-find pattern s)))
|
||||
|
||||
(defn path-normalize
|
||||
"Normalize file path (for reading paths from FS, not required by writting)"
|
||||
[s]
|
||||
|
@ -40,7 +34,7 @@
|
|||
(defn tag-valid?
|
||||
[tag-name]
|
||||
(when (string? tag-name)
|
||||
(not (safe-re-find #"[# \t\r\n]+" tag-name))))
|
||||
(not (re-find #"[# \t\r\n]+" tag-name))))
|
||||
|
||||
(defn safe-subs
|
||||
([s start]
|
||||
|
|
|
@ -27,6 +27,11 @@ a logseq page-ref e.g. [[page name]]"
|
|||
[page-name]
|
||||
(str left-brackets page-name right-brackets))
|
||||
|
||||
(defn ->page-ref-re-str
|
||||
"Create a page ref regex escaped string given a page name"
|
||||
[page-name]
|
||||
(string/replace (->page-ref page-name) #"([\[\]])" "\\$1"))
|
||||
|
||||
(defn get-page-name
|
||||
"Extracts page-name from page-ref string"
|
||||
[s]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(ns logseq.graph-parser.property-test
|
||||
(:require [cljs.test :refer [are deftest]]
|
||||
(:require [cljs.test :refer [are deftest is]]
|
||||
[logseq.graph-parser.property :as gp-property]))
|
||||
|
||||
(deftest test->new-properties
|
||||
|
@ -24,3 +24,16 @@
|
|||
|
||||
"hello\n:PROPERTIES:\n:foo: bar\n:nice\n:END:\nnice"
|
||||
"hello\nfoo:: bar\n:nice\nnice"))
|
||||
|
||||
(deftest property-value-from-content
|
||||
(is (= "62b38254-4be7-4627-a2b7-6d9ee20999e5"
|
||||
(gp-property/property-value-from-content
|
||||
"id"
|
||||
"type:: blog-posting\ndesc:: nice walkthrough on creating a blog with #nbb\nid:: 62b38254-4be7-4627-a2b7-6d9ee20999e5"))
|
||||
"Pulls value from end of block content")
|
||||
|
||||
(is (= "nice walkthrough on creating a blog with #nbb"
|
||||
(gp-property/property-value-from-content
|
||||
"desc"
|
||||
"type:: blog-posting\ndesc:: nice walkthrough on creating a blog with #nbb\nid:: 62b38254-4be7-4627-a2b7-6d9ee20999e5"))
|
||||
"Pulls value from middle of block content"))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(ns logseq.graph-parser.text-test
|
||||
(:require [cljs.test :refer [are deftest testing]]
|
||||
(:require [cljs.test :refer [are deftest testing is]]
|
||||
[logseq.graph-parser.text :as text]))
|
||||
|
||||
(deftest test-get-page-name
|
||||
|
@ -109,4 +109,9 @@
|
|||
:tags "\"[[foo]], [[bar]]\"" "\"[[foo]], [[bar]]\""
|
||||
:tags "baz, \"[[foo]], [[bar]]\"" #{"baz"})))
|
||||
|
||||
(deftest extract-page-refs-and-tags
|
||||
(is (= #{"cljs" "nbb" "js" "amazing"}
|
||||
(text/extract-page-refs-and-tags "This project is written with #cljs, #nbb and #js. #amazing!"))
|
||||
"Don't extract punctation at end of a tag"))
|
||||
|
||||
#_(cljs.test/test-ns 'logseq.graph-parser.text-test)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
(ns logseq.graph-parser-test
|
||||
(:require [cljs.test :refer [deftest testing is]]
|
||||
(:require [cljs.test :refer [deftest testing is are]]
|
||||
[clojure.string :as string]
|
||||
[logseq.graph-parser :as graph-parser]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.graph-parser.block :as gp-block]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
[datascript.core :as d]))
|
||||
|
||||
(def foo-edn
|
||||
|
@ -97,3 +98,139 @@
|
|||
(test-property-order 4))
|
||||
(testing "Sort order and persistence of 10 properties"
|
||||
(test-property-order 10)))
|
||||
|
||||
(defn- quoted-property-values-test
|
||||
[user-config]
|
||||
(let [conn (ldb/start-conn)
|
||||
_ (graph-parser/parse-file conn
|
||||
"foo.md"
|
||||
"- desc:: \"#foo is not a ref\""
|
||||
{:extract-options {:user-config user-config}})
|
||||
block (->> (d/q '[:find (pull ?b [* {:block/refs [*]}])
|
||||
:in $
|
||||
:where [?b :block/properties]]
|
||||
@conn)
|
||||
(map first)
|
||||
first)]
|
||||
(is (= {:desc "\"#foo is not a ref\""}
|
||||
(:block/properties block))
|
||||
"Quoted value is unparsed")
|
||||
(is (= ["desc"]
|
||||
(map :block/original-name (:block/refs block)))
|
||||
"No refs from property value")))
|
||||
|
||||
(deftest quoted-property-values
|
||||
(testing "With default config"
|
||||
(quoted-property-values-test {}))
|
||||
(testing "With :rich-property-values config"
|
||||
(quoted-property-values-test {:rich-property-values? true})))
|
||||
|
||||
(deftest page-properties-persistence
|
||||
(testing "Non-string property values"
|
||||
(let [conn (ldb/start-conn)]
|
||||
(graph-parser/parse-file conn
|
||||
"lythe-of-heaven.md"
|
||||
"rating:: 8\nrecommend:: true\narchive:: false"
|
||||
{})
|
||||
(is (= {:rating 8 :recommend true :archive false}
|
||||
(->> (d/q '[:find (pull ?b [*])
|
||||
:in $
|
||||
:where [?b :block/properties]]
|
||||
@conn)
|
||||
(map (comp :block/properties first))
|
||||
first)))))
|
||||
|
||||
(testing "Linkable built-in properties"
|
||||
(let [conn (ldb/start-conn)
|
||||
_ (graph-parser/parse-file conn
|
||||
"lol.md"
|
||||
"alias:: 233\ntags:: fun, facts"
|
||||
{})
|
||||
block (->> (d/q '[:find (pull ?b [:block/properties {:block/alias [:block/name]} {:block/tags [:block/name]}])
|
||||
:in $
|
||||
:where [?b :block/name "lol"]]
|
||||
@conn)
|
||||
(map first)
|
||||
first)]
|
||||
|
||||
(is (= {:block/alias [{:block/name "233"}]
|
||||
:block/tags [{:block/name "fun"} {:block/name "facts"}]
|
||||
:block/properties {:alias ["233"] :tags ["fun" "facts"]}}
|
||||
block))
|
||||
|
||||
(is (every? vector? (vals (:block/properties block)))
|
||||
"Linked built-in property values as vectors provides for easier transforms"))))
|
||||
|
||||
(defn- property-relationships-test
|
||||
"Runs tests on page properties and block properties. file-properties is what is
|
||||
visible in a file and db-properties is what is pulled out from the db"
|
||||
[file-properties db-properties user-config]
|
||||
(let [conn (ldb/start-conn)
|
||||
page-content (gp-property/->block-content file-properties)
|
||||
;; Create Block properties from given page ones
|
||||
block-property-transform (fn [m] (update-keys m #(keyword (str "block-" (name %)))))
|
||||
block-content (gp-property/->block-content (block-property-transform file-properties))
|
||||
_ (graph-parser/parse-file conn
|
||||
"property-relationships.md"
|
||||
(str page-content "\n- " block-content)
|
||||
{:extract-options {:user-config user-config}})
|
||||
pages (->> (d/q '[:find (pull ?b [* :block/properties])
|
||||
:in $
|
||||
:where [?b :block/name] [?b :block/properties]]
|
||||
@conn)
|
||||
(map first))
|
||||
_ (assert (= 1 (count pages)))
|
||||
blocks (->> (d/q '[:find (pull ?b [:block/pre-block? :block/properties
|
||||
{:block/refs [:block/original-name]}])
|
||||
:in $
|
||||
:where [?b :block/properties] [(missing? $ ?b :block/name)]]
|
||||
@conn)
|
||||
(map first)
|
||||
(map (fn [m] (update m :block/refs #(map :block/original-name %)))))
|
||||
block-db-properties (block-property-transform db-properties)]
|
||||
|
||||
(is (= db-properties (:block/properties (first pages)))
|
||||
"page has expected properties")
|
||||
|
||||
(is (= [true nil] (map :block/pre-block? blocks))
|
||||
"page has 2 blocks, one of which is a pre-block")
|
||||
|
||||
(is (= [db-properties block-db-properties]
|
||||
(map :block/properties blocks))
|
||||
"pre-block/page and block have expected properties")
|
||||
|
||||
;; has expected refs
|
||||
(are [db-props refs]
|
||||
(= (->> (vals db-props)
|
||||
;; ignore string values
|
||||
(mapcat #(if (coll? %) % []))
|
||||
(concat (map name (keys db-props)))
|
||||
set)
|
||||
(set refs))
|
||||
; pre-block/page has expected refs
|
||||
db-properties (first (map :block/refs blocks))
|
||||
;; block has expected refs
|
||||
block-db-properties (second (map :block/refs blocks)))))
|
||||
|
||||
(deftest property-relationships
|
||||
(let [properties {:single-link "[[bar]]"
|
||||
:multi-link "[[Logseq]] is the fastest #triples #[[text editor]]"
|
||||
:desc "This is a multiple sentence description. It has one [[link]]"
|
||||
:comma-prop "one, two,three"}]
|
||||
(testing "With default config"
|
||||
(property-relationships-test
|
||||
properties
|
||||
{:single-link #{"bar"}
|
||||
:multi-link #{"Logseq" "is the fastest" "triples" "text editor"}
|
||||
:desc #{"This is a multiple sentence description. It has one" "link"}
|
||||
:comma-prop #{"one" "two" "three"}}
|
||||
{}))
|
||||
|
||||
(testing "With :rich-property-values config"
|
||||
(property-relationships-test
|
||||
properties
|
||||
{:single-link #{"bar"}
|
||||
:multi-link #{"Logseq" "triples" "text editor"}
|
||||
:desc #{"link"}
|
||||
:comma-prop "one, two,three"}
|
||||
{:rich-property-values? true}))))
|
||||
|
|
|
@ -72,7 +72,7 @@ contextBridge.exposeInMainWorld('apis', {
|
|||
|
||||
showItemInFolder (fullpath) {
|
||||
if (IS_WIN32) {
|
||||
shell.openPath(path.dirname(fullpath))
|
||||
shell.openPath(path.dirname(fullpath).replaceAll("/", "\\"))
|
||||
} else {
|
||||
shell.showItemInFolder(fullpath)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Logseq",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"main": "electron.js",
|
||||
"author": "Logseq",
|
||||
"license": "AGPL-3.0",
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
:devtools {:enabled false}
|
||||
;; disable :static-fns to allow for with-redefs and repl development
|
||||
:compiler-options {:static-fns false}
|
||||
:main frontend.test.node-test-runner/main}
|
||||
:main frontend.test.frontend-node-test-runner/main}
|
||||
|
||||
:publishing {:target :browser
|
||||
:module-loader true
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
(ns electron.find-in-page
|
||||
(:require [electron.utils :as utils]
|
||||
[cljs-bean.core :as bean]))
|
||||
|
||||
(defn find!
|
||||
[^js window search option]
|
||||
(when window
|
||||
(let [contents ^js (.-webContents window)]
|
||||
(.findInPage contents search option)
|
||||
(.on contents "found-in-page"
|
||||
(fn [_event result]
|
||||
(utils/send-to-renderer window "foundInPage" (bean/->clj result))))
|
||||
true)))
|
||||
|
||||
(defn clear!
|
||||
[^js window]
|
||||
(when window
|
||||
(.stopFindInPage ^js (.-webContents window) "clearSelection")))
|
|
@ -21,7 +21,8 @@
|
|||
[electron.plugin :as plugin]
|
||||
[electron.window :as win]
|
||||
[electron.file-sync-rsapi :as rsapi]
|
||||
[electron.backup-file :as backup-file]))
|
||||
[electron.backup-file :as backup-file]
|
||||
[electron.find-in-page :as find]))
|
||||
|
||||
(defmulti handle (fn [_window args] (keyword (first args))))
|
||||
|
||||
|
@ -536,6 +537,12 @@
|
|||
(f)
|
||||
(state/set-state! :window/once-persist-done nil)))
|
||||
|
||||
(defmethod handle :find-in-page [^js win [_ search option]]
|
||||
(find/find! win search (bean/->js option)))
|
||||
|
||||
(defmethod handle :clear-find-in-page [^js win [_]]
|
||||
(find/clear! win))
|
||||
|
||||
(defn set-ipc-handler! [window]
|
||||
(let [main-channel "main"]
|
||||
(.handle ipcMain main-channel
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
(defn setup-window-listeners!
|
||||
[^js win]
|
||||
(when win
|
||||
(let [web-contents (. win -webContents)
|
||||
(let [web-contents (. win -webContents)
|
||||
new-win-handler
|
||||
(fn [e url]
|
||||
(let [url (if (string/starts-with? url "file:")
|
||||
|
@ -140,7 +140,7 @@
|
|||
|
||||
context-menu-handler
|
||||
(context-menu/setup-context-menu! win)]
|
||||
|
||||
|
||||
(doto web-contents
|
||||
(.on "new-window" new-win-handler)
|
||||
(.on "will-navigate" will-navigate-handler))
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
[frontend.ui :as ui]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.repo :as repo-handler]
|
||||
[frontend.handler.user :as user]))
|
||||
[frontend.handler.user :as user]
|
||||
[dommy.core :as dom]))
|
||||
|
||||
(defn persist-dbs!
|
||||
[]
|
||||
|
@ -124,6 +125,15 @@
|
|||
:on-error error-f}]
|
||||
(repo-handler/persist-db! repo handlers))))
|
||||
|
||||
(js/window.apis.on "foundInPage"
|
||||
(fn [data]
|
||||
(let [data' (bean/->clj data)]
|
||||
(state/set-state! [:ui/find-in-page :matches] data')
|
||||
(dom/remove-style! (dom/by-id "search-in-page-input") :visibility)
|
||||
(dom/set-text! (dom/by-id "search-in-page-placeholder") "")
|
||||
(ui/focus-element "search-in-page-input")
|
||||
true)))
|
||||
|
||||
(js/window.apis.on "loginCallback"
|
||||
(fn [code]
|
||||
(user/login-callback code)))
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
[logseq.graph-parser.config :as gp-config]
|
||||
[logseq.graph-parser.mldoc :as gp-mldoc]
|
||||
[logseq.graph-parser.text :as text]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
[logseq.graph-parser.util :as gp-util]
|
||||
[logseq.graph-parser.util.block-ref :as block-ref]
|
||||
[logseq.graph-parser.util.page-ref :as page-ref]
|
||||
|
@ -1821,9 +1822,15 @@
|
|||
[:span ", "])
|
||||
|
||||
(rum/defc property-cp
|
||||
[config block k v]
|
||||
(let [date (and (= k :date) (date/get-locale-string (str v)))
|
||||
property-pages-enabled? (contains? #{true nil} (:property-pages/enabled? (state/get-config)))]
|
||||
[config block k value]
|
||||
(let [date (and (= k :date) (date/get-locale-string (str value)))
|
||||
user-config (state/get-config)
|
||||
;; In this mode and when value is a set of refs, display full property text
|
||||
;; because :block/properties value only contains refs but user wants to see text
|
||||
v (if (and (:rich-property-values? user-config) (coll? value))
|
||||
(gp-property/property-value-from-content (name k) (:block/content block))
|
||||
value)
|
||||
property-pages-enabled? (contains? #{true nil} (:property-pages/enabled? user-config))]
|
||||
[:div
|
||||
(if property-pages-enabled?
|
||||
(page-cp (assoc config :property? true) {:block/name (subs (str k) 1)})
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
(ns frontend.components.find-in-page
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.handler.search :as search-handler :refer [debounced-search]]
|
||||
[goog.dom :as gdom]
|
||||
[frontend.mixins :as mixins]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(rum/defc search-input
|
||||
[q matches]
|
||||
[:div.flex.w-48.relative
|
||||
[:input#search-in-page-input.form-input.block.sm:text-sm.sm:leading-5.my-2.border-none.mr-4.outline-none
|
||||
{:auto-focus true
|
||||
:placeholder "Find in page"
|
||||
:aria-label "Find in page"
|
||||
:value q
|
||||
:on-change (fn [e]
|
||||
(let [value (util/evalue e)]
|
||||
(state/set-state! [:ui/find-in-page :q] value)
|
||||
(debounced-search)))}]
|
||||
(when-not (string/blank? q)
|
||||
(when-let [total (:matches matches)]
|
||||
[:div.text-sm.absolute.top-2.right-0.py-2.px-4
|
||||
(:activeMatchOrdinal matches 0)
|
||||
"/"
|
||||
total]))
|
||||
[:div#search-in-page-placeholder.absolute.top-2.left-0.p-2.sm:text-sm]])
|
||||
|
||||
(rum/defc search-inner < rum/static
|
||||
(mixins/event-mixin
|
||||
(fn [state]
|
||||
(mixins/hide-when-esc-or-outside
|
||||
state
|
||||
:node (gdom/getElement "search-in-page")
|
||||
:on-hide (fn []
|
||||
(search-handler/electron-exit-find-in-page!)))))
|
||||
[{:keys [matches match-case? q]}]
|
||||
[:div#search-in-page.flex.flex-row.absolute.top-2.right-4.shadow-lg.px-2.py-1.faster-fade-in.items-center
|
||||
|
||||
(search-input q matches)
|
||||
|
||||
(ui/button
|
||||
(ui/icon "letter-case")
|
||||
:on-click (fn []
|
||||
(state/update-state! [:ui/find-in-page :match-case?] not)
|
||||
(debounced-search))
|
||||
:intent "link"
|
||||
:small? true
|
||||
:title "Match case"
|
||||
:class (str (when match-case? "active ") "text-lg"))
|
||||
|
||||
(ui/button
|
||||
(ui/icon "caret-up")
|
||||
:on-click (fn []
|
||||
(state/set-state! [:ui/find-in-page :backward?] true)
|
||||
(debounced-search))
|
||||
:intent "link"
|
||||
:small? true
|
||||
:class "text-lg"
|
||||
:title "Previous result")
|
||||
|
||||
(ui/button
|
||||
(ui/icon "caret-down")
|
||||
:on-click (fn []
|
||||
(state/set-state! [:ui/find-in-page :backward?] false)
|
||||
(debounced-search))
|
||||
:intent "link"
|
||||
:small? true
|
||||
:class "text-lg"
|
||||
:title "Next result")
|
||||
|
||||
(ui/button
|
||||
(ui/icon "x")
|
||||
:on-click (fn []
|
||||
(search-handler/electron-exit-find-in-page!))
|
||||
:intent "link"
|
||||
:small? true
|
||||
:class "text-lg"
|
||||
:title "Close")])
|
||||
|
||||
(rum/defc search < rum/reactive
|
||||
[]
|
||||
(let [{:keys [active?] :as opt} (state/sub :ui/find-in-page)]
|
||||
(when active?
|
||||
(search-inner opt))))
|
|
@ -0,0 +1,21 @@
|
|||
#search-in-page {
|
||||
z-index: 999;
|
||||
background-color: var(--ls-primary-background-color);
|
||||
|
||||
.form-input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ui__button[intent='link'],
|
||||
.ui__button[intent='link']:focus {
|
||||
border-color: none;
|
||||
}
|
||||
|
||||
.ui__button {
|
||||
margin-top: 0;
|
||||
|
||||
&.active {
|
||||
color: var(--ls-link-text-color);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -297,7 +297,7 @@
|
|||
[:div "Recent search:"]
|
||||
(ui/with-shortcut :go/search-in-page "bottom"
|
||||
[:div.flex-row.flex.align-items
|
||||
[:div.mr-2 "Search in page:"]
|
||||
[:div.mr-2 "Search blocks in page:"]
|
||||
[:div {:style {:margin-top 3}}
|
||||
(ui/toggle in-page-search?
|
||||
(fn [_value]
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[frontend.components.svg :as svg]
|
||||
[frontend.components.theme :as theme]
|
||||
[frontend.components.widgets :as widgets]
|
||||
[frontend.components.find-in-page :as find-in-page]
|
||||
[frontend.config :as config]
|
||||
[frontend.context.i18n :refer [t]]
|
||||
[frontend.db :as db]
|
||||
|
@ -347,6 +348,9 @@
|
|||
[:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center.flex-row
|
||||
{:data-is-margin-less-pages margin-less-pages?}
|
||||
|
||||
(when (util/electron?)
|
||||
(find-in-page/search))
|
||||
|
||||
(when show-action-bar?
|
||||
(action-bar/action-bar))
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
get-files get-files-blocks get-files-full get-journals-length
|
||||
get-latest-journals get-page get-page-alias get-page-alias-names get-paginated-blocks
|
||||
get-page-blocks-count get-page-blocks-no-cache get-page-file get-page-format get-page-properties
|
||||
get-page-referenced-blocks get-page-referenced-blocks-full get-page-referenced-pages get-page-unlinked-references get-page-referenced-blocks-no-cache
|
||||
get-page-referenced-blocks get-page-referenced-blocks-full get-page-referenced-pages get-page-unlinked-references
|
||||
get-all-pages get-pages get-pages-relation get-pages-that-mentioned-page get-public-pages get-tag-pages
|
||||
journal-page? page-alias-set pull-block
|
||||
set-file-last-modified-at! page-empty? page-exists? page-empty-or-dummy? get-alias-source-page
|
||||
|
|
|
@ -1152,18 +1152,6 @@
|
|||
db-utils/seq-flatten)]
|
||||
(mapv (fn [page] [page (get-page-alias repo page)]) mentioned-pages))))
|
||||
|
||||
(defn get-page-referenced-blocks-no-cache
|
||||
[page-id]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(->>
|
||||
(d/q '[:find (pull ?b [*])
|
||||
:in $ ?page-id
|
||||
:where
|
||||
[?b :block/refs ?page-id]]
|
||||
(conn/get-db repo)
|
||||
page-id)
|
||||
(flatten))))
|
||||
|
||||
(defn get-page-referenced-blocks-full
|
||||
([page]
|
||||
(get-page-referenced-blocks-full (state/get-current-repo) page nil))
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[clojure.walk :as walk]
|
||||
[frontend.state :as state]
|
||||
[frontend.date :as date]
|
||||
[frontend.db.model :as model]
|
||||
[frontend.db.query-react :as query-react]
|
||||
|
@ -235,12 +234,20 @@
|
|||
(= 4 (count e))
|
||||
(build-between-three-arg e)))
|
||||
|
||||
|
||||
(defn parse-property-value
|
||||
"Parses non-string property values or any page-ref like values"
|
||||
[v]
|
||||
(if-some [res (text/parse-non-string-property-value v)]
|
||||
res
|
||||
(text/split-page-refs-without-brackets v)))
|
||||
|
||||
(defn- build-property-two-arg
|
||||
[e]
|
||||
(let [k (string/replace (name (nth e 1)) "_" "-")
|
||||
v (nth e 2)
|
||||
v (if-not (nil? v)
|
||||
(text/parse-property k v (state/get-config))
|
||||
(parse-property-value (str v))
|
||||
v)
|
||||
v (if (coll? v) (first v) v)]
|
||||
{:query (list 'property '?b (keyword k) v)
|
||||
|
@ -285,7 +292,7 @@
|
|||
(let [[k v] (rest e)
|
||||
k (string/replace (name k) "_" "-")]
|
||||
(if (some? v)
|
||||
(let [v' (text/parse-property k v (state/get-config))
|
||||
(let [v' (parse-property-value (str v))
|
||||
val (if (coll? v') (first v') v')]
|
||||
{:query (list 'page-property '?p (keyword k) val)
|
||||
:rules [:page-property]})
|
||||
|
|
|
@ -2922,8 +2922,9 @@
|
|||
|
||||
(defn- cut-blocks-and-clear-selections!
|
||||
[copy?]
|
||||
(cut-selection-blocks copy?)
|
||||
(clear-selection!))
|
||||
(when-not (get-in @state/state [:ui/find-in-page :active?])
|
||||
(cut-selection-blocks copy?)
|
||||
(clear-selection!)))
|
||||
|
||||
(defn shortcut-copy-selection
|
||||
[_e]
|
||||
|
|
|
@ -373,9 +373,9 @@
|
|||
;; update all pages which have references to this page
|
||||
(let [repo (state/get-current-repo)
|
||||
to-page (db/entity [:block/name (util/page-name-sanity-lc new-name)])
|
||||
blocks (db/get-page-referenced-blocks-no-cache (:db/id page))
|
||||
page-ids (->> (map :block/page blocks)
|
||||
(remove nil?)
|
||||
blocks (:block/_refs (db/entity (:db/id page)))
|
||||
page-ids (->> (map (fn [b]
|
||||
{:db/id (:db/id (:block/page b))}) blocks)
|
||||
(set))
|
||||
tx (->> (map (fn [{:block/keys [uuid content properties] :as block}]
|
||||
(let [content (let [content' (replace-old-page! content old-original-name new-name)]
|
||||
|
@ -389,8 +389,11 @@
|
|||
{:block/uuid uuid
|
||||
:block/content content
|
||||
:block/properties properties
|
||||
:block/properties-order (map first properties)
|
||||
:block/refs (rename-update-block-refs! (:block/refs block) (:db/id page) (:db/id to-page))})))) blocks)
|
||||
:block/properties-order (when (seq properties)
|
||||
(map first properties))
|
||||
:block/refs (->> (rename-update-block-refs! (:block/refs block) (:db/id page) (:db/id to-page))
|
||||
(map :db/id)
|
||||
(set))})))) blocks)
|
||||
(remove nil?))]
|
||||
(db/transact! repo tx)
|
||||
(doseq [page-id page-ids]
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
[promesa.core :as p]
|
||||
[logseq.graph-parser.text :as text]
|
||||
[frontend.util.drawer :as drawer]
|
||||
[frontend.util.property :as property]))
|
||||
[frontend.util.property :as property]
|
||||
[electron.ipc :as ipc]
|
||||
[goog.functions :refer [debounce]]
|
||||
[dommy.core :as dom]))
|
||||
|
||||
(defn add-search-to-recent!
|
||||
[repo q]
|
||||
|
@ -51,6 +54,56 @@
|
|||
(swap! state/state assoc search-key result)
|
||||
result))))))
|
||||
|
||||
(defn open-find-in-page!
|
||||
[]
|
||||
(when (util/electron?)
|
||||
(let [{:keys [active?]} (:ui/find-in-page @state/state)]
|
||||
(when-not active? (state/set-state! [:ui/find-in-page :active?] true)))))
|
||||
|
||||
(defn electron-find-in-page!
|
||||
[]
|
||||
(when (util/electron?)
|
||||
(let [{:keys [active? backward? match-case? q]} (:ui/find-in-page @state/state)
|
||||
option (cond->
|
||||
{}
|
||||
|
||||
(not active?)
|
||||
(assoc :findNext true)
|
||||
|
||||
backward?
|
||||
(assoc :forward false)
|
||||
|
||||
match-case?
|
||||
(assoc :matchCase true))]
|
||||
(open-find-in-page!)
|
||||
(when-not (string/blank? q)
|
||||
(dom/set-style! (dom/by-id "search-in-page-input")
|
||||
:visibility "hidden")
|
||||
(when (> (count q) 1)
|
||||
(dom/set-html! (dom/by-id "search-in-page-placeholder")
|
||||
(util/format
|
||||
"<span><span>%s</span><span style=\"margin-left: -4px;\">%s</span></span>"
|
||||
(first q)
|
||||
(str " " (subs q 1)))))
|
||||
(ipc/ipc "find-in-page" q option)))))
|
||||
|
||||
(defonce debounced-search (debounce electron-find-in-page! 500))
|
||||
|
||||
(defn loop-find-in-page!
|
||||
[backward?]
|
||||
(when (and (get-in @state/state [:ui/find-in-page :active?])
|
||||
(not (state/editing?)))
|
||||
(state/set-state! [:ui/find-in-page :backward?] backward?)
|
||||
(debounced-search)))
|
||||
|
||||
(defn electron-exit-find-in-page!
|
||||
[& {:keys [clear-state?]
|
||||
:or {clear-state? true}}]
|
||||
(when (util/electron?)
|
||||
(ipc/ipc "clear-find-in-page")
|
||||
(when clear-state?
|
||||
(state/set-state! :ui/find-in-page nil))))
|
||||
|
||||
(defn clear-search!
|
||||
([]
|
||||
(clear-search! true))
|
||||
|
|
|
@ -249,6 +249,20 @@
|
|||
(editor-handler/escape-editing)
|
||||
(route-handler/go-to-search! :global))}
|
||||
|
||||
:go/electron-find-in-page {:binding "mod+f"
|
||||
:fn #(when (util/electron?)
|
||||
(search-handler/open-find-in-page!))}
|
||||
|
||||
:go/electron-jump-to-the-next {:binding ["enter" "mod+g"]
|
||||
:fn (fn [_state _e]
|
||||
(when (util/electron?)
|
||||
(search-handler/loop-find-in-page! false)))}
|
||||
|
||||
:go/electron-jump-to-the-previous {:binding ["shift+enter" "mod+shift+g"]
|
||||
:fn (fn [_state _e]
|
||||
(when (util/electron?)
|
||||
(search-handler/loop-find-in-page! true)))}
|
||||
|
||||
:go/journals {:binding "g j"
|
||||
:fn route-handler/go-to-journals!}
|
||||
|
||||
|
@ -280,7 +294,7 @@
|
|||
:graph/open {:fn #(do
|
||||
(editor-handler/escape-editing)
|
||||
(state/set-state! :ui/open-select :graph-open))
|
||||
:binding "mod+shift+g"}
|
||||
:binding "alt+shift+g"}
|
||||
|
||||
:graph/remove {:fn #(do
|
||||
(editor-handler/escape-editing)
|
||||
|
@ -501,6 +515,9 @@
|
|||
:ui/toggle-brackets
|
||||
:go/search-in-page
|
||||
:go/search
|
||||
:go/electron-find-in-page
|
||||
:go/electron-jump-to-the-next
|
||||
:go/electron-jump-to-the-previous
|
||||
:go/backward
|
||||
:go/forward
|
||||
:search/re-index
|
||||
|
@ -553,6 +570,9 @@
|
|||
:editor/select-all-blocks
|
||||
:go/search
|
||||
:go/search-in-page
|
||||
:go/electron-find-in-page
|
||||
:go/electron-jump-to-the-next
|
||||
:go/electron-jump-to-the-previous
|
||||
:editor/undo
|
||||
:editor/redo
|
||||
:editor/copy
|
||||
|
|
|
@ -77,6 +77,9 @@
|
|||
:editor/zoom-out "Zoom out editing block / Backwards otherwise"
|
||||
:ui/toggle-brackets "Toggle whether to display brackets"
|
||||
:go/search-in-page "Search in the current page"
|
||||
:go/electron-find-in-page "Find in page"
|
||||
:go/electron-jump-to-the-next "Jump to the next match to your Find bar search"
|
||||
:go/electron-jump-to-the-previous "Jump to the previous match to your Find bar search"
|
||||
:go/search "Full text search"
|
||||
:go/journals "Go to journals"
|
||||
:go/backward "Backwards"
|
||||
|
|
|
@ -232,6 +232,7 @@
|
|||
|
||||
:encryption/graph-parsing? false
|
||||
|
||||
:ui/find-in-page nil
|
||||
})))
|
||||
|
||||
;; block uuid -> {content(String) -> ast}
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
opts))
|
||||
|
||||
(defn button
|
||||
[text & {:keys [background href class intent on-click small? large?]
|
||||
[text & {:keys [background href class intent on-click small? large? title]
|
||||
:or {small? false large? false}
|
||||
:as option}]
|
||||
(let [klass (when-not intent ".bg-indigo-600.hover:bg-indigo-700.focus:border-indigo-700.active:bg-indigo-700.text-center")
|
||||
|
@ -176,6 +176,7 @@
|
|||
[:button.ui__button
|
||||
(merge
|
||||
{:type "button"
|
||||
:title title
|
||||
:class (str (util/hiccup->class klass) " " class)}
|
||||
(dissoc option :background :class :small? :large?)
|
||||
(when href
|
||||
|
@ -274,6 +275,11 @@
|
|||
[]
|
||||
(gdom/getElement "main-content-container"))
|
||||
|
||||
(defn focus-element
|
||||
[element]
|
||||
(when-let [element ^js (gdom/getElement element)]
|
||||
(.focus element)))
|
||||
|
||||
(defn get-scroll-top []
|
||||
(.-scrollTop (main-node)))
|
||||
|
||||
|
|
|
@ -79,8 +79,7 @@
|
|||
(defn electron?
|
||||
[]
|
||||
(when (and js/window (gobj/get js/window "navigator"))
|
||||
(let [ua (string/lower-case js/navigator.userAgent)]
|
||||
(string/includes? ua " electron")))))
|
||||
(gstring/caseInsensitiveContains js/navigator.userAgent " electron"))))
|
||||
|
||||
#?(:cljs
|
||||
(defn mocked-open-dir-path
|
||||
|
@ -486,7 +485,10 @@
|
|||
|
||||
#?(:cljs
|
||||
(defn safe-path-join [prefix & paths]
|
||||
(apply node-path.join (cons prefix paths))))
|
||||
(let [path (apply node-path.join (cons prefix paths))]
|
||||
(if (and (electron?) (gstring/caseInsensitiveStartsWith path "file://"))
|
||||
(js/decodeURIComponent (subs path 7))
|
||||
path))))
|
||||
|
||||
(defn trim-safe
|
||||
[s]
|
||||
|
|
|
@ -315,12 +315,14 @@ export const nodePath = Object.assign({}, path, {
|
|||
join (input, ...paths) {
|
||||
let orURI = null
|
||||
|
||||
try {
|
||||
orURI = new URL(input)
|
||||
input = input.replace(orURI.protocol + '//', '')
|
||||
.replace(orURI.protocol, '')
|
||||
.replace(/^\/+/, '/')
|
||||
} catch (_e) {}
|
||||
if (input.startsWith("file://")) {
|
||||
try {
|
||||
orURI = new URL(input)
|
||||
input = input.replace(orURI.protocol + '//', '')
|
||||
.replace(orURI.protocol, '')
|
||||
.replace(/^\/+/, '/')
|
||||
} catch (_e) {}
|
||||
}
|
||||
|
||||
input = path.join(input, ...paths)
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
(ns frontend.version)
|
||||
|
||||
(defonce version "0.8.1")
|
||||
(defonce version "0.8.2")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[clojure.string :as str]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.query-dsl :as query-dsl]
|
||||
[frontend.test.helper :as test-helper :refer [load-test-files]]))
|
||||
[frontend.test.helper :as test-helper :include-macros true :refer [load-test-files]]))
|
||||
|
||||
;; TODO: quickcheck
|
||||
;; 1. generate query filters
|
||||
|
@ -45,7 +45,8 @@
|
|||
;; Tests
|
||||
;; =====
|
||||
|
||||
(deftest block-property-queries
|
||||
(defn- block-property-queries-test
|
||||
[]
|
||||
(load-test-files [{:file/path "journals/2022_02_28.md"
|
||||
:file/content "a:: b
|
||||
- b1
|
||||
|
@ -64,7 +65,7 @@ prop-d:: nada"}])
|
|||
(testing "Blocks have given property value"
|
||||
(is (= #{"b1" "b2"}
|
||||
(set (map (comp first str/split-lines :block/content)
|
||||
(dsl-query "(property prop-a val-a)")))))
|
||||
(dsl-query "(property prop-a val-a)")))))
|
||||
|
||||
(is (= ["b2"]
|
||||
(map (comp first str/split-lines :block/content)
|
||||
|
@ -112,15 +113,27 @@ prop-d:: nada"}])
|
|||
(dsl-query "(property prop-d)")))
|
||||
"Blocks that have a property"))
|
||||
|
||||
(deftest page-property-queries
|
||||
(deftest block-property-queries
|
||||
(testing "block property tests with default config"
|
||||
(test-helper/with-config {}
|
||||
(block-property-queries-test)))
|
||||
|
||||
(test-helper/start-test-db!) ;; reset db
|
||||
|
||||
(testing "block property tests with rich-property-values? config"
|
||||
(test-helper/with-config {:rich-property-values? true}
|
||||
(block-property-queries-test))))
|
||||
|
||||
(defn- page-property-queries-test
|
||||
[]
|
||||
(load-test-files [{:file/path "pages/page1.md"
|
||||
:file/content "parent:: [[child page 1]], [[child-no-space]]"}
|
||||
:file/content "parent:: [[child page 1]], [[child-no-space]]\ninteresting:: true"}
|
||||
{:file/path "pages/page2.md"
|
||||
:file/content "foo:: bar"}
|
||||
:file/content "foo:: #bar\ninteresting:: false"}
|
||||
{:file/path "pages/page3.md"
|
||||
:file/content "parent:: [[child page 1]], child page 2\nfoo:: bar"}
|
||||
:file/content "parent:: [[child page 1]], [[child page 2]]\nfoo:: bar\ninteresting:: false"}
|
||||
{:file/path "pages/page4.md"
|
||||
:file/content "parent:: child page 2\nfoo:: baz"}])
|
||||
:file/content "parent:: [[child page 2]]\nfoo:: baz"}])
|
||||
|
||||
(is (= ["page1" "page3" "page4"]
|
||||
(map :block/name (dsl-query "(page-property parent)")))
|
||||
|
@ -160,7 +173,27 @@ prop-d:: nada"}])
|
|||
(map
|
||||
:block/name
|
||||
(dsl-query "(and (not (page-property foo bar)) (page-property parent [[child page 2]]))")))
|
||||
"Page property queries nested NOT in first clause"))
|
||||
"Page property queries nested NOT in first clause")
|
||||
|
||||
(testing "boolean values"
|
||||
(is (= ["page1"]
|
||||
(map :block/name (dsl-query "(page-property interesting true)")))
|
||||
"Boolean true")
|
||||
|
||||
(is (= ["page2" "page3"]
|
||||
(map :block/name (dsl-query "(page-property interesting false)")))
|
||||
"Boolean false")))
|
||||
|
||||
(deftest page-property-queries
|
||||
(testing "page property tests with default config"
|
||||
(test-helper/with-config {}
|
||||
(page-property-queries-test)))
|
||||
|
||||
(test-helper/start-test-db!) ;; reset db
|
||||
|
||||
(testing "page property tests with rich-property-values? config"
|
||||
(test-helper/with-config {:rich-property-values? true}
|
||||
(page-property-queries-test))))
|
||||
|
||||
(deftest task-queries
|
||||
(load-test-files [{:file/path "pages/page1.md"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
(ns frontend.test.frontend-node-test-runner
|
||||
"This is a custom version of the node-test-runner for the frontend build"
|
||||
{:dev/always true} ;; necessary for test-data freshness
|
||||
(:require [frontend.test.node-test-runner :as node-test-runner]
|
||||
[shadow.test.env :as env]
|
||||
[lambdaisland.glogi.console :as glogi-console]
|
||||
;; activate humane test output for all tests
|
||||
[pjstadig.humane-test-output]))
|
||||
|
||||
;; Needed for new test runners
|
||||
(defn ^:dev/after-load reset-test-data! []
|
||||
(-> (env/get-test-data)
|
||||
(env/reset-test-data!)))
|
||||
|
||||
(defn main [& args]
|
||||
[]
|
||||
(glogi-console/install!) ;; see log messages
|
||||
(reset-test-data!)
|
||||
(node-test-runner/parse-and-run-tests args))
|
|
@ -0,0 +1,8 @@
|
|||
(ns frontend.test.helper)
|
||||
|
||||
(defmacro with-config
|
||||
[config & body]
|
||||
`(let [repo# (frontend.state/get-current-repo)]
|
||||
(frontend.state/set-config! repo# ~config)
|
||||
~@body
|
||||
(frontend.state/set-config! repo# nil)))
|
|
@ -1,6 +1,6 @@
|
|||
(ns frontend.test.node-test-runner
|
||||
"shadow-cljs test runner for :node-test that provides the same test selection
|
||||
options as
|
||||
"Application agnostic shadow-cljs test runner for :node-test that provides the
|
||||
same test selection options as
|
||||
https://github.com/cognitect-labs/test-runner#invoke-with-clojure--m-clojuremain.
|
||||
This gives the user a fair amount of control over which tests and namespaces
|
||||
to call from the commandline. Once this test runner is stable enough we should
|
||||
|
@ -12,9 +12,7 @@
|
|||
[clojure.set :as set]
|
||||
[shadow.test :as st]
|
||||
[cljs.test :as ct]
|
||||
["util" :as util]
|
||||
;; activate humane test output for all tests
|
||||
[pjstadig.humane-test-output]))
|
||||
[goog.string :as gstring]))
|
||||
|
||||
;; Cljs.test customization
|
||||
;; Inherit behavior from default reporter
|
||||
|
@ -47,10 +45,10 @@
|
|||
(defn- print-summary
|
||||
"Print help summary given args and opts strings"
|
||||
[options-summary additional-msg]
|
||||
(println (util/format "Usage: %s [OPTIONS]\nOptions:\n%s%s"
|
||||
"$0"
|
||||
options-summary
|
||||
additional-msg)))
|
||||
(println (gstring/format "Usage: %s [OPTIONS]\nOptions:\n%s%s"
|
||||
"$0"
|
||||
options-summary
|
||||
additional-msg)))
|
||||
|
||||
(defn- parse-options
|
||||
"Processes a command's functionality given a cli options definition, arguments
|
||||
|
@ -172,9 +170,9 @@ returns selected tests and namespaces to run"
|
|||
(st/run-test-vars test-env test-vars))
|
||||
(st/run-all-tests test-env nil))))
|
||||
|
||||
(defn main [& args]
|
||||
(reset-test-data!)
|
||||
|
||||
(defn parse-and-run-tests
|
||||
"Main entry point for custom test runners"
|
||||
[args]
|
||||
(let [{:keys [options summary]} (parse-options args cli-options)]
|
||||
(if (:help options)
|
||||
(do
|
||||
|
@ -182,3 +180,9 @@ returns selected tests and namespaces to run"
|
|||
"\n\nMultiple options are ANDed. Defaults to running all tests")
|
||||
(js/process.exit 0))
|
||||
(run-tests (keys (env/get-tests)) (env/get-test-vars) options))))
|
||||
|
||||
(defn main
|
||||
"Main entry point if this ns is configured as a test runner"
|
||||
[& args]
|
||||
(reset-test-data!)
|
||||
(parse-and-run-tests args))
|
||||
|
|
|
@ -228,6 +228,10 @@
|
|||
;; E.g.:property-pages/excludelist #{:duration :author}
|
||||
;; :property-pages/excludelist
|
||||
|
||||
;; Enables property values to contain a mix of tags, page-refs, special
|
||||
;; punctuation and free-form text
|
||||
;; :rich-property-values? true
|
||||
|
||||
;; logbook setup
|
||||
;; :logbook/settings
|
||||
;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated
|
||||
|
|
Loading…
Reference in New Issue