diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb47d7cc79..7ae1d6bd64 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,13 +112,13 @@ jobs: run: clojure -M:clj-kondo --parallel --lint src - name: Carve lint for unused vars - run: bb lint:carve 2>/dev/null + run: bb lint:carve - name: Lint for vars that are too large - run: bb lint:large-vars 2>/dev/null + run: bb lint:large-vars - name: Lint for namespaces that aren't documented - run: bb lint:ns-docstrings 2>/dev/null + run: bb lint:ns-docstrings - name: Lint invalid translation entries run: bb lang:validate-translations diff --git a/.github/workflows/db.yml b/.github/workflows/db.yml index d3e807a253..8361d161aa 100644 --- a/.github/workflows/db.yml +++ b/.github/workflows/db.yml @@ -86,13 +86,13 @@ jobs: run: clojure -M:clj-kondo --lint src test - name: Carve lint for unused vars - run: bb lint:carve 2>/dev/null + run: bb lint:carve - name: Lint for vars that are too large - run: bb lint:large-vars 2>/dev/null + run: bb lint:large-vars - name: Lint datalog rules run: bb lint:rules - name: Lint for namespaces that aren't documented - run: bb lint:ns-docstrings 2>/dev/null + run: bb lint:ns-docstrings diff --git a/.github/workflows/graph-parser.yml b/.github/workflows/graph-parser.yml index 44909f28b1..2ac539af19 100644 --- a/.github/workflows/graph-parser.yml +++ b/.github/workflows/graph-parser.yml @@ -108,10 +108,10 @@ jobs: run: clojure -M:clj-kondo --parallel --lint src test - name: Carve lint for unused vars - run: bb lint:carve 2>/dev/null + run: bb lint:carve - name: Lint for vars that are too large - run: bb lint:large-vars 2>/dev/null + run: bb lint:large-vars - name: Lint for namespaces that aren't documented - run: bb lint:ns-docstrings 2>/dev/null + run: bb lint:ns-docstrings diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index de5663b84e..6eafa22a46 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -2,8 +2,8 @@ android { compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } } diff --git a/android/build.gradle b/android/build.gradle index 632d121927..c6bd5595f2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,8 +8,8 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.1.1' - classpath 'com.google.gms:google-services:4.3.15' + classpath 'com.android.tools.build:gradle:8.7.2' + classpath 'com.google.gms:google-services:4.4.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 7454180f2a..a4b76b9530 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3796d3cd3c..c1d5e01859 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew index 1b6c787337..f5feea6d6b 100755 --- a/android/gradlew +++ b/android/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +82,12 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +134,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +217,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/android/gradlew.bat b/android/gradlew.bat index ac1b06f938..9b42019c79 100644 --- a/android/gradlew.bat +++ b/android/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/android/variables.gradle b/android/variables.gradle index df5c0f24d8..b319e0e7d1 100644 --- a/android/variables.gradle +++ b/android/variables.gradle @@ -1,16 +1,16 @@ ext { - minSdkVersion = 22 - compileSdkVersion = 33 - targetSdkVersion = 33 - androidxActivityVersion = '1.7.0' - androidxAppCompatVersion = '1.6.1' + minSdkVersion = 23 + compileSdkVersion = 35 + targetSdkVersion = 35 + androidxActivityVersion = '1.9.2' + androidxAppCompatVersion = '1.7.0' androidxCoordinatorLayoutVersion = '1.2.0' - androidxCoreVersion = '1.10.0' - androidxFragmentVersion = '1.5.6' + androidxCoreVersion = '1.15.0' + androidxFragmentVersion = '1.8.4' junitVersion = '4.13.2' - androidxJunitVersion = '1.1.5' - androidxEspressoCoreVersion = '3.5.1' + androidxJunitVersion = '1.2.1' + androidxEspressoCoreVersion = '3.6.1' cordovaAndroidVersion = '10.1.1' - coreSplashScreenVersion = '1.0.0' - androidxWebkitVersion = '1.6.1' + coreSplashScreenVersion = '1.0.1' + androidxWebkitVersion = '1.12.1' } diff --git a/deps.edn b/deps.edn index 2f62a543c9..fa2087345a 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,8 @@ {:paths ["src/main" "src/electron" "src/resources"] :deps {org.clojure/clojure {:mvn/version "1.11.1"} - rum/rum {:mvn/version "0.12.9"} + rum/rum {:git/url "https://github.com/logseq/rum" ;; fork + :sha "5d672bf84ed944414b9f61eeb83808ead7be9127"} datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork :sha "1f84d10df4970f054489b0ee78799f64b8dd4ee2"} diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 4bfa4b9372..d5e440fce5 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -430,6 +430,9 @@ {:type :coll :hide? true :public? false} + ;; ignore this property when rtc, + ;; since users frequently click the sort button to view table content temporarily, + ;; but this action does not need to be synchronized with other clients. :rtc {:rtc/ignore-attr-when-init-upload true :rtc/ignore-attr-when-init-download true :rtc/ignore-attr-when-syncing true}} @@ -438,47 +441,32 @@ :schema {:type :map :hide? true - :public? false} - :rtc {:rtc/ignore-attr-when-init-upload true - :rtc/ignore-attr-when-init-download true - :rtc/ignore-attr-when-syncing true}} + :public? false}} :logseq.property.table/hidden-columns {:title "View hidden columns" :schema {:type :keyword :cardinality :many :hide? true - :public? false} - :rtc {:rtc/ignore-attr-when-init-upload true - :rtc/ignore-attr-when-init-download true - :rtc/ignore-attr-when-syncing true}} + :public? false}} :logseq.property.table/ordered-columns {:title "View ordered columns" :schema {:type :coll :hide? true - :public? false} - :rtc {:rtc/ignore-attr-when-init-upload true - :rtc/ignore-attr-when-init-download true - :rtc/ignore-attr-when-syncing true}} + :public? false}} :logseq.property.table/sized-columns {:title "View columns settings" :schema {:type :map :hide? true - :public? false} - :rtc {:rtc/ignore-attr-when-init-upload true - :rtc/ignore-attr-when-init-download true - :rtc/ignore-attr-when-syncing true}} + :public? false}} :logseq.property.table/pinned-columns {:title "Table view pinned columns" :schema {:type :property :cardinality :many :hide? true - :public? false} - :rtc {:rtc/ignore-attr-when-init-upload true - :rtc/ignore-attr-when-init-download true - :rtc/ignore-attr-when-syncing true}} + :public? false}} :logseq.property/view-for {:title "This view belongs to" :schema {:type :node diff --git a/deps/db/src/logseq/db/frontend/property/build.cljs b/deps/db/src/logseq/db/frontend/property/build.cljs index 6a1eb70ef5..49bba4a866 100644 --- a/deps/db/src/logseq/db/frontend/property/build.cljs +++ b/deps/db/src/logseq/db/frontend/property/build.cljs @@ -65,26 +65,32 @@ (into [property-tx] (closed-values->blocks property)))) -(defn- build-property-value-block +(defn build-property-value-block "Builds a property value entity given a block map/entity, a property entity or - ident and its property value" - [block property value & {:keys [block-uuid]}] + ident and its property value. Takes the following options: + * :block-uuid - :block/uuid for property value entity + * :properties - Additional properties and attributes to add to entity" + [block property value & {:keys [block-uuid properties]}] (let [block-id (or (:db/id block) (:db/ident block))] - (-> (merge - {:block/uuid (or block-uuid (common-uuid/gen-uuid)) - :block/page (if (:block/page block) - (:db/id (:block/page block)) + (cond-> + (merge + {:block/uuid (or block-uuid (common-uuid/gen-uuid)) + :block/page (if (:block/page block) + (:db/id (:block/page block)) ;; page block - block-id) - :block/parent block-id - :logseq.property/created-from-property (if (= (:db/ident property) :logseq.property/default-value) - block-id - (or (:db/id property) {:db/ident (:db/ident property)})) - :block/order (db-order/gen-key)} - (if (db-property-type/property-value-content? (:logseq.property/type property) property) - {:logseq.property/value value} - {:block/title value})) - common-util/block-with-timestamps))) + block-id) + :block/parent block-id + :logseq.property/created-from-property (if (= (:db/ident property) :logseq.property/default-value) + block-id + (or (:db/id property) {:db/ident (:db/ident property)})) + :block/order (db-order/gen-key)} + (if (db-property-type/property-value-content? (:logseq.property/type property) property) + {:logseq.property/value value} + {:block/title value})) + true + common-util/block-with-timestamps + properties + (merge properties)))) (defn build-property-values-tx-m "Builds a map of property names to their property value blocks to be @@ -99,7 +105,7 @@ (let [block' (if (:db/id block) block (assoc block :db/id [:block/uuid (:block/uuid block)]))] (->> properties (map (fn [[k v]] - (let [property-map (if (map? k) k {:db/ident k}) + (let [{:keys [property-value-properties] :as property-map} (if (map? k) k {:db/ident k}) gen-uuid-value-prefix (when pure? (or (:db/ident block) (:block/uuid block)))] (assert (:db/ident property-map) "Key in map must have a :db/ident") @@ -108,15 +114,20 @@ (if (set? v) (set (map #(build-property-value-block block' property-map % - (when pure? - {:block-uuid - (common-uuid/gen-uuid :builtin-block-uuid (str gen-uuid-value-prefix "-" %))})) + (cond-> {} + property-value-properties + (assoc :properties property-value-properties) + pure? + (assoc :block-uuid + (common-uuid/gen-uuid :builtin-block-uuid (str gen-uuid-value-prefix "-" %))))) v)) (build-property-value-block block' property-map v - (when pure? - {:block-uuid - (common-uuid/gen-uuid - :builtin-block-uuid (str gen-uuid-value-prefix "-" v))})))]))) + (cond-> {} + property-value-properties + (assoc :properties property-value-properties) + pure? + (assoc :block-uuid + (common-uuid/gen-uuid :builtin-block-uuid (str gen-uuid-value-prefix "-" v))))))]))) (into {})))) (defn build-properties-with-ref-values diff --git a/deps/db/src/logseq/db/sqlite/build.cljs b/deps/db/src/logseq/db/sqlite/build.cljs index 2b3887bd64..22a071d2be 100644 --- a/deps/db/src/logseq/db/sqlite/build.cljs +++ b/deps/db/src/logseq/db/sqlite/build.cljs @@ -99,6 +99,30 @@ "Provides the next temp :db/id to use in a create-graph transact!" #(swap! current-db-id dec)) +(defn- build-property-map-for-pvalue-tx + "Returns a property map if the given property pair should have a property value entity constructured + or nil if it should not. Property maps must at least contain the :db/ident and :logseq.property/type keys" + [k v new-block properties-config all-idents] + (if-let [built-in-type (get-in db-property/built-in-properties [k :schema :type])] + (if (and (db-property-type/value-ref-property-types built-in-type) + ;; closed values are referenced by their :db/ident so no need to create values + (not (get-in db-property/built-in-properties [k :closed-values]))) + {:db/ident k + :logseq.property/type built-in-type} + (when-let [built-in-type' (get (or (:build/properties-ref-types new-block) + ;; Reasonable default for properties like logseq.property/default-value + {:entity :number}) + built-in-type)] + {:db/ident k + :logseq.property/type built-in-type'})) + (when (and (db-property-type/value-ref-property-types (get-in properties-config [k :logseq.property/type])) + ;; Don't build property value entity if values are :block/uuid refs + (if (set? v) (not (vector? (first v))) (not (vector? v)))) + (let [prop-type (get-in properties-config [k :logseq.property/type])] + {:db/ident (get-ident all-idents k) + :original-property-id k + :logseq.property/type prop-type})))) + (defn- ->property-value-tx-m "Given a new block and its properties, creates a map of properties which have values of property value tx. This map is used for both creating the new property values and then adding them to a block. @@ -106,28 +130,18 @@ [new-block properties properties-config all-idents] (->> properties (keep (fn [[k v]] - (if-let [built-in-type (get-in db-property/built-in-properties [k :schema :type])] - (if (and (db-property-type/value-ref-property-types built-in-type) - ;; closed values are referenced by their :db/ident so no need to create values - (not (get-in db-property/built-in-properties [k :closed-values]))) - (let [property-map {:db/ident k - :logseq.property/type built-in-type}] - [property-map v]) - (when-let [built-in-type' (get (or (:build/properties-ref-types new-block) - ;; Reasonable default for properties like logseq.property/default-value - {:entity :number}) - built-in-type)] - (let [property-map {:db/ident k - :logseq.property/type built-in-type'}] - [property-map v]))) - (when (and (db-property-type/value-ref-property-types (get-in properties-config [k :logseq.property/type])) - ;; TODO: Support translate-property-value without this hack - (not (vector? v))) - (let [prop-type (get-in properties-config [k :logseq.property/type]) - property-map {:db/ident (get-ident all-idents k) - :original-property-id k - :logseq.property/type prop-type}] - [property-map v]))))) + (when-let [property-map (build-property-map-for-pvalue-tx k v new-block properties-config all-idents)] + [(let [pvalue-attrs (when (:build/property-value v) + (merge (:build/properties v) + {:block/tags (mapv #(hash-map :db/ident (get-ident all-idents %)) + (:build/tags v))} + (select-keys v [:block/created-at :block/updated-at])))] + (cond-> property-map + (and (:build/property-value v) (seq pvalue-attrs)) + (assoc :property-value-properties pvalue-attrs))) + (if (:build/property-value v) + (or (:logseq.property/value v) (:block/title v)) + v)]))) (db-property-build/build-property-values-tx-m new-block))) (defn- extract-basic-content-refs diff --git a/deps/db/src/logseq/db/sqlite/export.cljs b/deps/db/src/logseq/db/sqlite/export.cljs index 27c2d39cbd..b5e839c7a7 100644 --- a/deps/db/src/logseq/db/sqlite/export.cljs +++ b/deps/db/src/logseq/db/sqlite/export.cljs @@ -12,7 +12,8 @@ [logseq.db.frontend.entity-plus :as entity-plus] [logseq.db.frontend.entity-util :as entity-util] [logseq.db.frontend.property :as db-property] - [logseq.db.sqlite.build :as sqlite-build])) + [logseq.db.sqlite.build :as sqlite-build] + [medley.core :as medley])) ;; Export fns ;; ========== @@ -37,54 +38,84 @@ {:build/journal (:block/journal-day page-entity)} {:block/title (block-title page-entity)})) -(defn- buildable-property-value-entity - "Converts property value to a buildable version" - [property-ent pvalue {:keys [property-value-uuids?]}] - (cond (and (not property-value-uuids?) (ldb/internal-page? pvalue)) +(defn- build-pvalue-entity-for-build-page + [pvalue] + (cond (ldb/internal-page? pvalue) ;; Should page properties be pulled here? [:build/page (cond-> (shallow-copy-page pvalue) (seq (:block/tags pvalue)) (assoc :build/tags (->build-tags (:block/tags pvalue))))] - (and (not property-value-uuids?) (entity-util/journal? pvalue)) - [:build/page {:build/journal (:block/journal-day pvalue)}] - :else - (if (contains? #{:node :date} (:logseq.property/type property-ent)) - ;; Idents take precedence over uuid because they are keep data graph-agnostic - (if (:db/ident pvalue) - (:db/ident pvalue) - ;; Use metadata distinguish from block references that don't exist like closed values - ^::existing-property-value? [:block/uuid (:block/uuid pvalue)]) - (or (:db/ident pvalue) - ;; nbb-compatible version of db-property/property-value-content - (or (block-title pvalue) - (:logseq.property/value pvalue)))))) + (entity-util/journal? pvalue) + [:build/page {:build/journal (:block/journal-day pvalue)}])) + +(defn- build-pvalue-entity-default [ent-properties pvalue options] + (if (or (seq ent-properties) (seq (:block/tags pvalue))) + (cond-> {:build/property-value :block + :block/title (or (block-title pvalue) + (:logseq.property/value pvalue))} + (seq (:block/tags pvalue)) + (assoc :build/tags (->build-tags (:block/tags pvalue))) + + (seq ent-properties) + (assoc :build/properties ent-properties) + + (:include-timestamps? options) + (merge (select-keys pvalue [:block/created-at :block/updated-at]))) + ;; nbb-compatible version of db-property/property-value-content + (or (block-title pvalue) + (:logseq.property/value pvalue)))) (defn- buildable-properties "Originally copied from db-test/readable-properties. Modified so that property values are valid sqlite.build EDN" [db ent-properties properties-config options] - (->> ent-properties - (map (fn [[k v]] - [k - (if (and (:block/closed-value-property v) (not (db-property/logseq-property? k))) - (if-let [closed-uuid (some #(when (= (:value %) (db-property/property-value-content v)) - (:uuid %)) - (get-in properties-config [k :build/closed-values]))] - [:block/uuid closed-uuid] - (throw (ex-info (str "No closed value found for content: " (pr-str (db-property/property-value-content v))) {:properties properties-config}))) - (cond - (de/entity? v) - (buildable-property-value-entity (d/entity db k) v options) - (and (set? v) (every? de/entity? v)) - (let [property-ent (d/entity db k)] - (set (map #(buildable-property-value-entity property-ent % options) v))) - :else - v))])) - (into {}))) + (letfn [(build-pvalue-entity + [db' property-ent pvalue properties-config' {:keys [property-value-uuids?] :as options'}] + (if-let [build-page (and (not property-value-uuids?) (build-pvalue-entity-for-build-page pvalue))] + build-page + (if (contains? #{:node :date} (:logseq.property/type property-ent)) + ;; Idents take precedence over uuid because they are keep data graph-agnostic + (if (:db/ident pvalue) + (:db/ident pvalue) + ;; Use metadata distinguish from block references that don't exist like closed values + ^::existing-property-value? [:block/uuid (:block/uuid pvalue)]) + (or (:db/ident pvalue) + (let [ent-properties* (->> (apply dissoc (db-property/properties pvalue) + :logseq.property/value :logseq.property/created-from-property + db-property/public-db-attribute-properties) + ;; TODO: Allow user properties when sqlite.build supports it + (medley/filter-keys db-property/internal-property?)) + ent-properties (when (and (not (:block/closed-value-property pvalue)) (seq ent-properties*)) + (buildable-properties db' ent-properties* properties-config' options'))] + (build-pvalue-entity-default ent-properties pvalue options'))))))] + (->> ent-properties + (map (fn [[k v]] + [k + ;; handle user closed value properties. built-ins have idents and shouldn't be handled here + (if (and (not (db-property/logseq-property? k)) + (or (:block/closed-value-property v) + (and (set? v) (:block/closed-value-property (first v))))) + (let [find-closed-uuid (fn [val] + (or (some #(when (= (:value %) (db-property/property-value-content val)) + (:uuid %)) + (get-in properties-config [k :build/closed-values])) + (throw (ex-info (str "No closed value found for content: " (pr-str (db-property/property-value-content val))) {:properties properties-config}))))] + (if (set? v) + (set (map #(vector :block/uuid (find-closed-uuid %)) v)) + [:block/uuid (find-closed-uuid v)])) + (cond + (de/entity? v) + (build-pvalue-entity db (d/entity db k) v properties-config options) + (and (set? v) (every? de/entity? v)) + (let [property-ent (d/entity db k)] + (set (map #(build-pvalue-entity db property-ent % properties-config options) v))) + :else + v))])) + (into {})))) (defn- build-export-properties "The caller of this fn is responsible for building :build/:property-classes unless shallow-copy?" - [db user-property-idents {:keys [include-properties? include-timestamps? include-uuid? shallow-copy?] :as options}] + [db user-property-idents {:keys [include-properties? include-timestamps? include-uuid? shallow-copy? include-alias?] :as options}] (let [properties-config-by-ent (->> user-property-idents (map (fn [ident] @@ -98,6 +129,8 @@ (assoc :block/uuid (:block/uuid property) :build/keep-uuid? true) include-timestamps? (merge (select-keys property [:block/created-at :block/updated-at])) + (and (not shallow-copy?) include-alias? (:block/alias property)) + (assoc :block/alias (set (map #(vector :block/uuid (:block/uuid %)) (:block/alias property)))) (and (not shallow-copy?) (:logseq.property/classes property)) (assoc :build/property-classes (mapv :db/ident (:logseq.property/classes property))) (seq closed-values) @@ -129,8 +162,7 @@ (defn- build-export-class "The caller of this fn is responsible for building any classes or properties from this fn unless shallow-copy?" - [class-ent {:keys [include-parents? include-uuid? shallow-copy? include-timestamps?] - :or {include-parents? true}}] + [class-ent {:keys [include-uuid? shallow-copy? include-timestamps? include-alias?]}] (cond-> (select-keys class-ent [:block/title :block/collapsed?]) include-uuid? (assoc :block/uuid (:block/uuid class-ent) :build/keep-uuid? true) @@ -139,11 +171,10 @@ (and (:logseq.property.class/properties class-ent) (not shallow-copy?)) (assoc :build/class-properties (mapv :db/ident (:logseq.property.class/properties class-ent))) - (and (not shallow-copy?) (:block/alias class-ent)) + (and (not shallow-copy?) include-alias? (:block/alias class-ent)) (assoc :block/alias (set (map #(vector :block/uuid (:block/uuid %)) (:block/alias class-ent)))) ;; It's caller's responsibility to ensure parent is included in final export - (and include-parents? - (not shallow-copy?) + (and (not shallow-copy?) (:logseq.property/parent class-ent) (not= :logseq.class/Root (:db/ident (:logseq.property/parent class-ent)))) (assoc :build/class-parent @@ -364,12 +395,26 @@ :classes (apply merge (map :classes uuid-block-pages)) :pages-and-blocks (mapv #(select-keys % [:page :blocks]) uuid-block-pages)})) +(defn sort-pages-and-blocks + "Provide a reliable sort order since this tends to be large. Helps with diffing + and readability" + [pages-and-blocks] + (vec + (sort-by #(or (get-in % [:page :block/title]) + (some-> (get-in % [:page :build/journal]) str) + (str (get-in % [:page :block/uuid]))) + pages-and-blocks))) + (defn- finalize-export-maps - "Given final export maps, merges them, adds any missing class parents and merges those in" + "Given final export maps, merges them, adds any missing class parents and merges those in. + If :pages-and-blocks exist, sorts them in order to have reliable sort order" [db & export-maps] (let [final-export* (apply merge-export-maps export-maps) - class-parents-export (some->> (:classes final-export*) (build-class-parents-export db))] - (merge-export-maps final-export* class-parents-export))) + class-parents-export (some->> (:classes final-export*) (build-class-parents-export db)) + merged-map (merge-export-maps final-export* class-parents-export)] + (cond-> merged-map + (:pages-and-blocks merged-map) + (update :pages-and-blocks sort-pages-and-blocks)))) (defn- build-block-export "Exports block for given block eid" @@ -387,7 +432,7 @@ (merge {::block (:node node-export)} block-export))) -(defn- build-page-blocks-export [db page-entity {:keys [properties classes blocks ontology-page?] :as options}] +(defn- build-page-blocks-export [db page-entity {:keys [properties classes blocks ontology-page? include-alias?] :as options}] (let [options' (cond-> (dissoc options :classes :blocks :graph-ontology) (:exclude-ontology? options) (assoc :properties (get-in options [:graph-ontology :properties]))) @@ -400,7 +445,7 @@ (:node page-ent-export) (merge (dissoc (:node page-ent-export) :block/title) (shallow-copy-page page-entity) - (when (:block/alias page-entity) + (when (and include-alias? (:block/alias page-entity)) {:block/alias (set (map #(vector :block/uuid (:block/uuid %)) (:block/alias page-entity)))}))) page-blocks-export {:pages-and-blocks [{:page page :blocks blocks}] :properties properties @@ -439,7 +484,9 @@ page-export (finalize-export-maps db page-export* uuid-block-export content-ref-export)] page-export)) -(defn build-view-nodes-export* [db nodes opts] +(defn- build-nodes-export + "Export a mix of pages and blocks" + [db nodes opts] (let [node-pages (filter entity-util/page? nodes) pages-export (merge @@ -452,9 +499,7 @@ (->> node-blocks (group-by :block/page) (map (fn [[parent-page-ent blocks]] - (merge (build-blocks-export db - (sort-by :block/order blocks) - (merge opts {:include-children? false})) + (merge (build-blocks-export db (sort-by :block/order blocks) opts) {:page (shallow-copy-page parent-page-ent)})))) pages-to-blocks-export {:properties (apply merge (map :properties pages-to-blocks)) @@ -474,7 +519,29 @@ {:keys [content-ref-uuids content-ref-ents] :as content-ref-export} (build-content-ref-export db (into nodes property-value-ents)) {:keys [pvalue-uuids] :as nodes-export} - (build-view-nodes-export* db nodes {:include-uuid-fn content-ref-uuids}) + (build-nodes-export db nodes {:include-uuid-fn content-ref-uuids :include-children? false}) + uuid-block-export (build-uuid-block-export db pvalue-uuids content-ref-ents {}) + view-nodes-export (finalize-export-maps db nodes-export uuid-block-export content-ref-export)] + view-nodes-export)) + +(defn- build-selected-nodes-export + "Exports given nodes selected by a user. Nodes can be a mix of blocks and pages" + [db eids] + (let [top-level-nodes (map #(d/entity db %) eids) + children-nodes (->> top-level-nodes + ;; Remove pages b/c when selected their children are not highlighted + (remove entity-util/page?) + (mapcat #(rest (ldb/get-block-and-children db (:block/uuid %)))) + (remove :logseq.property/created-from-property)) + nodes (concat top-level-nodes children-nodes) + property-value-ents (mapcat #(->> (apply dissoc (db-property/properties %) db-property/public-db-attribute-properties) + vals + (filter de/entity?)) + nodes) + {:keys [content-ref-uuids content-ref-ents] :as content-ref-export} + (build-content-ref-export db (into nodes property-value-ents)) + {:keys [pvalue-uuids] :as nodes-export} + (build-nodes-export db nodes {:include-uuid-fn content-ref-uuids :include-children? true}) uuid-block-export (build-uuid-block-export db pvalue-uuids content-ref-ents {}) view-nodes-export (finalize-export-maps db nodes-export uuid-block-export content-ref-export)] view-nodes-export)) @@ -607,16 +674,6 @@ :blocks (sqlite-build/update-each-block blocks remove-uuid-if-not-ref)}) pages-and-blocks)))))) -(defn sort-pages-and-blocks - "Provide a reliable sort order since this tends to be large. Helps with diffing - and readability" - [pages-and-blocks] - (vec - (sort-by #(or (get-in % [:page :block/title]) - (some-> (get-in % [:page :build/journal]) str) - (str (get-in % [:page :block/uuid]))) - pages-and-blocks))) - (defn- add-ontology-for-include-namespaces "Adds :properties to export for given namespace parents. Current use case is for :exclude-namespaces so no need to add :classes yet" @@ -644,7 +701,8 @@ * :exclude-built-in-pages? - When set, built-in pages are excluded from export * :exclude-files? - When set, files are excluded from export" [db {:keys [exclude-files?] :as options*}] - (let [options (merge options* {:property-value-uuids? true}) + (let [options (merge options* {:property-value-uuids? true + :include-alias? true}) content-ref-uuids (get-graph-content-ref-uuids db options) ontology-options (merge options {:include-uuid? true}) ontology-export (build-graph-ontology-export db ontology-options) @@ -702,7 +760,10 @@ ;; Only looks one-level deep in properties e.g. not inside :build/page ;; Doesn't find :block/link refs ref-uuids - (->> (concat (mapcat get-pvalue-uuids (vals classes)) + (->> (concat (mapcat #(map second (:block/alias %)) (vals classes)) + (mapcat #(map second (:block/alias %)) (vals properties)) + (mapcat #(map second (:block/alias (:page %))) pages-and-blocks) + (mapcat get-pvalue-uuids (vals classes)) (mapcat get-pvalue-uuids (vals properties)) (mapcat (comp get-pvalue-uuids :page) pages-and-blocks) (mapcat #(sqlite-build/extract-from-blocks (:blocks %) get-pvalue-uuids) pages-and-blocks)) @@ -736,6 +797,8 @@ (build-page-export db (:page-id options)) :view-nodes (build-view-nodes-export db (:node-ids options)) + :selected-nodes + (build-selected-nodes-export db (:node-ids options)) :graph-ontology (build-graph-ontology-export db {}) :graph diff --git a/deps/db/test/logseq/db/sqlite/build_test.cljs b/deps/db/test/logseq/db/sqlite/build_test.cljs index 0e7e3d883c..c61f67d39b 100644 --- a/deps/db/test/logseq/db/sqlite/build_test.cljs +++ b/deps/db/test/logseq/db/sqlite/build_test.cljs @@ -205,4 +205,43 @@ (->> (d/q '[:find [?b ...] :in $ ?page-id :where [?b :block/page ?page-id]] @conn [:block/uuid property-uuid]) (map #(:block/title (d/entity @conn %))))) - "Property page has correct blocks"))) \ No newline at end of file + "Property page has correct blocks"))) + +(deftest property-value-with-properties-and-tags + (let [conn (db-test/create-conn-with-blocks + {:properties {:p1 {:logseq.property/type :default}} + :classes {:C1 {}} + :pages-and-blocks + [{:page {:block/title "page1"} + :blocks [{:block/title "block has pvalue with built-in tag" + :build/properties + {:p1 {:build/property-value :block + :block/title "t1" + :build/tags [:logseq.class/Task]}}} + {:block/title "block has pvalue with user tag" + :build/properties + {:p1 {:build/property-value :block + :block/title "u1" + :build/tags [:C1]}}} + {:block/title "Todo query", + :build/tags [:logseq.class/Query], + :build/properties + {:logseq.property/query + {:build/property-value :block + :block/title "{:query (task Todo)}" + :build/properties + {:logseq.property.code/lang "clojure" + :logseq.property.node/display-type :code}}}}]}]})] + (is (= {:logseq.property.node/display-type :code + :logseq.property.code/lang "clojure"} + (-> (db-test/find-block-by-content @conn "{:query (task Todo)}") + db-test/readable-properties + (dissoc :logseq.property/created-from-property)))) + (is (= {:block/tags [:logseq.class/Task]} + (-> (db-test/find-block-by-content @conn "t1") + db-test/readable-properties + (dissoc :logseq.property/created-from-property)))) + (is (= {:block/tags [:user.class/C1]} + (-> (db-test/find-block-by-content @conn "u1") + db-test/readable-properties + (dissoc :logseq.property/created-from-property)))))) \ No newline at end of file diff --git a/deps/db/test/logseq/db/sqlite/export_test.cljs b/deps/db/test/logseq/db/sqlite/export_test.cljs index ed75c41dcd..cf02c5655f 100644 --- a/deps/db/test/logseq/db/sqlite/export_test.cljs +++ b/deps/db/test/logseq/db/sqlite/export_test.cljs @@ -57,17 +57,21 @@ (sqlite-export/build-export @import-conn {:export-type :page :page-id (:db/id page2)}))) (defn- import-second-time-assertions [conn conn2 page-title original-data - & {:keys [transform-expected-blocks] + & {:keys [transform-expected-blocks build-journal] :or {transform-expected-blocks (fn [bs] (into bs bs))}}] (let [page (db-test/find-page-by-title @conn2 page-title) imported-page (export-page-and-import-to-another-graph conn conn2 page-title) updated-page (db-test/find-page-by-title @conn2 page-title) expected-page-and-blocks - (update-in (:pages-and-blocks original-data) [0 :blocks] transform-expected-blocks)] + (update-in (:pages-and-blocks original-data) [0 :blocks] transform-expected-blocks) + filter-imported-page (if build-journal + #(= build-journal (get-in % [:page :build/journal])) + #(= (get-in % [:page :block/title]) page-title))] + (assert (first expected-page-and-blocks)) ;; Assume first page is one being imported for now (is (= (first expected-page-and-blocks) - (first (:pages-and-blocks imported-page))) + (first (filter filter-imported-page (:pages-and-blocks imported-page)))) "Blocks are appended to existing page") (is (= (:block/created-at page) (:block/created-at updated-page)) "Existing page didn't get re-created") @@ -323,7 +327,8 @@ (is (= (-> (:pages-and-blocks original-data) (medley/dissoc-in [1 :blocks 0 :build/properties]) ;; shallow block means this page doesn't get included - butlast) + butlast + sort-pages-and-blocks) (:pages-and-blocks imported-page)) "Page's blocks are imported") @@ -412,7 +417,7 @@ (is (= (:pages-and-blocks original-data) (:pages-and-blocks imported-page)) "Page's blocks are imported") - (import-second-time-assertions conn conn2 journal-title original-data))) + (import-second-time-assertions conn conn2 journal-title original-data {:build-journal 20250210}))) (deftest import-page-with-different-property-types (let [block-object-uuid (random-uuid) @@ -458,7 +463,8 @@ "Page's classes are imported") (is (= (-> (:pages-and-blocks original-data) ;; adjust shallow block - (medley/dissoc-in [1 :blocks 0 :build/tags])) + (medley/dissoc-in [1 :blocks 0 :build/tags]) + sort-pages-and-blocks) (:pages-and-blocks imported-page)) "Page's blocks are imported") @@ -527,7 +533,44 @@ imported-nodes (sqlite-export/build-export @conn2 {:export-type :view-nodes :node-ids (get-node-ids @conn2)})] - (is (= (:pages-and-blocks original-data) (:pages-and-blocks imported-nodes))) + (is (= (sort-pages-and-blocks (:pages-and-blocks original-data)) (:pages-and-blocks imported-nodes))) + (is (= (expand-properties (:properties original-data)) (:properties imported-nodes))) + (is (= (expand-classes (:classes original-data)) (:classes imported-nodes))))) + +(deftest import-selected-nodes + (let [original-data + ;; Test a mix of pages and blocks + {:properties {:user.property/p1 {:logseq.property/type :default}} + :classes {:user.class/class1 {}} + :pages-and-blocks [{:page {:block/title "page1"} + :blocks [{:block/title "b1" + :build/properties {:user.property/p1 "ok"} + :build/children [{:block/title "b2"}]} + {:block/title "b3" + :build/tags [:user.class/class1] + :build/children [{:block/title "b4"}]}]} + {:page {:block/title "page2"} + :blocks [{:block/title "dont export"}]}]} + conn (db-test/create-conn-with-blocks original-data) + get-node-ids (fn [db] + (->> [(db-test/find-block-by-content db "b1") + (db-test/find-page-by-title db "b3") + (db-test/find-page-by-title db "page2")] + (remove nil?) + (mapv #(vector :block/uuid (:block/uuid %))))) + conn2 (db-test/create-conn) + {:keys [init-tx block-props-tx] :as _txs} + (-> (sqlite-export/build-export @conn {:export-type :selected-nodes :node-ids (get-node-ids @conn)}) + (sqlite-export/build-import @conn2 {})) + ;; _ (cljs.pprint/pprint _txs) + _ (d/transact! conn2 init-tx) + _ (d/transact! conn2 block-props-tx) + _ (validate-db @conn2) + imported-nodes (sqlite-export/build-export @conn2 {:export-type :selected-nodes :node-ids (get-node-ids @conn2)})] + + (is (= (->> (:pages-and-blocks original-data) + (map #(if (= (get-in % [:page :block/title]) "page2") (dissoc % :blocks) %))) + (:pages-and-blocks imported-nodes))) (is (= (expand-properties (:properties original-data)) (:properties imported-nodes))) (is (= (expand-classes (:classes original-data)) (:classes imported-nodes))))) @@ -558,6 +601,7 @@ :logseq.property/default-value 42})} :user.property/default-closed {:logseq.property/type :default + :db/cardinality :db.cardinality/many :build/closed-values [{:value "joy" :uuid closed-value-uuid} {:value "sad" :uuid (random-uuid)}]} :user.property/checkbox {:logseq.property/type :checkbox} @@ -587,10 +631,25 @@ :user.property/node #{[:block/uuid page-pvalue-uuid]}}} :blocks [{:block/title "b1" :build/properties {:user.property/num 1 - :user.property/default-closed [:block/uuid closed-value-uuid] + :user.property/default-closed #{[:block/uuid closed-value-uuid]} :user.property/date [:block/uuid journal-uuid]}} {:block/title "b2" :build/properties {:user.property/node #{[:block/uuid page-object-uuid]}}} - {:block/title "b3" :build/properties {:user.property/node #{[:block/uuid page-object-uuid]}}}]} + {:block/title "b3" :build/properties {:user.property/node #{[:block/uuid page-object-uuid]}}} + {:block/title "Example advanced query", + :build/tags [:logseq.class/Query], + :build/properties + {:logseq.property/query + {:build/property-value :block + :block/title "{:query (task Todo)}" + :build/properties + {:logseq.property.code/lang "clojure" + :logseq.property.node/display-type :code}}}} + {:block/title "block has property value with tags and properties" + :build/properties + {:user.property/url + {:build/property-value :block + :block/title "https://example.com" + :build/tags [:user.class/MyClass]}}}]} {:page {:block/title "page object" :block/uuid page-object-uuid :build/keep-uuid? true} diff --git a/deps/graph-parser/nbb.edn b/deps/graph-parser/nbb.edn index 98eda58b65..95d1f22920 100644 --- a/deps/graph-parser/nbb.edn +++ b/deps/graph-parser/nbb.edn @@ -2,9 +2,8 @@ :deps {logseq/common {:local/root "../common"} - logseq/db {:local/root "../db"} - io.github.nextjournal/nbb-test-runner - {:git/sha "60ed57aa04bca8d604f5ba6b28848bd887109347"}}} + {:git/sha "60ed57aa04bca8d604f5ba6b28848bd887109347"} + io.github.pez/baldr {:mvn/version "1.0.9"}}} \ No newline at end of file diff --git a/deps/graph-parser/package.json b/deps/graph-parser/package.json index 3ebe01be00..a66f0505b0 100644 --- a/deps/graph-parser/package.json +++ b/deps/graph-parser/package.json @@ -10,6 +10,7 @@ "mldoc": "^1.5.9" }, "scripts": { - "test": "nbb-logseq -cp test:../outliner/src -m nextjournal.test-runner" + "test": "nbb-logseq -cp test:../outliner/src -m nextjournal.test-runner", + "test-v": "nbb-logseq -cp test:../outliner/src -m logseq.graph-parser.test-runner" } } diff --git a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs index 1676bf7a86..e92e990a6e 100644 --- a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs @@ -918,30 +918,41 @@ (dissoc :block/whiteboard?) (update-page-tags db user-options per-file-state all-idents))) +(defn- get-page-parents + "Like ldb/get-page-parents but using all-existing-page-uuids" + [node all-existing-page-uuids] + (let [get-parent (fn get-parent [n] + (when (:block/uuid (:logseq.property/parent n)) + (or (get all-existing-page-uuids (:block/uuid (:logseq.property/parent n))) + (throw (ex-info (str "No parent page found for " (pr-str (:block/uuid (:logseq.property/parent n)))) + {:node n})))))] + (when-let [parent (get-parent node)] + (loop [current-parent parent + parents' []] + (if (and current-parent (not (contains? parents' current-parent))) + (recur (get-parent current-parent) + (conj parents' current-parent)) + (vec (reverse parents'))))))) + (defn- get-all-existing-page-uuids "Returns a map of unique page names mapped to their uuids. The page names are in a format that is compatible with extract/extract e.g. namespace pages have their full hierarchy in the name" - [db classes-from-property-parents] - (->> db - ;; don't fetch built-in as that would give the wrong entity if a user used - ;; a db-only built-in property name e.g. description - (d/q '[:find [?b ...] - :where [?b :block/name] [(missing? $ ?b :logseq.property/built-in?)]]) - (map #(d/entity db %)) - (map #(vector - (if-let [parents (and (or (ldb/internal-page? %) (ldb/class? %)) + [classes-from-property-parents all-existing-page-uuids] + (->> all-existing-page-uuids + (map (fn [[_ p]] + (vector + (if-let [parents (and (or (contains? (:block/tags p) :logseq.class/Tag) + (contains? (:block/tags p) :logseq.class/Page)) ;; These classes have parents now but don't in file graphs (and in extract) - (not (contains? classes-from-property-parents (:block/title %))) - (->> (ldb/get-page-parents %) - (remove (fn [e] (= :logseq.class/Root (:db/ident e)))) - seq))] + (not (contains? classes-from-property-parents (:block/title p))) + (get-page-parents p all-existing-page-uuids))] ;; Build a :block/name for namespace pages that matches data from extract/extract - (string/join ns-util/namespace-char (map :block/name (conj (vec parents) %))) - (:block/name %)) - (or (:block/uuid %) - (throw (ex-info (str "No uuid for existing page " (pr-str (:block/name %))) - (select-keys % [:block/name :block/tags])))))) + (string/join ns-util/namespace-char (map :block/name (conj (vec parents) p))) + (:block/name p)) + (or (:block/uuid p) + (throw (ex-info (str "No uuid for existing page " (pr-str (:block/name p))) + (select-keys p [:block/name :block/tags]))))))) (into {}))) (defn- build-existing-page @@ -1008,8 +1019,9 @@ (not (:block/file %)))) ;; remove file path relative (map #(dissoc % :block/file))) - ;; Fetch all named ents once per import file to speed up named lookups - all-existing-page-uuids (get-all-existing-page-uuids @conn @(:classes-from-property-parents import-state)) + ;; Build all named ents once per import file to speed up named lookups + all-existing-page-uuids (get-all-existing-page-uuids @(:classes-from-property-parents import-state) + @(:all-existing-page-uuids import-state)) all-pages (map #(modify-page-tx % all-existing-page-uuids) all-pages*) all-new-page-uuids (->> all-pages (remove #(all-existing-page-uuids (or (::original-name %) (:block/name %)))) @@ -1119,6 +1131,8 @@ ;; Map of property names (keyword) and their current schemas (map of qualified properties). ;; Used for adding schemas to properties and detecting changes across a property's usage :property-schemas (atom {}) + ;; Indexes all created pages by uuid. Index is used to fetch all parents of a page + :all-existing-page-uuids (atom {}) ;; Map of property or class names (keyword) to db-ident keywords :all-idents (atom {}) ;; Set of children pages turned into classes by :property-parent-classes option @@ -1312,6 +1326,12 @@ classes-tx) retract-page-tag-from-existing-pages)})) +(defn- save-from-tx + "Save importer state from given txs" + [txs {:keys [import-state]}] + (when-let [nodes (seq (filter :block/name txs))] + (swap! (:all-existing-page-uuids import-state) merge (into {} (map (juxt :block/uuid identity) nodes))))) + (defn add-file-to-db-graph "Parse file and save parsed data to the given db graph. Options available: @@ -1351,6 +1371,7 @@ ;; _ (when (seq property-pages-tx) (cljs.pprint/pprint {:property-pages-tx property-pages-tx})) ;; Necessary to transact new property entities first so that block+page properties can be transacted next main-props-tx-report (d/transact! conn property-pages-tx {::new-graph? true ::path file}) + _ (save-from-tx property-pages-tx options) classes-tx @(:classes-tx tx-options) {:keys [retract-page-tags-tx] pages-tx'' :pages-tx} (clean-extra-invalid-tags @conn pages-tx' classes-tx existing-pages) @@ -1376,11 +1397,13 @@ ;; [whiteboard-pages pages-index page-properties-tx property-page-properties-tx pages-tx' classes-tx blocks-index blocks-tx])) ;; _ (when (not (seq whiteboard-pages)) (cljs.pprint/pprint {#_:property-pages-tx #_property-pages-tx :pages-tx pages-tx :tx tx'})) main-tx-report (d/transact! conn tx' {::new-graph? true ::path file}) + _ (save-from-tx tx' options) upstream-properties-tx (build-upstream-properties-tx @conn @(:upstream-properties tx-options) (:import-state options) log-fn) ;; _ (when (seq upstream-properties-tx) (cljs.pprint/pprint {:upstream-properties-tx upstream-properties-tx})) - upstream-tx-report (when (seq upstream-properties-tx) (d/transact! conn upstream-properties-tx {::new-graph? true ::path file}))] + upstream-tx-report (when (seq upstream-properties-tx) (d/transact! conn upstream-properties-tx {::new-graph? true ::path file})) + _ (save-from-tx upstream-properties-tx options)] ;; Return all tx-reports that occurred in this fn as UI needs to know what changed [main-props-tx-report main-tx-report upstream-tx-report])) diff --git a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs index 5d3eb2162e..a085a48bd9 100644 --- a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs @@ -10,6 +10,7 @@ [logseq.common.util.date-time :as date-time-util] [logseq.db :as ldb] [logseq.db.frontend.content :as db-content] + [logseq.db.frontend.entity-plus :as entity-plus] [logseq.db.frontend.malli-schema :as db-malli-schema] [logseq.db.frontend.rules :as rules] [logseq.db.frontend.validate :as db-validate] @@ -19,8 +20,7 @@ [logseq.graph-parser.test.docs-graph-helper :as docs-graph-helper] [logseq.graph-parser.test.helper :as test-helper :include-macros true :refer [deftest-async]] [logseq.outliner.db-pipeline :as db-pipeline] - [promesa.core :as p] - [logseq.db.frontend.entity-plus :as entity-plus])) + [promesa.core :as p])) ;; Helpers ;; ======= @@ -130,11 +130,18 @@ (deftest-async ^:integration export-docs-graph-with-convert-all-tags (p/let [file-graph-dir "test/resources/docs-0.10.9" + start-time (cljs.core/system-time) _ (docs-graph-helper/clone-docs-repo-if-not-exists file-graph-dir "v0.10.9") conn (db-test/create-conn) _ (db-pipeline/add-listener conn) {:keys [import-state]} - (import-file-graph-to-db file-graph-dir conn {:convert-all-tags? true})] + (import-file-graph-to-db file-graph-dir conn {:convert-all-tags? true}) + end-time (cljs.core/system-time)] + + ;; Add multiplicative factor for CI as it runs about twice as slow + (let [max-time (-> 15 (* (if js/process.env.CI 2 1)))] + (is (< (-> end-time (- start-time) (/ 1000)) max-time) + (str "Importing large graph takes less than " max-time "s"))) (is (empty? (map :entity (:errors (db-validate/validate-db! @conn)))) "Created graph has no validation errors") diff --git a/deps/graph-parser/test/logseq/graph_parser/test_runner.cljs b/deps/graph-parser/test/logseq/graph_parser/test_runner.cljs new file mode 100644 index 0000000000..50f8d1d3f1 --- /dev/null +++ b/deps/graph-parser/test/logseq/graph_parser/test_runner.cljs @@ -0,0 +1,6 @@ +(ns logseq.graph-parser.test-runner + "Test runner which enables https://github.com/PEZ/baldr by default" + (:require [nextjournal.test-runner :as next-runner] + [pez.baldr])) + +(def -main next-runner/-main) diff --git a/deps/shui/deps.edn b/deps/shui/deps.edn index fdb9142c2f..8206a42d82 100644 --- a/deps/shui/deps.edn +++ b/deps/shui/deps.edn @@ -3,6 +3,8 @@ {org.clojure/clojure {:mvn/version "1.11.1"} org.clojure/clojurescript {:mvn/version "1.11.132"} funcool/promesa {:mvn/version "11.0.678"} - rum/rum {:mvn/version "0.12.9"} + rum/rum {:git/url "https://github.com/logseq/rum" ;; fork + :sha "5d672bf84ed944414b9f61eeb83808ead7be9127"} + medley/medley {:mvn/version "1.4.0"} cljs-bean/cljs-bean {:mvn/version "1.5.0"}}} diff --git a/deps/shui/src/logseq/shui/demo.cljs b/deps/shui/src/logseq/shui/demo.cljs index 861f734699..0619a1b07d 100644 --- a/deps/shui/src/logseq/shui/demo.cljs +++ b/deps/shui/src/logseq/shui/demo.cljs @@ -1,10 +1,11 @@ (ns logseq.shui.demo - (:require [rum.core :as rum] - [logseq.shui.ui :as ui] - [dommy.core :refer-macros [sel1]] + (:require [dommy.core :refer-macros [sel1]] + [logseq.shui.dialog.core :as dialog-core] [logseq.shui.form.core :refer [yup yup-resolver] :as form-core] + [logseq.shui.hooks :as hooks] + [logseq.shui.ui :as ui] [promesa.core :as p] - [logseq.shui.dialog.core :as dialog-core])) + [rum.core :as rum])) (rum/defc section-item [title children] @@ -511,7 +512,7 @@ [] (let [el-ref (rum/use-ref nil)] - (rum/use-effect! + (hooks/use-effect! (fn [] (let [^js container (get-main-scroll-container) ^js el (rum/deref el-ref) diff --git a/deps/shui/src/logseq/shui/demo2.cljs b/deps/shui/src/logseq/shui/demo2.cljs index 33b277c990..95737ac900 100644 --- a/deps/shui/src/logseq/shui/demo2.cljs +++ b/deps/shui/src/logseq/shui/demo2.cljs @@ -1,23 +1,24 @@ (ns logseq.shui.demo2 - (:require [clojure.string :as string] - [rum.core :as rum] - [logseq.shui.ui :as ui] - [logseq.shui.popup.core :refer [install-popups update-popup! get-popup]] - [logseq.shui.select.multi :refer [x-select-content]] + (:require [cljs-bean.core :as bean] + [clojure.string :as string] [frontend.components.icon :refer [emojis-cp emojis icon-search]] [frontend.storage :as storage] - [cljs-bean.core :as bean] - [promesa.core :as p])) + [logseq.shui.hooks :as hooks] + [logseq.shui.popup.core :refer [install-popups update-popup! get-popup]] + [logseq.shui.select.multi :refer [x-select-content]] + [logseq.shui.ui :as ui] + [promesa.core :as p] + [rum.core :as rum])) (defn do-fetch! ([action] (do-fetch! action nil)) ([action query-str] (-> (js/window.fetch - (str "https://movies-api14.p.rapidapi.com/" (name action) (when query-str (str "?" query-str))) - #js {:method "GET" - :headers #js {:X-RapidAPI-Key "808ffd08c0mshc67d496f6024b46p164350jsn7b35179966c9", - :X-RapidAPI-Host "movies-api14.p.rapidapi.com"}}) - (p/then #(.json %))))) + (str "https://movies-api14.p.rapidapi.com/" (name action) (when query-str (str "?" query-str))) + #js {:method "GET" + :headers #js {:X-RapidAPI-Key "808ffd08c0mshc67d496f6024b46p164350jsn7b35179966c9", + :X-RapidAPI-Host "movies-api14.p.rapidapi.com"}}) + (p/then #(.json %))))) (rum/defc multi-select-demo [] @@ -35,96 +36,96 @@ rm-item! (fn [item-or-id] (set-selected-items! - (remove #(or (= item-or-id %) - (= item-or-id (str (:id %)))) - selected-items))) + (remove #(or (= item-or-id %) + (= item-or-id (str (:id %)))) + selected-items))) add-item! (fn [item] (set-selected-items! (conj selected-items item))) [open? set-open!] (rum/use-state false)] - (rum/use-effect! - (fn [] - (storage/set :ls-demo-multi-selected-items selected-items)) - [selected-items]) + (hooks/use-effect! + (fn [] + (storage/set :ls-demo-multi-selected-items selected-items)) + [selected-items]) (ui/card - (ui/card-header - (ui/card-title "Search Movies") - (ui/card-description "x multiselect for the remote items")) - (ui/card-content + (ui/card-header + (ui/card-title "Search Movies") + (ui/card-description "x multiselect for the remote items")) + (ui/card-content ;; Basic - (ui/dropdown-menu - {:open open?} + (ui/dropdown-menu + {:open open?} ;; trigger - (ui/dropdown-menu-trigger - [:div.border.p-2.rounded.w-full.cursor-pointer.flex.items-center.gap-1.flex-wrap - {:on-click (fn [^js e] - (let [^js target (.-target e)] - (if-let [^js c (some-> target (.closest ".close"))] - (some-> (.-dataset c) (.-k) (rm-item!)) - (set-open! true))))} - (for [{:keys [id original_title class poster_path]} selected-items] - (ui/badge {:variant :secondary :class (str class " group relative")} - [:span.flex.items-center.gap-1.flex-nowrap - [:img {:src poster_path :class "w-[16px] scale-75"}] - [:b original_title]] - (ui/button - {:variant :destructive - :size :icon - :data-k id - :class "!rounded-full !h-4 !w-4 absolute top-[-7px] right-[-3px] group-hover:visible invisible close"} - (ui/tabler-icon "x" {:size 12})))) - (ui/button {:variant :link :size :sm} "+")]) + (ui/dropdown-menu-trigger + [:div.border.p-2.rounded.w-full.cursor-pointer.flex.items-center.gap-1.flex-wrap + {:on-click (fn [^js e] + (let [^js target (.-target e)] + (if-let [^js c (some-> target (.closest ".close"))] + (some-> (.-dataset c) (.-k) (rm-item!)) + (set-open! true))))} + (for [{:keys [id original_title class poster_path]} selected-items] + (ui/badge {:variant :secondary :class (str class " group relative")} + [:span.flex.items-center.gap-1.flex-nowrap + [:img {:src poster_path :class "w-[16px] scale-75"}] + [:b original_title]] + (ui/button + {:variant :destructive + :size :icon + :data-k id + :class "!rounded-full !h-4 !w-4 absolute top-[-7px] right-[-3px] group-hover:visible invisible close"} + (ui/tabler-icon "x" {:size 12})))) + (ui/button {:variant :link :size :sm} "+")]) ;; content - (x-select-content items selected-items - {;; test item render - :open? open? - :close! #(set-open! false) - :search-enabled? true - :search-key q - :search-fn (fn [items] - (when (not fetching?) items)) - :on-search-key-change (fn [v] - (set-q! v) - (if (string/blank? v) - (set-items! []) - (when (not fetching?) - (set-fetching? true) - (-> (do-fetch! :search (str "query=" v)) - (p/then #(when-let [ret (bean/->clj %)] - (when-let [items (:contents ret)] - (set-items! (map (fn [item] (assoc item :id (:_id item))) (take 12 items)))))) - (p/finally #(set-fetching? false)))))) + (x-select-content items selected-items + {;; test item render + :open? open? + :close! #(set-open! false) + :search-enabled? true + :search-key q + :search-fn (fn [items] + (when (not fetching?) items)) + :on-search-key-change (fn [v] + (set-q! v) + (if (string/blank? v) + (set-items! []) + (when (not fetching?) + (set-fetching? true) + (-> (do-fetch! :search (str "query=" v)) + (p/then #(when-let [ret (bean/->clj %)] + (when-let [items (:contents ret)] + (set-items! (map (fn [item] (assoc item :id (:_id item))) (take 12 items)))))) + (p/finally #(set-fetching? false)))))) - :item-render (fn [item {:keys [selected?]}] - (if item - (ui/dropdown-menu-checkbox-item - {:checked selected? - :on-click (fn [] - (if selected? - (rm-item! item) - (add-item! item)) + :item-render (fn [item {:keys [selected?]}] + (if item + (ui/dropdown-menu-checkbox-item + {:checked selected? + :on-click (fn [] + (if selected? + (rm-item! item) + (add-item! item)) ;(set-open! false) - )} - [:div.flex.items-center.gap-2 - [:span [:img {:src (:poster_path item) - :class "w-[20px]"}]] - [:span.flex.flex-col - [:b (:original_title item)] - [:small.opacity-50 - {:class "text-[10px]"} - (:release_date item)]]]) - (ui/dropdown-menu-separator))) + )} + [:div.flex.items-center.gap-2 + [:span [:img {:src (:poster_path item) + :class "w-[20px]"}]] + [:span.flex.flex-col + [:b (:original_title item)] + [:small.opacity-50 + {:class "text-[10px]"} + (:release_date item)]]]) + (ui/dropdown-menu-separator))) - :head-render (fn [] (when (and fetching? (not (string/blank? q))) - [:b.flex.items-center.justify-center.py-4 - (ui/tabler-icon "loader" {:class "animate-spin"})])) + :head-render (fn [] (when (and fetching? (not (string/blank? q))) + [:b.flex.items-center.justify-center.py-4 + (ui/tabler-icon "loader" {:class "animate-spin"})])) ;:foot-render (fn [] [:b "footer"]) - :content-props - {:align "start" - :class "w-80"}}))))) + :content-props + {:align "start" + :class "w-80"}}))))) [:hr] @@ -146,50 +147,50 @@ [open? set-open!] (rum/use-state false)] (ui/card - (ui/card-header - (ui/card-title "Basic") - (ui/card-description "x multiselect for shui")) - (ui/card-content - [:label.block.flex.items-center.pb-3.cursor-pointer - (ui/checkbox {:checked search? - :on-click #(set-search? (not search?))}) - [:small.pl-2 "Enable basic search input"]] + (ui/card-header + (ui/card-title "Basic") + (ui/card-description "x multiselect for shui")) + (ui/card-content + [:label.block.flex.items-center.pb-3.cursor-pointer + (ui/checkbox {:checked search? + :on-click #(set-search? (not search?))}) + [:small.pl-2 "Enable basic search input"]] ;; Basic - (ui/dropdown-menu - {:open open?} + (ui/dropdown-menu + {:open open?} ;; trigger - (ui/dropdown-menu-trigger - [:p.border.p-2.rounded.w-full.cursor-pointer - {:on-click #(set-open! true)} - (for [{:keys [key value class]} selected-items] - (ui/badge {:variant :secondary :class class} (str "#" key " " value))) - (ui/button {:variant :link :size :sm} "+")]) + (ui/dropdown-menu-trigger + [:p.border.p-2.rounded.w-full.cursor-pointer + {:on-click #(set-open! true)} + (for [{:keys [key value class]} selected-items] + (ui/badge {:variant :secondary :class class} (str "#" key " " value))) + (ui/button {:variant :link :size :sm} "+")]) ;; content - (x-select-content items selected-items - {:close! #(set-open! false) - :search-enabled? search? - :search-key-render (fn [q {:keys [items]}] - (when (and (not (string/blank? q)) - (not (seq items))) - [:b.flex.items-center.justify-center.py-4.gap-2.font-normal.opacity-80 - (ui/tabler-icon "lemon") [:small "No fruits!"]])) - :on-chosen on-chosen - :value-render (fn [v {:keys [selected?]}] - (if selected? - [:b.text-red-800 v] - [:b.text-green-800 v])) - :content-props - {:class "w-48"}}))))) + (x-select-content items selected-items + {:close! #(set-open! false) + :search-enabled? search? + :search-key-render (fn [q {:keys [items]}] + (when (and (not (string/blank? q)) + (not (seq items))) + [:b.flex.items-center.justify-center.py-4.gap-2.font-normal.opacity-80 + (ui/tabler-icon "lemon") [:small "No fruits!"]])) + :on-chosen on-chosen + :value-render (fn [v {:keys [selected?]}] + (if selected? + [:b.text-red-800 v] + [:b.text-green-800 v])) + :content-props + {:class "w-48"}}))))) [:hr] (let [[items set-items!] (rum/use-state - [{:key 1 :value "Apple" :class "bg-gray-800 text-gray-50"} - {:key 2 :value "Orange" :class "bg-orange-700 text-gray-50"} - nil - {:key 3 :value "Pear"} - {:key 4 :value "Banana" :class "bg-yellow-700 text-gray-700"}]) + [{:key 1 :value "Apple" :class "bg-gray-800 text-gray-50"} + {:key 2 :value "Orange" :class "bg-orange-700 text-gray-50"} + nil + {:key 3 :value "Pear"} + {:key 4 :value "Banana" :class "bg-yellow-700 text-gray-700"}]) [selected-items set-selected-items!] (rum/use-state [(last items) (first items)]) @@ -202,55 +203,54 @@ [open? set-open!] (rum/use-state false)] (ui/card - (ui/card-header - (ui/card-title "Search & Custom") - (ui/card-description "x multiselect for shui")) - (ui/card-content + (ui/card-header + (ui/card-title "Search & Custom") + (ui/card-description "x multiselect for shui")) + (ui/card-content ;; Basic - (ui/dropdown-menu - {:open open?} + (ui/dropdown-menu + {:open open?} ;; trigger - (ui/dropdown-menu-trigger - [:p.border.p-2.rounded.w-full.cursor-pointer - {:on-click #(set-open! true)} - (for [{:keys [key value class]} selected-items] - (ui/badge {:variant :secondary :class class} (str "#" key " " value))) - (ui/button {:variant :link :size :sm} "+")]) + (ui/dropdown-menu-trigger + [:p.border.p-2.rounded.w-full.cursor-pointer + {:on-click #(set-open! true)} + (for [{:keys [key value class]} selected-items] + (ui/badge {:variant :secondary :class class} (str "#" key " " value))) + (ui/button {:variant :link :size :sm} "+")]) ;; content - (x-select-content items selected-items - {;; test item render - :open? open? - :close! #(set-open! false) - :search-enabled? true - :item-render (fn [item {:keys [selected?]}] - (if item - (ui/dropdown-menu-checkbox-item - {:checked selected? - :on-click (fn [] - (if selected? - (rm-item! item) - (add-item! item)))} - (:value item)) - (ui/dropdown-menu-separator))) + (x-select-content items selected-items + {;; test item render + :open? open? + :close! #(set-open! false) + :search-enabled? true + :item-render (fn [item {:keys [selected?]}] + (if item + (ui/dropdown-menu-checkbox-item + {:checked selected? + :on-click (fn [] + (if selected? + (rm-item! item) + (add-item! item)))} + (:value item)) + (ui/dropdown-menu-separator))) - :search-key-render - (fn [k {:keys [items x-item exist-fn]}] - (when (and - (not (string/blank? k)) - (not (exist-fn))) - (x-item - {:on-click (fn [] - (ui/toast! (str "Create: " k) :warning) - (set-open! false))} - (str "+ create: " k)))) + :search-key-render + (fn [k {:keys [items x-item exist-fn]}] + (when (and + (not (string/blank? k)) + (not (exist-fn))) + (x-item + {:on-click (fn [] + (ui/toast! (str "Create: " k) :warning) + (set-open! false))} + (str "+ create: " k)))) ;:head-render (fn [] [:b "header"]) ;:foot-render (fn [] [:b "footer"]) - :content-props - {:align "start" - :class "w-48"}}))))) - ]) + :content-props + {:align "start" + :class "w-48"}})))))]) (rum/defc icon-picker-demo [] @@ -282,27 +282,27 @@ [:a.underline {:on-click #(ui/popup-show! % - (fn [_config] - [:div.max-h-72.overflow-auto.p-1 - (emojis-cp (take 80 emojis) - {:on-chosen - (fn [_ t] - (set-emoji! t) - (ui/popup-hide-all!))})]) - {:content-props {:class "w-72 p-0"} - :as-dropdown? true})} + (fn [_config] + [:div.max-h-72.overflow-auto.p-1 + (emojis-cp (take 80 emojis) + {:on-chosen + (fn [_ t] + (set-emoji! t) + (ui/popup-hide-all!))})]) + {:content-props {:class "w-72 p-0"} + :as-dropdown? true})} (if emoji [:strong.px-1.text-6xl [:em-emoji emoji]] "emoji :O")] "."])] [:<> (emoji-picker nil) [:p.py-4 (ui/button - {:variant :secondary - :on-click #(ui/popup-show! % - (fn [] - [:p.p-4 - (emoji-picker true)]))} - "Play a nested x popup.")] + {:variant :secondary + :on-click #(ui/popup-show! % + (fn [] + [:p.p-4 + (emoji-picker true)]))} + "Play a nested x popup.")] [:p.py-4 (let [gen-content @@ -312,60 +312,60 @@ (emoji-picker true) [:strong.px-1.text-6xl q]])] (ui/input - {:placeholder "Select a fruit." - :ref *q-ref - :value q - :on-change (fn [^js e] - (let [val (.-value (.-target e))] - (set-q! val) - (update-popup! :select-a-fruit-input [:content] (gen-content val)))) - :class "w-1/5" - :on-focus (fn [^js e] - (let [id :select-a-fruit-input - [_ popup] (get-popup id)] - (if (not popup) - (ui/popup-show! (.-target e) - (gen-content q) - {:id id - :align "start" - :content-props - {:class "x-input-popup-content" - :onPointerDownOutside - (fn [^js e] - (js/console.log "===>> onPointerDownOutside:" e (rum/deref *q-ref)) - (when-let [q-ref (rum/deref *q-ref)] - (let [^js target (or (.-relatedTarget e) - (.-target e))] - (js/console.log "t:" target) - (when (and - (not (.contains q-ref target)) - (not (.closest target ".x-input-popup-content"))) - (ui/popup-hide! id))))) - :onOpenAutoFocus #(.preventDefault %)}}) + {:placeholder "Select a fruit." + :ref *q-ref + :value q + :on-change (fn [^js e] + (let [val (.-value (.-target e))] + (set-q! val) + (update-popup! :select-a-fruit-input [:content] (gen-content val)))) + :class "w-1/5" + :on-focus (fn [^js e] + (let [id :select-a-fruit-input + [_ popup] (get-popup id)] + (if (not popup) + (ui/popup-show! (.-target e) + (gen-content q) + {:id id + :align "start" + :content-props + {:class "x-input-popup-content" + :onPointerDownOutside + (fn [^js e] + (js/console.log "===>> onPointerDownOutside:" e (rum/deref *q-ref)) + (when-let [q-ref (rum/deref *q-ref)] + (let [^js target (or (.-relatedTarget e) + (.-target e))] + (js/console.log "t:" target) + (when (and + (not (.contains q-ref target)) + (not (.closest target ".x-input-popup-content"))) + (ui/popup-hide! id))))) + :onOpenAutoFocus #(.preventDefault %)}}) ;; update content - (update-popup! id [:content] - (gen-content q))))) + (update-popup! id [:content] + (gen-content q))))) ;:on-blur (fn [^js e] ; (let [^js target (.-relatedTarget e)] ; (js/console.log "==>>>" target) ; (when-not (.closest target ".x-input-popup-content") ; (hide-x-popup! :select-a-fruit-input)))) - }))] + }))] [:div.w-full.p-4.border.rounded.dotted.h-48.mt-8.bg-gray-02 {:on-click #(ui/popup-show! % - (->> (range 8) - (map (fn [it] - (ui/dropdown-menu-item - {:on-select (fn [] - (ui/toast! it) - (ui/popup-hide-all!))} - [:strong it])))) - {:as-dropdown? true - :content-props {:class "w-48"}}) + (->> (range 8) + (map (fn [it] + (ui/dropdown-menu-item + {:on-select (fn [] + (ui/toast! it) + (ui/popup-hide-all!))} + [:strong it])))) + {:as-dropdown? true + :content-props {:class "w-48"}}) :on-context-menu #(ui/popup-show! % - [:h1.text-3xl.font-bold "hi x popup for custom context menu!"])}]])]) + [:h1.text-3xl.font-bold "hi x popup for custom context menu!"])}]])]) (rum/defc custom-trigger-content [] @@ -381,17 +381,16 @@ [:h1.text-3xl.font-bold.border-b.pb-4 "Sample dropdown/menu trigger"] [:div.py-4 (ui/dropdown-menu - (ui/dropdown-menu-trigger - {:as-child true} - (ui/trigger-child-wrap - {:class "border p-6 border"} - (custom-trigger-content))) - (ui/dropdown-menu-content - (ui/dropdown-menu-item "A item") - (ui/dropdown-menu-item "B item") - (ui/dropdown-menu-item "C item")))] - ]) + (ui/dropdown-menu-trigger + {:as-child true} + (ui/trigger-child-wrap + {:class "border p-6 border"} + (custom-trigger-content))) + (ui/dropdown-menu-content + (ui/dropdown-menu-item "A item") + (ui/dropdown-menu-item "B item") + (ui/dropdown-menu-item "C item")))]]) (rum/defc page [] - (sample-dropdown-trigger)) \ No newline at end of file + (sample-dropdown-trigger)) diff --git a/deps/shui/src/logseq/shui/dialog/core.cljs b/deps/shui/src/logseq/shui/dialog/core.cljs index 7f5455dbfc..659773f84f 100644 --- a/deps/shui/src/logseq/shui/dialog/core.cljs +++ b/deps/shui/src/logseq/shui/dialog/core.cljs @@ -2,6 +2,7 @@ (:require [daiquiri.interpreter :refer [interpret]] [logseq.shui.base.core :as base] [logseq.shui.form.core :as form] + [logseq.shui.hooks :as hooks] [logseq.shui.util :as util] [medley.core :as medley] [promesa.core :as p] @@ -130,10 +131,11 @@ :close :align :on-open-change :open? :root-props :content-props) props (assoc-in props [:overlay-props :data-align] (name (or align :center)))] - (rum/use-effect! + (hooks/use-effect! (fn [] (when (false? open?) - (js/setTimeout #(detach-modal! id) 128))) + (let [timeout (js/setTimeout #(detach-modal! id) 128)] + #(js/clearTimeout timeout)))) [open?]) (dialog @@ -171,10 +173,11 @@ (let [{:keys [id title description content footer deferred open?]} config props (dissoc config :id :title :description :content :footer :deferred :open? :alert?)] - (rum/use-effect! + (hooks/use-effect! (fn [] (when (false? open?) - (js/setTimeout #(detach-modal! id) 128))) + (let [timeout (js/setTimeout #(detach-modal! id) 128)] + #(js/clearTimeout timeout)))) [open?]) (alert-dialog @@ -209,14 +212,15 @@ *ok-ref (rum/use-ref nil) *reminder-ref (rum/use-ref nil)] - (rum/use-effect! + (hooks/use-effect! (fn [] (when ready? - (js/setTimeout - #(some-> (rum/deref *ok-ref) (.focus)) 128))) + (let [timeout (js/setTimeout + #(some-> (rum/deref *ok-ref) (.focus)) 128)] + #(js/clearTimeout timeout)))) [ready?]) - (rum/use-effect! + (hooks/use-effect! (fn [] (try (if-let [reminder-v (and reminder? (js/localStorage.getItem (str id)))] diff --git a/src/main/frontend/hooks.cljs b/deps/shui/src/logseq/shui/hooks.cljs similarity index 78% rename from src/main/frontend/hooks.cljs rename to deps/shui/src/logseq/shui/hooks.cljs index 6b04b9d9d5..a7ea3a0844 100644 --- a/src/main/frontend/hooks.cljs +++ b/deps/shui/src/logseq/shui/hooks.cljs @@ -1,4 +1,4 @@ -(ns frontend.hooks +(ns logseq.shui.hooks "React custom hooks." (:refer-clojure :exclude [ref deref]) (:require [frontend.common.missionary :as c.m] @@ -26,17 +26,23 @@ "setup-fn will be invoked every render of component when no deps arg provided" ([setup-fn] (rum/use-effect! setup-fn)) ([setup-fn deps & {:keys [equal-fn]}] - (rum/use-effect! setup-fn (if (empty? deps) - deps - #js[(memo-deps equal-fn deps)])))) + (rum/use-effect! (fn [& deps] + (let [result (apply setup-fn deps)] + (when (fn? result) result))) + (if (empty? deps) + deps + #js[(memo-deps equal-fn deps)])))) #_{:clj-kondo/ignore [:discouraged-var]} (defn use-layout-effect! ([setup-fn] (rum/use-layout-effect! setup-fn)) ([setup-fn deps & {:keys [equal-fn]}] - (rum/use-layout-effect! setup-fn (if (empty? deps) - deps - #js[(memo-deps equal-fn deps)])))) + (rum/use-layout-effect! (fn [& deps] + (let [result (apply setup-fn deps)] + (when (fn? result) result))) + (if (empty? deps) + deps + #js[(memo-deps equal-fn deps)])))) #_{:clj-kondo/ignore [:discouraged-var]} (defn use-callback diff --git a/deps/shui/src/logseq/shui/select/multi.cljs b/deps/shui/src/logseq/shui/select/multi.cljs index 205f1fa879..13a98adf84 100644 --- a/deps/shui/src/logseq/shui/select/multi.cljs +++ b/deps/shui/src/logseq/shui/select/multi.cljs @@ -1,14 +1,15 @@ (ns logseq.shui.select.multi (:require [clojure.string :as string] - [rum.core :as rum] + [logseq.shui.form.core :as form] + [logseq.shui.hooks :as hooks] [logseq.shui.popup.core :as popup] - [logseq.shui.form.core :as form])) + [rum.core :as rum])) (defn- get-k [item] (if (map? item) (some->> ((juxt :id :key :label) item) - (remove nil?) - (first)) + (remove nil?) + (first)) item)) (defn- get-v @@ -21,27 +22,27 @@ (let [*el (rum/use-ref nil) [down set-down!] (rum/use-state 0)] - (rum/use-effect! - (fn [] - (when-let [^js item (and (> down 0) - (some-> (rum/deref *el) - (.closest ".head") - (.-nextSibling)))] - (some-> (if valid-search-key? (.-nextSibling item) item) - (.focus)))) - [down]) + (hooks/use-effect! + (fn [] + (when-let [^js item (and (> down 0) + (some-> (rum/deref *el) + (.closest ".head") + (.-nextSibling)))] + (some-> (if valid-search-key? (.-nextSibling item) item) + (.focus)))) + [down]) [:div.search-input {:ref *el} (form/input - (merge {:placeholder "search" - :on-key-up #(case (.-key %) - "ArrowDown" (set-down! (inc down)) - "ArrowUp" nil - "Enter" (when (fn? on-enter) (on-enter)) - :dune) - :auto-focus true} - input-props))])) + (merge {:placeholder "search" + :on-key-up #(case (.-key %) + "ArrowDown" (set-down! (inc down)) + "ArrowUp" nil + "Enter" (when (fn? on-enter) (on-enter)) + :dune) + :auto-focus true} + input-props))])) (defn- simple-search-fn [items q] @@ -49,8 +50,8 @@ (if (string/blank? q) items (filter #(some-> (get-v %) - (string/lower-case) - (string/includes? q)) items)))) + (string/lower-case) + (string/includes? q)) items)))) (rum/defc x-select-content [items selected-items & {:keys [on-chosen item-render value-render @@ -70,8 +71,8 @@ (when (and search-enabled? (not= "INPUT" (.-nodeName target))) ;; focus search input (some-> (get-content-el target) - (.querySelector "input") - (.focus)))) + (.querySelector "input") + (.focus)))) items (if search-enabled? (if (fn? search-fn) (search-fn items search-key1) @@ -79,100 +80,100 @@ items) close1! #(when (fn? close!) (close!))] - (rum/use-effect! - (fn [] - (when (fn? on-search-key-change) - (on-search-key-change search-key1'))) - [search-key1']) + (hooks/use-effect! + (fn [] + (when (fn? on-search-key-change) + (on-search-key-change search-key1'))) + [search-key1']) - (rum/use-effect! - (fn [] - (when-let [t (when (and search-enabled? (false? open?)) - (js/setTimeout #(set-search-key! "") 500))] - #(js/clearTimeout t))) - [open?]) + (hooks/use-effect! + (fn [] + (when-let [t (when (and search-enabled? (false? open?)) + (js/setTimeout #(set-search-key! "") 500))] + #(js/clearTimeout t))) + [open?]) (x-content - (merge - {:onInteractOutside close1! - :onEscapeKeyDown close1! - :on-key-down (fn [^js e] - (when-let [^js target (.-target e)] - (case (.-key e) - "ArrowUp" - (when (= (some-> (get-item-nodes target) (first)) - js/document.activeElement) - (focus-search-input! target)) - "l" (when (or (.-metaKey e) (.-ctrlKey e)) - (focus-search-input! target)) - :dune))) - :class (str (:class content-props) - " ui__multi-select-content" - (when valid-search-key? " has-search-key"))} - (dissoc content-props :class)) + (merge + {:onInteractOutside close1! + :onEscapeKeyDown close1! + :on-key-down (fn [^js e] + (when-let [^js target (.-target e)] + (case (.-key e) + "ArrowUp" + (when (= (some-> (get-item-nodes target) (first)) + js/document.activeElement) + (focus-search-input! target)) + "l" (when (or (.-metaKey e) (.-ctrlKey e)) + (focus-search-input! target)) + :dune))) + :class (str (:class content-props) + " ui__multi-select-content" + (when valid-search-key? " has-search-key"))} + (dissoc content-props :class)) ;; header - (when (or search-enabled? (fn? head-render)) - [:div.head - {:ref *head-ref} - (when search-enabled? - (search-input - {:value search-key1 - :on-key-down (fn [^js e] - (.stopPropagation e) - (case (.-key e) - "Escape" (if (string/blank? search-key1) - (some-> (.-target e) (.closest "[data-radix-menu-content]") (.focus)) - (set-search-key! "")) - :dune)) - :on-change #(set-search-key! (.-value (.-target %)))} + (when (or search-enabled? (fn? head-render)) + [:div.head + {:ref *head-ref} + (when search-enabled? + (search-input + {:value search-key1 + :on-key-down (fn [^js e] + (.stopPropagation e) + (case (.-key e) + "Escape" (if (string/blank? search-key1) + (some-> (.-target e) (.closest "[data-radix-menu-content]") (.focus)) + (set-search-key! "")) + :dune)) + :on-change #(set-search-key! (.-value (.-target %)))} - {:on-enter (fn [] - (when-let [head-el (and (not (string/blank? search-key1')) - (rum/deref *head-ref))] - (when-let [^js item (.-nextSibling head-el)] - (when (contains? #{"menuitemcheckbox" "menuitem"} - (.getAttribute item "role")) - (.click item))))) - :valid-search-key? valid-search-key?})) - (when head-render (head-render))]) + {:on-enter (fn [] + (when-let [head-el (and (not (string/blank? search-key1')) + (rum/deref *head-ref))] + (when-let [^js item (.-nextSibling head-el)] + (when (contains? #{"menuitemcheckbox" "menuitem"} + (.getAttribute item "role")) + (.click item))))) + :valid-search-key? valid-search-key?})) + (when head-render (head-render))]) ;; items - (for [item items - :let [selected? (some #(let [k (get-k item) - k' (get-k %)] - (or (= item %) - (and (not (nil? k)) - (not (nil? k')) - (= k k')))) - selected-items)]] - (if (fn? item-render) - (item-render item {:x-item x-item :selected? selected?}) - (let [k (get-k item) - v (get-v item)] - (when k - (let [opts {:selected? selected?} - on-click' (:on-click item-props) - on-click (fn [e] + (for [item items + :let [selected? (some #(let [k (get-k item) + k' (get-k %)] + (or (= item %) + (and (not (nil? k)) + (not (nil? k')) + (= k k')))) + selected-items)]] + (if (fn? item-render) + (item-render item {:x-item x-item :selected? selected?}) + (let [k (get-k item) + v (get-v item)] + (when k + (let [opts {:selected? selected?} + on-click' (:on-click item-props) + on-click (fn [e] ;; TODO: return value - (when (fn? on-click') (on-click' e)) - (when (fn? on-chosen) - (on-chosen item opts)))] - (x-item (merge {:data-k k :on-click on-click} item-props) - [:span.flex.items-center.gap-2.w-full - (form/checkbox {:checked selected?}) - (let [v' (if (fn? v) (v item opts) v)] - (if (fn? value-render) - (value-render v' (assoc opts :item item)) v'))])))))) + (when (fn? on-click') (on-click' e)) + (when (fn? on-chosen) + (on-chosen item opts)))] + (x-item (merge {:data-k k :on-click on-click} item-props) + [:span.flex.items-center.gap-2.w-full + (form/checkbox {:checked selected?}) + (let [v' (if (fn? v) (v item opts) v)] + (if (fn? value-render) + (value-render v' (assoc opts :item item)) v'))])))))) - (when (and search-enabled? - (fn? search-key-render)) - (let [exist-fn (fn [] - (and (not (string/blank? search-key1)) - (seq items) - (contains? (into #{} (map #(some-> (get-v %) (string/lower-case)) items)) - (string/lower-case search-key1))))] - (search-key-render search-key1 - {:items items :x-item x-item :exist-fn exist-fn}))) + (when (and search-enabled? + (fn? search-key-render)) + (let [exist-fn (fn [] + (and (not (string/blank? search-key1)) + (seq items) + (contains? (into #{} (map #(some-> (get-v %) (string/lower-case)) items)) + (string/lower-case search-key1))))] + (search-key-render search-key1 + {:items items :x-item x-item :exist-fn exist-fn}))) ;; footer - (when (fn? foot-render) - [:div.foot - (foot-render)])))) + (when (fn? foot-render) + [:div.foot + (foot-render)])))) diff --git a/deps/shui/src/logseq/shui/table/core.cljc b/deps/shui/src/logseq/shui/table/core.cljc index 39f5702450..f6a8cf1467 100644 --- a/deps/shui/src/logseq/shui/table/core.cljc +++ b/deps/shui/src/logseq/shui/table/core.cljc @@ -2,6 +2,7 @@ "Table" (:require [clojure.set :as set] [dommy.core :refer-macros [sel1]] + [logseq.shui.hooks :as hooks] [logseq.shui.table.impl :as impl] [rum.core :as rum])) @@ -147,7 +148,7 @@ ;; FIXME: ux (defn- use-sticky-element! [^js/HTMLElement container target-ref] - (rum/use-effect! + (hooks/use-effect! (fn [] (let [^js el (rum/deref target-ref) ^js cls (.-classList el) @@ -189,7 +190,7 @@ ;; FIXME: another solution for the sticky header (defn- use-sticky-element2! [^js/HTMLDivElement target-ref] - (rum/use-effect! + (hooks/use-effect! (fn [] (let [^js target (rum/deref target-ref) ^js container (or (.closest target ".sidebar-item-list") (get-main-scroll-container)) diff --git a/deps/shui/src/logseq/shui/toaster/core.cljs b/deps/shui/src/logseq/shui/toaster/core.cljs index 4115a1ddb1..db31b60867 100644 --- a/deps/shui/src/logseq/shui/toaster/core.cljs +++ b/deps/shui/src/logseq/shui/toaster/core.cljs @@ -1,8 +1,9 @@ (ns logseq.shui.toaster.core - (:require [rum.core :as rum] + (:require [cljs-bean.core :as bean] [daiquiri.interpreter :refer [interpret]] + [logseq.shui.hooks :as hooks] [logseq.shui.util :as util] - [cljs-bean.core :as bean])) + [rum.core :as rum])) (defonce ^:private Toaster (util/lsui-wrap "Toaster")) (defonce ^:private *toast (atom nil)) @@ -23,22 +24,22 @@ < rum/static [] (let [^js js-toast (js/window.LSUI.useToast)] - (rum/use-effect! - (fn [] - (reset! *toast {:toast (.-toast js-toast) - :dismiss (.-dismiss js-toast) - :update (.-update js-toast)}) - #()) - []) + (hooks/use-effect! + (fn [] + (reset! *toast {:toast (.-toast js-toast) + :dismiss (.-dismiss js-toast) + :update (.-update js-toast)}) + #()) + []) [:<> (Toaster)])) (defn update-html-props [v] (update-keys v - #(case % - :class :className - :for :htmlFor - %))) + #(case % + :class :className + :for :htmlFor + %))) (defn interpret-vals [config ks & args] @@ -46,7 +47,7 @@ (let [v (get config k) v (if (fn? v) (apply v args) v)] (if (vector? v) (assoc config k (interpret v)) config))) - config ks)) + config ks)) (defn toast! ([content-or-config] (toast! content-or-config :default nil)) @@ -56,12 +57,12 @@ (let [config (if (map? content-or-config) content-or-config (-> {:description content-or-config} - (merge (if (map? status) status {:variant status})))) + (merge (if (map? status) status {:variant status})))) config (update-html-props (merge config opts)) id (or (:id config) (gen-id)) config (assoc config :id id) config (interpret-vals config [:title :description :action :icon] - {:id id :dismiss! #(dismiss id) :update! #(toast! (assoc %1 :id id))})] + {:id id :dismiss! #(dismiss id) :update! #(toast! (assoc %1 :id id))})] (js->clj (toast (clj->js config)))) :exception))) diff --git a/gulpfile.js b/gulpfile.js index 1ae0c46ab4..ad347250f0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -161,7 +161,7 @@ const common = { stdio: 'inherit', }) - cp.execSync(`npx cap run ${mode} --external`, { + cp.execSync(`npx cap run ${mode}`, { stdio: 'inherit', env: Object.assign(process.env, { LOGSEQ_APP_SERVER_URL, diff --git a/ios/App/Podfile b/ios/App/Podfile index c931f25369..a9fcddd9aa 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -1,6 +1,6 @@ require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers' -platform :ios, '13.0' +platform :ios, '14.0' use_frameworks! # workaround to avoid Xcode caching of Pods that requires diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock new file mode 100644 index 0000000000..b1c5bf28a7 --- /dev/null +++ b/ios/App/Podfile.lock @@ -0,0 +1,131 @@ +PODS: + - AgeEncryption (1.0.6) + - Alamofire (5.6.2) + - AWSCore (2.27.10) + - AWSS3 (2.27.10): + - AWSCore (= 2.27.10) + - Capacitor (7.2.0): + - CapacitorCordova + - CapacitorActionSheet (7.0.1): + - Capacitor + - CapacitorApp (7.0.1): + - Capacitor + - CapacitorCamera (7.0.1): + - Capacitor + - CapacitorClipboard (7.0.1): + - Capacitor + - CapacitorCordova (7.2.0) + - CapacitorFilesystem (7.0.1): + - Capacitor + - CapacitorHaptics (7.0.1): + - Capacitor + - CapacitorKeyboard (7.0.1): + - Capacitor + - CapacitorShare (7.0.1): + - Capacitor + - CapacitorSplashScreen (7.0.1): + - Capacitor + - CapacitorStatusBar (7.0.1): + - Capacitor + - CapacitorVoiceRecorder (5.0.0): + - Capacitor + - CapawesomeCapacitorBackgroundTask (7.0.1): + - Capacitor + - CapgoCapacitorNavigationBar (7.1.2): + - Capacitor + - LogseqCapacitorFileSync (5.0.2): + - AgeEncryption (~> 1.0.6) + - Alamofire + - AWSS3 + - Capacitor + - SendIntent (0.0.1): + - Capacitor + +DEPENDENCIES: + - "Capacitor (from `../../node_modules/@capacitor/ios`)" + - "CapacitorActionSheet (from `../../node_modules/@capacitor/action-sheet`)" + - "CapacitorApp (from `../../node_modules/@capacitor/app`)" + - "CapacitorCamera (from `../../node_modules/@capacitor/camera`)" + - "CapacitorClipboard (from `../../node_modules/@capacitor/clipboard`)" + - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" + - "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)" + - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)" + - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)" + - "CapacitorShare (from `../../node_modules/@capacitor/share`)" + - "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)" + - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)" + - CapacitorVoiceRecorder (from `../../node_modules/capacitor-voice-recorder`) + - "CapawesomeCapacitorBackgroundTask (from `../../node_modules/@capawesome/capacitor-background-task`)" + - "CapgoCapacitorNavigationBar (from `../../node_modules/@capgo/capacitor-navigation-bar`)" + - "LogseqCapacitorFileSync (from `../../node_modules/@logseq/capacitor-file-sync`)" + - SendIntent (from `../../node_modules/send-intent`) + +SPEC REPOS: + trunk: + - AgeEncryption + - Alamofire + - AWSCore + - AWSS3 + +EXTERNAL SOURCES: + Capacitor: + :path: "../../node_modules/@capacitor/ios" + CapacitorActionSheet: + :path: "../../node_modules/@capacitor/action-sheet" + CapacitorApp: + :path: "../../node_modules/@capacitor/app" + CapacitorCamera: + :path: "../../node_modules/@capacitor/camera" + CapacitorClipboard: + :path: "../../node_modules/@capacitor/clipboard" + CapacitorCordova: + :path: "../../node_modules/@capacitor/ios" + CapacitorFilesystem: + :path: "../../node_modules/@capacitor/filesystem" + CapacitorHaptics: + :path: "../../node_modules/@capacitor/haptics" + CapacitorKeyboard: + :path: "../../node_modules/@capacitor/keyboard" + CapacitorShare: + :path: "../../node_modules/@capacitor/share" + CapacitorSplashScreen: + :path: "../../node_modules/@capacitor/splash-screen" + CapacitorStatusBar: + :path: "../../node_modules/@capacitor/status-bar" + CapacitorVoiceRecorder: + :path: "../../node_modules/capacitor-voice-recorder" + CapawesomeCapacitorBackgroundTask: + :path: "../../node_modules/@capawesome/capacitor-background-task" + CapgoCapacitorNavigationBar: + :path: "../../node_modules/@capgo/capacitor-navigation-bar" + LogseqCapacitorFileSync: + :path: "../../node_modules/@logseq/capacitor-file-sync" + SendIntent: + :path: "../../node_modules/send-intent" + +SPEC CHECKSUMS: + AgeEncryption: 23c203675d5e4883a18b133ab1d5e61ff29e0c18 + Alamofire: d368e1ff8a298e6dde360e35a3e68e6c610e7204 + AWSCore: dbad318b7ff0fd86fb8387d3ad1f30049c05bc58 + AWSS3: 0cf2cedb263368f624ca721e5c56a8cb59fc44bc + Capacitor: 106e7a4205f4618d582b886a975657c61179138d + CapacitorActionSheet: 24609588961cc27c87e8b033be92b5eee65b5d4c + CapacitorApp: d63334c052278caf5d81585d80b21905c6f93f39 + CapacitorCamera: eb8687d8687fed853598ec9460d94bcd5e16babe + CapacitorClipboard: b98aead5dc7ec595547fc2c5d75bacd2ae3338bc + CapacitorCordova: 5967b9ba03915ef1d585469d6e31f31dc49be96f + CapacitorFilesystem: 307f97c27a265edf8396a1c9c235592fd8572fe3 + CapacitorHaptics: 70e47470fa1a6bd6338cd102552e3846b7f9a1b3 + CapacitorKeyboard: 969647d0ca2e5c737d7300088e2517aa832434e2 + CapacitorShare: 58d6c2da63b093e8693287b2d36db92435538435 + CapacitorSplashScreen: 19cd3573e57507e02d6f34597a8c421e00931487 + CapacitorStatusBar: 275cbf2f4dfc00388f519ef80c7ec22edda342c9 + CapacitorVoiceRecorder: 872ea857b497ce2c71afe3e4eb5de0a74290c0db + CapawesomeCapacitorBackgroundTask: 834d797abc9933fac4354490d1a2f3c0e389b98d + CapgoCapacitorNavigationBar: 3a0e93a40b7da3d3cb74c0410bb761a1525406be + LogseqCapacitorFileSync: 541dcd5492b8aeb2257cce3d18bb9ed5800cfcad + SendIntent: 0a17b6984c4f27e9dfa56513267ba2c044a5a6c8 + +PODFILE CHECKSUM: d9e4df9f9578f817a4148a5e29ee928f271e4cc8 + +COCOAPODS: 1.11.2 diff --git a/package.json b/package.json index 061ed18498..ee828984d0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "static/electron.js", "devDependencies": { "@axe-core/playwright": "=4.4.4", - "@capacitor/cli": "^5.0.0", + "@capacitor/cli": "7.2.0", "@playwright/test": "=1.51.0", "@tailwindcss/aspect-ratio": "0.4.2", "@tailwindcss/forms": "0.5.3", @@ -85,21 +85,21 @@ "postinstall": "yarn tldraw:build && yarn amplify:build && yarn ui:build" }, "dependencies": { - "@capacitor/action-sheet": "^5.0.7", - "@capacitor/android": "^5.0.0", - "@capacitor/app": "^5.0.0", - "@capacitor/camera": "^5.0.0", - "@capacitor/clipboard": "^5.0.0", - "@capacitor/core": "^5.0.0", - "@capacitor/filesystem": "^5.0.0", - "@capacitor/haptics": "^5.0.0", - "@capacitor/ios": "^5.0.0", - "@capacitor/keyboard": "^5.0.0", - "@capacitor/share": "^5.0.0", - "@capacitor/splash-screen": "^5.0.0", - "@capacitor/status-bar": "^5.0.0", - "@capawesome/capacitor-background-task": "^5.0.0", - "@capgo/capacitor-navigation-bar": "^6.0.0", + "@capacitor/action-sheet": "7.0.1", + "@capacitor/android": "7.2.0", + "@capacitor/app": "7.0.1", + "@capacitor/camera": "7.0.1", + "@capacitor/clipboard": "7.0.1", + "@capacitor/core": "7.2.0", + "@capacitor/filesystem": "7.0.1", + "@capacitor/haptics": "7.0.1", + "@capacitor/ios": "7.2.0", + "@capacitor/keyboard": "7.0.1", + "@capacitor/share": "7.0.1", + "@capacitor/splash-screen": "7.0.1", + "@capacitor/status-bar": "7.0.1", + "@capawesome/capacitor-background-task": "7.0.1", + "@capgo/capacitor-navigation-bar": "7.1.2", "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^7.0.2", "@emoji-mart/data": "^1.1.2", @@ -155,8 +155,8 @@ "pixi.js": "6.2.0", "posthog-js": "1.10.2", "prop-types": "^15.7.2", - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "18.3.1", + "react-dom": "18.3.1", "react-grid-layout": "0.16.6", "react-intersection-observer": "^9.3.5", "react-resize-context": "3.0.0", diff --git a/src/main/frontend/components/assets.cljs b/src/main/frontend/components/assets.cljs index aab80d21a6..4f67f0e019 100644 --- a/src/main/frontend/components/assets.cljs +++ b/src/main/frontend/components/assets.cljs @@ -8,10 +8,10 @@ [frontend.context.i18n :refer [t]] [frontend.handler.assets :as assets-handler] [frontend.handler.notification :as notification] - [frontend.hooks :as hooks] [frontend.state :as state] [frontend.ui :as ui] [frontend.util :as util] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [medley.core :as medley] [promesa.core :as p] diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 460f922d18..6170325c6e 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -55,7 +55,6 @@ [frontend.handler.route :as route-handler] [frontend.handler.ui :as ui-handler] [frontend.handler.whiteboard :as whiteboard-handler] - [frontend.hooks :as hooks] [frontend.mixins :as mixins] [frontend.mobile.intent :as mobile-intent] [frontend.mobile.util :as mobile-util] @@ -87,6 +86,7 @@ [logseq.graph-parser.text :as text] [logseq.outliner.property :as outliner-property] [logseq.shui.dialog.core :as shui-dialog] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [medley.core :as medley] [promesa.core :as p] diff --git a/src/main/frontend/components/bug_report.cljs b/src/main/frontend/components/bug_report.cljs index 1b07c75163..daf4665197 100644 --- a/src/main/frontend/components/bug_report.cljs +++ b/src/main/frontend/components/bug_report.cljs @@ -3,9 +3,9 @@ [frontend.components.header :as header] [frontend.context.i18n :refer [t]] [frontend.handler.notification :as notification] - [frontend.hooks :as hooks] [frontend.ui :as ui] [frontend.util :as util] + [logseq.shui.hooks :as hooks] [reitit.frontend.easy :as rfe] [rum.core :as rum])) diff --git a/src/main/frontend/components/cmdk/core.cljs b/src/main/frontend/components/cmdk/core.cljs index 5d89655e1c..e2db765367 100644 --- a/src/main/frontend/components/cmdk/core.cljs +++ b/src/main/frontend/components/cmdk/core.cljs @@ -18,7 +18,6 @@ [frontend.handler.page :as page-handler] [frontend.handler.route :as route-handler] [frontend.handler.whiteboard :as whiteboard-handler] - [frontend.hooks :as hooks] [frontend.mixins :as mixins] [frontend.modules.shortcut.core :as shortcut] [frontend.modules.shortcut.utils :as shortcut-utils] @@ -36,6 +35,7 @@ [logseq.common.util.block-ref :as block-ref] [logseq.db :as ldb] [logseq.graph-parser.text :as text] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [promesa.core :as p] [rum.core :as rum])) diff --git a/src/main/frontend/components/cmdk/list_item.cljs b/src/main/frontend/components/cmdk/list_item.cljs index 64cf853d3a..a78e1517c0 100644 --- a/src/main/frontend/components/cmdk/list_item.cljs +++ b/src/main/frontend/components/cmdk/list_item.cljs @@ -2,8 +2,8 @@ (:require ["remove-accents" :as remove-accents] [clojure.string :as string] - [frontend.hooks :as hooks] [goog.string :as gstring] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [rum.core :as rum])) diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index d25cc45dac..c884234aa4 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -32,7 +32,6 @@ [frontend.handler.route :as route-handler] [frontend.handler.user :as user-handler] [frontend.handler.whiteboard :as whiteboard-handler] - [frontend.hooks :as hooks] [frontend.mixins :as mixins] [frontend.mobile.action-bar :as action-bar] [frontend.mobile.footer :as footer] @@ -53,6 +52,7 @@ [logseq.common.util.namespace :as ns-util] [logseq.db :as ldb] [logseq.shui.dialog.core :as shui-dialog] + [logseq.shui.hooks :as hooks] [logseq.shui.popup.core :as shui-popup] [logseq.shui.toaster.core :as shui-toaster] [logseq.shui.ui :as shui] diff --git a/src/main/frontend/components/content.cljs b/src/main/frontend/components/content.cljs index 350f6974f0..1b9a5c96a2 100644 --- a/src/main/frontend/components/content.cljs +++ b/src/main/frontend/components/content.cljs @@ -81,7 +81,8 @@ (let [block-uuids (state/get-selection-block-ids)] (shui/popup-hide!) (shui/dialog-open! - #(export/export-blocks block-uuids {:whiteboard? false}))))} + #(export/export-blocks block-uuids {:whiteboard? false + :export-type :selected-nodes}))))} (t :content/copy-export-as)) (shui/dropdown-menu-item @@ -260,7 +261,8 @@ {:key "Copy as" :on-click (fn [_] (shui/dialog-open! - #(export/export-blocks [block-id] {:whiteboard? false})))} + #(export/export-blocks [block-id] {:whiteboard? false + :export-type :block})))} (t :content/copy-export-as)) (when-not property-default-value? diff --git a/src/main/frontend/components/dnd.cljs b/src/main/frontend/components/dnd.cljs index 99fad02201..42936ba33c 100644 --- a/src/main/frontend/components/dnd.cljs +++ b/src/main/frontend/components/dnd.cljs @@ -3,9 +3,9 @@ ["@dnd-kit/sortable" :refer [useSortable arrayMove SortableContext verticalListSortingStrategy horizontalListSortingStrategy] :as sortable] ["@dnd-kit/utilities" :refer [CSS]] [cljs-bean.core :as bean] - [frontend.hooks :as hooks] [frontend.rum :as r] [frontend.state :as state] + [logseq.shui.hooks :as hooks] [rum.core :as rum])) (def dnd-context (r/adapt-class DndContext)) diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index ce4bb60af8..a66d50598d 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -18,7 +18,6 @@ [frontend.handler.paste :as paste-handler] [frontend.handler.property.util :as pu] [frontend.handler.search :as search-handler] - [frontend.hooks :as hooks] [frontend.mixins :as mixins] [frontend.search :refer [fuzzy-search]] [frontend.state :as state] @@ -33,6 +32,7 @@ [logseq.db :as ldb] [logseq.db.frontend.class :as db-class] [logseq.graph-parser.property :as gp-property] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [promesa.core :as p] [react-draggable] diff --git a/src/main/frontend/components/export.cljs b/src/main/frontend/components/export.cljs index 44be905c80..a5bd6b36bc 100644 --- a/src/main/frontend/components/export.cljs +++ b/src/main/frontend/components/export.cljs @@ -1,6 +1,7 @@ (ns frontend.components.export (:require ["/frontend/utils" :as utils] [cljs-time.core :as t] + [cljs.pprint :as pprint] [frontend.config :as config] [frontend.context.i18n :refer [t]] [frontend.db :as db] @@ -160,6 +161,20 @@ current-repo top-level-ids {:remove-options text-remove-options :other-options text-other-options}) ""))) +(defn- > edn-str + (p/let [result (state/> pull-data js/encodeURIComponent (str "data:text/edn;charset=utf-8,")) filename (file-name repo :edn)] diff --git a/src/main/frontend/mobile/graph_picker.cljs b/src/main/frontend/mobile/graph_picker.cljs index bf6842fc63..d053fb833b 100644 --- a/src/main/frontend/mobile/graph_picker.cljs +++ b/src/main/frontend/mobile/graph_picker.cljs @@ -6,13 +6,13 @@ [frontend.handler.file-based.nfs :as nfs-handler] [frontend.handler.notification :as notification] [frontend.handler.page :as page-handler] - [frontend.hooks :as hooks] [frontend.mobile.util :as mobile-util] [frontend.modules.shortcut.core :as shortcut] [frontend.state :as state] [frontend.ui :as ui] [frontend.util :as util] [logseq.common.path :as path] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [promesa.core :as p] [rum.core :as rum])) diff --git a/src/main/frontend/rum.cljs b/src/main/frontend/rum.cljs index 6708182632..ca79f07187 100644 --- a/src/main/frontend/rum.cljs +++ b/src/main/frontend/rum.cljs @@ -5,7 +5,7 @@ [clojure.string :as string] [clojure.walk :as w] [daiquiri.interpreter :as interpreter] - [frontend.hooks :as hooks] + [logseq.shui.hooks :as hooks] [rum.core :refer [use-state] :as rum])) ;; copy from https://github.com/priornix/antizer/blob/35ba264cf48b84e6597743e28b3570d8aa473e74/src/antizer/core.cljs diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index cda45bf179..caad50c637 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -12,7 +12,6 @@ [frontend.db.conn-state :as db-conn-state] [frontend.db.transact :as db-transact] [frontend.flows :as flows] - [frontend.hooks :as hooks] [frontend.mobile.util :as mobile-util] [frontend.spec.storage :as storage-spec] [frontend.storage :as storage] @@ -25,6 +24,7 @@ [logseq.db.frontend.entity-plus :as entity-plus] [logseq.db.sqlite.util :as sqlite-util] [logseq.shui.dialog.core :as shui-dialog] + [logseq.shui.hooks :as hooks] [logseq.shui.ui :as shui] [missionary.core :as m] [promesa.core :as p] diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 2935d50436..12498fb8e4 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -18,7 +18,6 @@ [frontend.db-mixins :as db-mixins] [frontend.handler.notification :as notification] [frontend.handler.plugin :as plugin-handler] - [frontend.hooks :as hooks] [frontend.mixins :as mixins] [frontend.mobile.util :as mobile-util] [frontend.modules.shortcut.config :as shortcut-config] @@ -32,6 +31,7 @@ [goog.dom :as gdom] [goog.object :as gobj] [lambdaisland.glogi :as log] + [logseq.shui.hooks :as hooks] [logseq.shui.icon.v2 :as shui.icon.v2] [logseq.shui.popup.core :as shui-popup] [logseq.shui.ui :as shui] diff --git a/src/main/frontend/worker/db_worker.cljs b/src/main/frontend/worker/db_worker.cljs index ca954517a9..693e14b014 100644 --- a/src/main/frontend/worker/db_worker.cljs +++ b/src/main/frontend/worker/db_worker.cljs @@ -743,7 +743,8 @@ (js/console.error "export-edn error: " e) (worker-util/post-message :notification ["An unexpected error occurred during export. See the javascript console for details." - :error]))))) + :error]) + :export-edn-error)))) (def-thread-api :thread-api/get-view-data [repo view-id option] diff --git a/yarn.lock b/yarn.lock index cba5b8e23a..ac6b528b0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -240,25 +240,48 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@capacitor/action-sheet@^5.0.7": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@capacitor/action-sheet/-/action-sheet-5.0.7.tgz#4808af8c483a85f58c7fffdea76f8d374883e3a0" - integrity sha512-8q8fYYy9dwLi4eiDiYq+ys/uOm9C2YpjfAnlG7fYdha8QNpaz2314jR+dxsJO423zYB2Wag9NXlupHpXeGdGOA== +"@capacitor/action-sheet@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/action-sheet/-/action-sheet-7.0.1.tgz#8b6fd171375d1e4d9392ee9968ef4152309dcaa7" + integrity sha512-0ROMy6S62B/Ci9nZ7CRxhkK2LS0JBmhN+sxOXQOtntd2WHKW7+8J+VAtu8vk0LgvTjj7SjzJnicYC75KUjwLWw== -"@capacitor/android@^5.0.0": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@capacitor/android/-/android-5.4.1.tgz#5b0445202ca5e48fcb79d0c88e4403acc32504bc" - integrity sha512-25k/GyIly/8xKQo0EO6eIvJStpVWsBPyYh9Eiv+Or9DCz9iuVlGZY3vui+zjFhfHQ5f9Uwywa8B+thOGWU8f6g== +"@capacitor/android@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@capacitor/android/-/android-7.2.0.tgz#f30e313315ab92c500bd57d9f0c4716a46b42f40" + integrity sha512-zdhEy3jZPG5Toe/pGzKtDgIiBGywjaoEuQWnGVjBYPlSAEUtAhpZ2At7V0SCb26yluAuzrAUV0Ue+LQeEtHwFQ== -"@capacitor/app@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/app/-/app-5.0.6.tgz#2ee02551115fd2e92dc7e81bc30a6c6fa78efa66" - integrity sha512-6ZXVdnNmaYILasC/RjQw+yfTmq2ZO7Q3v5lFcDVfq3PFGnybyYQh+RstBrYri+376OmXOXxBD7E6UxBhrMzXGA== +"@capacitor/app@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/app/-/app-7.0.1.tgz#0d0709fb4dde5046c24853f2d6b77a7ea411f748" + integrity sha512-ArlVZAAla4MwQoKh26x2AaTDOBh5Vhp1VhMKR3RwqZSsZnazKTFGNrPbr9Ez5r1knnEDfApyjwp1uZnXK1WTYQ== -"@capacitor/camera@^5.0.0": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@capacitor/camera/-/camera-5.0.7.tgz#42f60168d731fc521df797aacc7cda703b7ac2b1" - integrity sha512-1Wk3Dk0UhhNHdBB07UrPvUOSL7Wi5gFZRyLY1LZL2awt34iqy2cnajtfJplFmEZHk8lD0i7NAl3HbkWm4td4OQ== +"@capacitor/camera@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/camera/-/camera-7.0.1.tgz#bcbd1c05cce648fa54b844bf7a6745854cae6ba4" + integrity sha512-gDUFsYlhMra5VVOa4iJV6+MQRhp3VXpTLQY4JDATj7UvoZ8Hv4DG8qplPL9ufUFNoR3QbDDnf8+gbQOsKdkDjg== + +"@capacitor/cli@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@capacitor/cli/-/cli-7.2.0.tgz#ea279f14e575b059edb7fe8dc64a8e3379088616" + integrity sha512-RNW9vtYYYSDmOdguYBSW0VpRnG/d6lGydlc9DLrJ7qbSPxFrotTz9IjkM48O+SruUma61DyuSqJttdbay2xSxg== + dependencies: + "@ionic/cli-framework-output" "^2.2.8" + "@ionic/utils-subprocess" "^3.0.1" + "@ionic/utils-terminal" "^2.3.5" + commander "^12.1.0" + debug "^4.4.0" + env-paths "^2.2.0" + fs-extra "^11.2.0" + kleur "^4.1.5" + native-run "^2.0.1" + open "^8.4.0" + plist "^3.1.0" + prompts "^2.4.2" + rimraf "^6.0.1" + semver "^7.6.3" + tar "^6.1.11" + tslib "^2.8.1" + xml2js "^0.6.2" "@capacitor/cli@^5.0.0": version "5.4.1" @@ -283,10 +306,17 @@ tslib "^2.4.0" xml2js "^0.5.0" -"@capacitor/clipboard@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/clipboard/-/clipboard-5.0.6.tgz#abc0101fb1b2780e829542b2d31f9eb1480b8ee8" - integrity sha512-VsokRAn+0HVWj6riSRdspczEfqFoHbrhS/XRhGoEPsj0uvYPSufy0Kb2dpnSqkeeElhh2Jvn8jmVAzII2XeR9w== +"@capacitor/clipboard@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/clipboard/-/clipboard-7.0.1.tgz#159fefa56b7d23632e9d08c9efd9cbd75a868b21" + integrity sha512-n4XEHma7apLOYvyeaR9S5u3uGzDYG7WeQxmtZlwP01HneIzMnusVgw4Im6I+pMBcoUN9TfVdf6eqKph97B1bAw== + +"@capacitor/core@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@capacitor/core/-/core-7.2.0.tgz#fdd1c5d2fbfa257887ce6065f66151a51f0e6d1b" + integrity sha512-2zCnA6RJeZ9ec4470o8QMZEQTWpekw9FNoqm5TLc10jeCrhvHVI8MPgxdZVc3mOdFlyieYu4AS1fNxSqbS57Pw== + dependencies: + tslib "^2.1.0" "@capacitor/core@^5.0.0": version "5.4.1" @@ -295,50 +325,50 @@ dependencies: tslib "^2.1.0" -"@capacitor/filesystem@^5.0.0": - version "5.1.4" - resolved "https://registry.yarnpkg.com/@capacitor/filesystem/-/filesystem-5.1.4.tgz#6e3278f4c47c72416d586367889736b576113ef5" - integrity sha512-10EM1KvFMs+pTzxkcflspzxBWcX9sOnS9nTP5Afjr5hn4OxLrwTFySw2Z12Uv6jdN4OnhY3jXtDKXPljXvXILg== +"@capacitor/filesystem@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/filesystem/-/filesystem-7.0.1.tgz#b0518d781f7640e936f529b80a59724e221d0471" + integrity sha512-dxuKNLFoUejm7tBKkQPs1j7+BLpDh5JKPSVu7nT8jgCbA/KXt5FoCLiepfkjWkYfq60X0JNFzGnIquc5FPOLzQ== -"@capacitor/haptics@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/haptics/-/haptics-5.0.6.tgz#c22fd6acbc62cbdff39279ded687c418f2c89a5a" - integrity sha512-UrMcR7p2X10ql4VLlowUuH/VckTeu0lj+RQpekxox14uxDmu5AGIFDK/iDTi8W6QZkxTJRZK6sbCjgwYgNJ7Pw== +"@capacitor/haptics@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/haptics/-/haptics-7.0.1.tgz#8e992837e87c0b65a4a38430944762d1e2fce6dc" + integrity sha512-ewZmspE5krgDUj5ZvUDcfNZvgerAIr+3bDSk6DLzyvBZ/dYmr/tMLu5H6WtYaaKYZJ32aZAudGpIal5epDyBYA== -"@capacitor/ios@^5.0.0": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@capacitor/ios/-/ios-5.4.1.tgz#79c1620ac7b57dc1ea85653ad1e5a32e8ec7dbea" - integrity sha512-s5djQEX1HFM6u4gQlWz7DUWG7ma0d3AwwnjbSbCh25aYEt40Dbei0TjzlKrfU6b3nUbyVVAZJBJgMuk7Bq59qA== +"@capacitor/ios@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@capacitor/ios/-/ios-7.2.0.tgz#c3d9435582e5267b57085229e5678d1d53b15b5a" + integrity sha512-MQgRZcXZpbpjN83bjkGrzQd7s3XeHBZplmWf38/msF/siMGJKLrXNmNzmmPIWA5Xpi/aH6UoJFk1wXuU2U+zMg== -"@capacitor/keyboard@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/keyboard/-/keyboard-5.0.6.tgz#04400e71b677abf9f1fc1ceaffd1211e7d864319" - integrity sha512-9GewAa/y2Hwkdw/Be8MTdiAjrFZ7TPDKpR44M0Y/0QMnK+mBbgzcoZ/UkuumWv6e2F1IAI+VY5eYVQHDeZcRoA== +"@capacitor/keyboard@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/keyboard/-/keyboard-7.0.1.tgz#edf212528cd1587494ceb1d260868c1a9540aed1" + integrity sha512-Gi064vOARMac+x9/DmEFeywN9oAETMf3OYsMuYm9gA8SvdsDJ3QJqMoFnSEIORYXe21Jzt2SIEdLlpT65P/b2g== -"@capacitor/share@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/share/-/share-5.0.6.tgz#76d2f6f13d1596999c49a0d99d21e7a63b8ecfef" - integrity sha512-/dVOW7kcuuD7hWB9Z1drArIpEk+5JCoMnMrAs2c7CLp3q5PeaXNJjTkGr6RJ1OtMhsHyXc6DAFwQ4frFkmZsgw== +"@capacitor/share@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/share/-/share-7.0.1.tgz#1d1e6d312504703c1f34fa0de94bed14af4bcbf8" + integrity sha512-7GAtWrb2inEWohC8E7mx38qAX6D9yqPDDnUtJaZ8JRpo15jjFRS40Cx388M8h4NlBWjV5NU3qf1sHXnyOBSJ5g== -"@capacitor/splash-screen@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/splash-screen/-/splash-screen-5.0.6.tgz#d29320de49cc68add59e17fecb64aa2f1a08447f" - integrity sha512-9B8wSm89D+LlshFw8B+mjPU8pJNf1WOx2mkMjMvcH0/EqxNaE+ZaO8lPCX+9WvWSEZs3O3l11qiSnOFHeK0t9A== +"@capacitor/splash-screen@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/splash-screen/-/splash-screen-7.0.1.tgz#ea70d39c4346db4558f749eeb2d3ac2f5c34c550" + integrity sha512-Nbqw9bEIe7uHj/HOT81mf4jT6uK1YykozpQw/uIKQDueMg6RJYaJK2/TMajIOohLk8fJF4TYIc1i9nGjNLnfGg== -"@capacitor/status-bar@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@capacitor/status-bar/-/status-bar-5.0.6.tgz#281568a7f7aeacf80777702cb9947c29dc32685c" - integrity sha512-7od8CxsBnot1XMK3IeOkproFL4hgoKoWAc3pwUvmDOkQsXoxwQm4SR9mLwQavv1XfxtHbFV9Ukd7FwMxOPSViw== +"@capacitor/status-bar@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capacitor/status-bar/-/status-bar-7.0.1.tgz#6bd3769ef35158c961ff2a6b571c03e9bce55809" + integrity sha512-iDv3mXYo9CdxYRVwt3/pRyuk25p7Sn4GfaS/zMZyVIqTzsvKLCIIH3GdKK+ta+nsNcAVpCw/t5jFEBt1D18ctA== -"@capawesome/capacitor-background-task@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@capawesome/capacitor-background-task/-/capacitor-background-task-5.0.0.tgz#eb985131065df59f95ffa1e9ef3abf0f3573a35f" - integrity sha512-puZ/MaNNlIMmwojuMX5Z5rqWJFHjvpdgMB+xGe/QXG+IMrcY5eMtR3l/NLGtbH8izwid1dAsxzBACX5RGHdVzA== +"@capawesome/capacitor-background-task@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@capawesome/capacitor-background-task/-/capacitor-background-task-7.0.1.tgz#5531717de4cea255156c7f83fd4bf0f1e472c534" + integrity sha512-ILkJ0bCOLperUc+fezzhpiH3Bfnr/318TI9XSrPU/vwvBXjMH7p7xYxKtjDA4VpJfbVh1cHmWLtRSWIk2wUglg== -"@capgo/capacitor-navigation-bar@^6.0.0": - version "6.0.6" - resolved "https://registry.yarnpkg.com/@capgo/capacitor-navigation-bar/-/capacitor-navigation-bar-6.0.6.tgz#e2c8d346298abf470d5a4583059fca34d4d4ff94" - integrity sha512-X0w0BFB07vyb2BipWaok8itPgn6inR5zuZIJgZGhsJXYmmyVAwsTbSRZZluIrDbMzd3LHD4bfzbzFzU02tfG3g== +"@capgo/capacitor-navigation-bar@7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@capgo/capacitor-navigation-bar/-/capacitor-navigation-bar-7.1.2.tgz#d017f22007e6e848c6a94aa38d70546b08d95473" + integrity sha512-lganepu29pay05+clCE41yEICE34xDzB61dmvtwWxZlWccvlu+XWbS8WnMSncvIotqBUmU1owfivG+usfrp4CA== "@colors/colors@1.5.0": version "1.5.0" @@ -430,6 +460,15 @@ debug "^4.0.0" tslib "^2.0.1" +"@ionic/cli-framework-output@^2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz#29d541acc7773a6aaceec5f3b079937fbcef5402" + integrity sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g== + dependencies: + "@ionic/utils-terminal" "2.3.5" + debug "^4.0.0" + tslib "^2.0.1" + "@ionic/utils-array@2.1.6": version "2.1.6" resolved "https://registry.yarnpkg.com/@ionic/utils-array/-/utils-array-2.1.6.tgz#eee863be945ee1a28b9a10ff16fdea776fa18c22" @@ -438,7 +477,7 @@ debug "^4.0.0" tslib "^2.0.1" -"@ionic/utils-fs@3.1.7", "@ionic/utils-fs@^3.1.6": +"@ionic/utils-fs@3.1.7", "@ionic/utils-fs@^3.1.6", "@ionic/utils-fs@^3.1.7": version "3.1.7" resolved "https://registry.yarnpkg.com/@ionic/utils-fs/-/utils-fs-3.1.7.tgz#e0d41225272c346846867e88a0b84b1a4ee9d9c9" integrity sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA== @@ -468,6 +507,18 @@ tree-kill "^1.2.2" tslib "^2.0.1" +"@ionic/utils-process@2.1.12": + version "2.1.12" + resolved "https://registry.yarnpkg.com/@ionic/utils-process/-/utils-process-2.1.12.tgz#17b05d66201859fe11f53b47be22b85aa90b9556" + integrity sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg== + dependencies: + "@ionic/utils-object" "2.1.6" + "@ionic/utils-terminal" "2.3.5" + debug "^4.0.0" + signal-exit "^3.0.3" + tree-kill "^1.2.2" + tslib "^2.0.1" + "@ionic/utils-stream@3.1.6": version "3.1.6" resolved "https://registry.yarnpkg.com/@ionic/utils-stream/-/utils-stream-3.1.6.tgz#7c2fdcf4d9e621e8b2260e2fee2471825a4e214f" @@ -476,6 +527,14 @@ debug "^4.0.0" tslib "^2.0.1" +"@ionic/utils-stream@3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@ionic/utils-stream/-/utils-stream-3.1.7.tgz#224f8c99012aa54e7dbf59950de903b6a61cd811" + integrity sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w== + dependencies: + debug "^4.0.0" + tslib "^2.0.1" + "@ionic/utils-subprocess@^2.1.11": version "2.1.12" resolved "https://registry.yarnpkg.com/@ionic/utils-subprocess/-/utils-subprocess-2.1.12.tgz#08ef08a13928aa97b9156b153e39fe5ff9c1e661" @@ -490,6 +549,20 @@ debug "^4.0.0" tslib "^2.0.1" +"@ionic/utils-subprocess@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz#561608fecf432c28fd80f94c1563dc0d092581b7" + integrity sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A== + dependencies: + "@ionic/utils-array" "2.1.6" + "@ionic/utils-fs" "3.1.7" + "@ionic/utils-process" "2.1.12" + "@ionic/utils-stream" "3.1.7" + "@ionic/utils-terminal" "2.3.5" + cross-spawn "^7.0.3" + debug "^4.0.0" + tslib "^2.0.1" + "@ionic/utils-terminal@2.3.4", "@ionic/utils-terminal@^2.3.3": version "2.3.4" resolved "https://registry.yarnpkg.com/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz#e40c44b676265ed6a07a68407bda6e135870f879" @@ -505,6 +578,33 @@ untildify "^4.0.0" wrap-ansi "^7.0.0" +"@ionic/utils-terminal@2.3.5", "@ionic/utils-terminal@^2.3.4", "@ionic/utils-terminal@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz#a48465f40496ee8f29c6d92e4506d5f19762ac3c" + integrity sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A== + dependencies: + "@types/slice-ansi" "^4.0.0" + debug "^4.0.0" + signal-exit "^3.0.3" + slice-ansi "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + tslib "^2.0.1" + untildify "^4.0.0" + wrap-ansi "^7.0.0" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@isomorphic-git/idb-keyval@3.3.2": version "3.3.2" resolved "https://registry.yarnpkg.com/@isomorphic-git/idb-keyval/-/idb-keyval-3.3.2.tgz#c0509a6c5987d8a62efb3e47f2815bcc5eda2489" @@ -1246,6 +1346,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1260,6 +1365,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -2210,6 +2320,11 @@ comlink@^4.4.1: resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.4.1.tgz#e568b8e86410b809e8600eb2cf40c189371ef981" integrity sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q== +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -2390,6 +2505,15 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -2570,6 +2694,13 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, d dependencies: ms "2.1.2" +debug@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: version "4.3.6" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" @@ -2878,6 +3009,11 @@ earcut@^2.2.2: resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a" integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2943,6 +3079,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -3519,6 +3660,14 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + fraction.js@^4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" @@ -3550,6 +3699,15 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^11.2.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" + integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -3784,6 +3942,18 @@ glob@9.0.0: minipass "^4.2.4" path-scurry "^1.5.0" +glob@^11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.1.tgz#1c3aef9a59d680e611b53dcd24bb8639cef064d9" + integrity sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw== + dependencies: + foreground-child "^3.1.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.7: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -4300,6 +4470,11 @@ ini@^3.0.1: resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== +ini@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.3.tgz#4c359675a6071a46985eb39b14e4a2c0ec98a795" + integrity sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg== + inter-ui@^3.19.3: version "3.19.3" resolved "https://registry.yarnpkg.com/inter-ui/-/inter-ui-3.19.3.tgz#cf4b4b6d30de8d5463e2462588654b325206488c" @@ -4765,6 +4940,13 @@ istextorbinary@^3.0.0: binaryextensions "^2.2.0" textextensions "^3.2.0" +jackspeak@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.1.0.tgz#c489c079f2b636dc4cbe9b0312a13ff1282e561b" + integrity sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw== + dependencies: + "@isaacs/cliui" "^8.0.2" + jiti@^1.19.1: version "1.21.0" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" @@ -4941,7 +5123,7 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -kleur@^4.1.4: +kleur@^4.1.4, kleur@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== @@ -5140,6 +5322,11 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117" + integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -5413,6 +5600,13 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -5470,6 +5664,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -5515,6 +5714,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + mute-stdout@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" @@ -5578,6 +5782,23 @@ native-run@^1.7.3: tslib "^2.4.0" yauzl "^2.10.0" +native-run@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/native-run/-/native-run-2.0.1.tgz#a9b213c32824b007cbdd0279e0edd3c24bcc2f7a" + integrity sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w== + dependencies: + "@ionic/utils-fs" "^3.1.7" + "@ionic/utils-terminal" "^2.3.4" + bplist-parser "^0.3.2" + debug "^4.3.4" + elementtree "^0.1.7" + ini "^4.1.1" + plist "^3.1.0" + split2 "^4.2.0" + through2 "^4.0.2" + tslib "^2.6.2" + yauzl "^2.10.0" + negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -5944,6 +6165,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -6118,6 +6344,14 @@ path-scurry@^1.6.1: lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -6334,7 +6568,7 @@ playwright@1.51.0, playwright@=1.51.0: optionalDependencies: fsevents "2.3.2" -plist@^3.0.5, plist@^3.0.6: +plist@^3.0.5, plist@^3.0.6, plist@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ== @@ -6943,14 +7177,13 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -react-dom@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +react-dom@18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.2" react-draggable@3.x: version "3.3.2" @@ -7038,13 +7271,12 @@ react-virtuoso@4.12.5: resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.12.5.tgz#cf92efc2527e56d6df1d4d63c6e4dd3fac5a4030" integrity sha512-YeCbRRsC9CLf0buD0Rct7WsDbzf+yBU1wGbo05/XjbcN2nJuhgh040m3y3+6HVogTZxEqVm45ac9Fpae4/MxRQ== -react@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" read-cache@^1.0.0: version "1.0.0" @@ -7387,6 +7619,14 @@ rimraf@^4.4.1: dependencies: glob "^9.2.0" +rimraf@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.0.1.tgz#ffb8ad8844dd60332ab15f52bc104bc3ed71ea4e" + integrity sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A== + dependencies: + glob "^11.0.0" + package-json-from-dist "^1.0.0" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -7472,13 +7712,12 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" semver-compare@^1.0.0: version "1.0.0" @@ -7516,6 +7755,11 @@ semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: dependencies: lru-cache "^6.0.0" +semver@^7.6.3: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + send-intent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/send-intent/-/send-intent-5.0.0.tgz#95d00455a7db4d95d9f79f8203698e96760c7408" @@ -7652,6 +7896,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -7854,7 +8103,7 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split2@^4.1.0: +split2@^4.1.0, split2@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== @@ -7935,6 +8184,15 @@ strictdom@^1.0.1: resolved "https://registry.yarnpkg.com/strictdom/-/strictdom-1.0.1.tgz#189de91649f73d44d59b8432efa68ef9d2659460" integrity sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -7961,6 +8219,15 @@ string-width@^2.0.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.padend@^3.0.0: version "3.1.5" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz#311ef3a4e3c557dd999cdf88fbdde223f2ac0f95" @@ -8011,6 +8278,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -8032,6 +8306,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -8474,6 +8755,11 @@ tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.6.2, tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -8974,6 +9260,15 @@ wide-align@^1.1.2: dependencies: string-width "^1.0.2 || 2 || 3 || 4" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -8991,6 +9286,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -9024,6 +9328,14 @@ xml2js@^0.5.0: sax ">=0.6.0" xmlbuilder "~11.0.0" +xml2js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" + integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@^15.1.1: version "15.1.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"