diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 2b4353352..c213af9e6 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -150,23 +150,23 @@ :hide? true :view-context :page :public? true}} - :logseq.property/table-sorting {:schema + :logseq.property.table/sorting {:schema {:type :coll :hide? true :public? false}} - :logseq.property/table-filters {:schema + :logseq.property.table/filters {:schema {:type :coll :hide? true :public? false}} - :logseq.property/table-hidden-columns {:schema + :logseq.property.table/hidden-columns {:schema {:type :keyword :cardinality :many :hide? true :public? false}} - :logseq.property/table-ordered-columns {:schema + :logseq.property.table/ordered-columns {:schema {:type :coll :hide? true :public? false}} @@ -201,7 +201,7 @@ (def logseq-property-namespaces #{"logseq.property" "logseq.property.tldraw" "logseq.property.pdf" "logseq.task" - "logseq.property.linked-references" "logseq.property.asset"}) + "logseq.property.linked-references" "logseq.property.asset" "logseq.property.table"}) (defn logseq-property? "Determines if keyword is a logseq property" diff --git a/deps/db/src/logseq/db/frontend/schema.cljs b/deps/db/src/logseq/db/frontend/schema.cljs index 575aaed53..3e02847ad 100644 --- a/deps/db/src/logseq/db/frontend/schema.cljs +++ b/deps/db/src/logseq/db/frontend/schema.cljs @@ -2,7 +2,7 @@ "Main datascript schemas for the Logseq app" (:require [clojure.set :as set])) -(def version 10) +(def version 11) ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name". (def ^:large-vars/data-var schema {:db/ident {:db/unique :db.unique/identity} diff --git a/deps/db/src/logseq/db/sqlite/util.cljs b/deps/db/src/logseq/db/sqlite/util.cljs index 879fffd51..f0adb8ed9 100644 --- a/deps/db/src/logseq/db/sqlite/util.cljs +++ b/deps/db/src/logseq/db/sqlite/util.cljs @@ -107,7 +107,7 @@ (assoc :db/valueType :db.type/ref)))))) (defn build-new-class - "Build a standard new class so that it is is consistent across contexts" + "Build a standard new class so that it is consistent across contexts" [block] {:pre [(qualified-keyword? (:db/ident block))]} (block-with-timestamps diff --git a/scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs b/scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs index dec697402..b2c9f8929 100644 --- a/scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs +++ b/scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs @@ -11,7 +11,6 @@ type logseq doesnt' support yet * schema.org assumes no cardinality. For now, only :node properties are given a :cardinality :many" (:require [logseq.outliner.cli :as outliner-cli] - [logseq.common.util :as common-util] [logseq.db.frontend.property :as db-property] [clojure.string :as string] [clojure.edn :as edn] @@ -77,8 +76,8 @@ {"schema:Integer" :number "schema:Float" :number "schema:Number" :number - "schema:Text_Class" :default - "schema:URL_Class" :url + "schema:Text" :default + "schema:URL" :url "schema:Boolean" :checkbox "schema:Date" :date}) @@ -158,11 +157,11 @@ (defn- get-vector-conflicts "Given a seq of tuples returns a seq of tuples that conflict i.e. their first element - has a case insensitive conflict/duplicate with another. An example conflict: - [[\"schema:businessFunction\" :property] [\"schema:BusinessFunction\" :class]]" + has a case sensitive conflict/duplicate with another. An example conflict: + [[\"schema:status\" :property] [\"schema:status\" :node]]" [tuples-seq] (->> tuples-seq - (group-by (comp common-util/page-name-sanity-lc first)) + (group-by first) (filter #(> (count (val %)) 1)) vals)) @@ -190,7 +189,8 @@ (if verbose (println "Renaming the following properties because they have names that conflict with Logseq's built in pages" (keys renamed-properties) "\n") - (println "Renaming" (count renamed-properties) "properties due to page name conflicts")) + (when (pos? (count renamed-properties)) + (println "Renaming" (count renamed-properties) "properties due to page name conflicts"))) renamed-properties)) (defn- detect-id-conflicts-and-get-renamed-classes @@ -219,7 +219,8 @@ (if verbose (println "Renaming the following classes because they have property names that conflict with Logseq's case insensitive :block/name:" (keys renamed-classes) "\n") - (println "Renaming" (count renamed-classes) "classes due to page name conflicts")) + (when (pos? (count renamed-classes)) + (println "Renaming" (count renamed-classes) "classes due to page name conflicts"))) renamed-classes)) (defn- get-all-properties [schema-data {:keys [verbose]}] @@ -308,7 +309,7 @@ select-class-ids (if (:subset options) ["schema:Person" "schema:CreativeWorkSeries" "schema:Organization" - "schema:Movie" "schema:CreativeWork" "schema:Thing"] + "schema:Movie" "schema:CreativeWork" "schema:Thing" "schema:Comment"] (keys class-map)) class-to-properties (get-class-to-properties select-class-ids all-properties) select-properties (set (mapcat val class-to-properties)) diff --git a/src/main/frontend/common.css b/src/main/frontend/common.css index a4752c2be..df2b935ac 100644 --- a/src/main/frontend/common.css +++ b/src/main/frontend/common.css @@ -384,7 +384,7 @@ button.menu:focus { .menu-link { @apply text-popover-foreground/75 select-none hover:text-popover-foreground/100; - @apply text-sm px-2 py-1.5 mx-1 hover:rounded transition-opacity duration-150; + @apply text-sm px-2 py-1.5 hover:rounded transition-opacity duration-150; } .menu-separator { diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index 8c324284b..98273464b 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -204,6 +204,24 @@ &.as-heading { @apply flex flex-1; + + h1& { + .ui__icon.ti svg { + @apply w-8 h-7; + } + } + + h2& { + .ui__icon.ti svg { + @apply w-7 h-6; + } + } + + h3& { + .ui__icon.ti svg { + @apply w-5 h-5; + } + } } &:has(.dsl-query), &:has(.embed-page) { diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index a01c304bb..fd1b5d577 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -545,7 +545,7 @@ {:drop (fn [_e files] (when-let [id (state/get-edit-input-id)] (let [format (:block/format (state/get-edit-block))] - (editor-handler/upload-asset id files format editor-handler/*asset-uploading? true))))}) + (editor-handler/upload-asset! id files format editor-handler/*asset-uploading? true))))}) (common-handler/listen-to-scroll! element) (when (:margin-less-pages? (first (:rum/args state))) ;; makes sure full screen pages displaying without scrollbar (set! (.. element -scrollTop) 0))) @@ -555,10 +555,10 @@ (dnd/unsubscribe! el :upload-files)) state)} [{:keys [route-match margin-less-pages? route-name indexeddb-support? db-restoring? main-content show-action-bar? show-recording-bar?]}] - (let [left-sidebar-open? (state/sub :ui/left-sidebar-open?) + (let [left-sidebar-open? (state/sub :ui/left-sidebar-open?) onboarding-and-home? (and (or (nil? (state/get-current-repo)) (config/demo-graph?)) - (not config/publishing?) - (= :home route-name)) + (not config/publishing?) + (= :home route-name)) margin-less-pages? (or (and (mobile-util/native-platform?) onboarding-and-home?) margin-less-pages?)] [:div#main-container.cp__sidebar-main-layout.flex-1.flex {:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])} diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index a5bfa84a2..397c97531 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -482,124 +482,6 @@ (util/stop e) (on-submit command @input-value pos)))]))))) -(rum/defc absolute-modal < rum/static - [cp modal-name set-default-width? {:keys [top left rect]}] - (let [MAX-HEIGHT 700 - MAX-HEIGHT' 600 - MAX-WIDTH 600 - SM-MAX-WIDTH 300 - Y-BOUNDARY-HEIGHT 150 - vw-width js/window.innerWidth - vw-height js/window.innerHeight - vw-max-width (- vw-width (:left rect)) - vw-max-height (- vw-height (:top rect)) - vw-max-height' (:top rect) - sm? (< vw-width 415) - max-height (min (- vw-max-height 20) MAX-HEIGHT) - max-height' (min (- vw-max-height' 70) MAX-HEIGHT') - max-width (if sm? SM-MAX-WIDTH (min (max 400 (/ vw-max-width 2)) MAX-WIDTH)) - offset-top 24 - to-max-height (cond-> (if (and (seq rect) (> vw-height max-height)) - (let [delta-height (- vw-height (+ (:top rect) top offset-top))] - (if (< delta-height max-height) - (- (max (* 2 offset-top) delta-height) 16) - max-height)) - max-height) - - (= modal-name "commands") - (min 500)) - right-sidebar? (:ui/sidebar-open? @state/state) - editing-key (state/get-edit-input-id) - *el (rum/use-ref nil) - y-overflow-vh? (or (< to-max-height Y-BOUNDARY-HEIGHT) - (> (- max-height' to-max-height) Y-BOUNDARY-HEIGHT)) - to-max-height (if y-overflow-vh? max-height' to-max-height) - pos-rect (when (and (seq rect) editing-key) - (:rect (cursor/get-caret-pos (state/get-input)))) - y-diff (when pos-rect (- (:height pos-rect) (:height rect))) - style (merge - {:top (+ top offset-top (if (int? y-diff) y-diff 0)) - :max-height to-max-height - :max-width 700 - ;; TODO: auto responsive fixed size - :width "fit-content" - :z-index 11} - (when set-default-width? - {:width max-width}) - (if (<= vw-max-width (+ left (if set-default-width? max-width 500))) - {:right 0} - {:left 0}))] - - (rum/use-effect! - (fn [] - (when-let [^js/HTMLElement cnt - (and right-sidebar? editing-key - (js/document.querySelector "#main-content-container"))] - (when (.contains cnt (js/document.querySelector (str "#" editing-key))) - (let [el (rum/deref *el) - ofx (- (.-scrollWidth cnt) (.-clientWidth cnt))] - (when (> ofx 0) - (set! (.-transform (.-style el)) - (util/format "translate(-%spx, %s)" (+ ofx 20) (if y-overflow-vh? "calc(-100% - 2rem)" 0)))))))) - [right-sidebar? editing-key y-overflow-vh?]) - - ;; HACK: close when click outside for classic editing models (popup) - (rum/use-effect! - (fn [] - (let [^js cnt js/document.body - handle (fn [^js e] - (when-not (some->> (.-target e) (.contains (rum/deref *el))) - (state/clear-editor-action!)))] - (.addEventListener cnt "click" handle false) - #(.removeEventListener cnt "click" handle))) - []) - - [:div.absolute.rounded-md.shadow-lg.absolute-modal - {:ref *el - :data-modal-name modal-name - :class (if y-overflow-vh? "is-overflow-vh-y" "") - :on-pointer-down (fn [e] - (.stopPropagation e)) - :on-key-down (fn [^js e] - (case (.-key e) - "Escape" - (do (state/clear-editor-action!) - (some-> (state/get-input) - (.focus))) - :dune) - (util/stop-propagation e)) - :style style} - cp])) - -(rum/defc transition-cp < rum/reactive - [cp modal-name set-default-width?] - (when-let [pos (:pos (state/sub :editor/action-data))] - (ui/css-transition - {:class-names "fade" - :timeout {:enter 500 - :exit 300}} - (absolute-modal cp modal-name set-default-width? pos)))) - -(rum/defc image-uploader < rum/reactive - [id format] - [:div.image-uploader - [:input - {:id "upload-file" - :type "file" - :on-change (fn [e] - (let [files (.-files (.-target e))] - (editor-handler/upload-asset id files format editor-handler/*asset-uploading? false))) - :hidden true}] - #_:clj-kondo/ignore - (when-let [uploading? (util/react editor-handler/*asset-uploading?)] - (let [processing (util/react editor-handler/*asset-uploading-process)] - (transition-cp - [:div.flex.flex-row.align-center.rounded-md.shadow-sm.bg-base-2.px-1.py-1 - (ui/loading - (util/format "Uploading %s%" (util/format "%2d" processing)))] - "upload-file" - false)))]) - (defn- set-up-key-down! [state format] (mixins/on-key-down @@ -694,146 +576,98 @@ [:span {:id (str "mock-text_" idx) :key idx} c])))]) -(rum/defc animated-modal < rum/reactive - [modal-name component set-default-width?] - (when-let [pos (:pos (state/get-editor-action-data))] - (ui/css-transition - {:key modal-name - :class-names {:enter "origin-top-left opacity-0 transform scale-95" - :enter-done "origin-top-left transition opacity-100 transform scale-100" - :exit "origin-top-left transition opacity-0 transform scale-95"} - :timeout {:enter 0 - :exit 150}} - (fn [_] - (absolute-modal - component - modal-name - set-default-width? - pos))))) - (defn- exist-editor-commands-popup? [] (some->> (shui-popup/get-popups) (some #(some-> % (:id) (str) (string/starts-with? ":editor.commands"))))) -;; TODO: [WIP] -(rum/defc shui-modals +(defn- open-editor-popup! + [id content opts] + (let [{:keys [left top rect]} (cursor/get-caret-pos (state/get-input)) + pos [(+ left (:left rect) -20) (+ top (:top rect) 20)] + {:keys [root-props content-props]} opts] + (shui/popup-show! + pos content + (merge + {:id (keyword :editor.commands id) + :align :start + :root-props (merge {:onOpenChange #(when-not % (state/clear-editor-action!))} root-props) + :content-props (merge {:onOpenAutoFocus #(.preventDefault %) + :onCloseAutoFocus #(.preventDefault %) + :data-editor-popup-ref (name id)} content-props) + :force-popover? true} + (dissoc opts :root-props :content-props))))) + +(rum/defc shui-editor-popups [id format action _data] (rum/use-effect! (fn [] - (let [{:keys [left top rect]} (cursor/get-caret-pos (state/get-input)) - pos [(+ left (:left rect) -20) (+ top (:top rect) 20)]] - (let [pid (case action - :commands - (shui/popup-show! pos - (commands id format) - {:id :editor.commands/commands - :align :start - :root-props {:onOpenChange - #(when-not % - (when (= :commands (state/get-editor-action)) - (state/clear-editor-action!)))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :onCloseAutoFocus #(.preventDefault %) - :withoutAnimation true - :data-editor-popup-ref "commands"} - :force-popover? true}) + (let [pid (case action + :commands + (open-editor-popup! :commands + (commands id format) + {:content-props {:withoutAnimation false}}) - :block-commands - (shui/popup-show! pos - (block-commands id format) - {:id :editor.commands/block-commands - :align :start - :root-props {:onOpenChange - #(when-not % - (when (= :block-commands (state/get-editor-action)) - (state/clear-editor-action!)))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :onCloseAutoFocus #(.preventDefault %) - :withoutAnimation true - :data-editor-popup-ref "commands"} - :force-popover? true}) + :block-commands + (open-editor-popup! :block-commands + (block-commands id format) + {:content-props {:withoutAnimation true}}) - (:block-search :page-search :page-search-hashtag) - (shui/popup-show! - pos (if (= :block-search action) - (block-search id format) - (page-search id format)) - {:id :editor.commands/block-search - :align :start - :root-props {:onOpenChange - #(when-not % - (when (contains? - #{:block-search :page-search :page-search-hashtag} - (state/get-editor-action)) - (state/clear-editor-action!)))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :onCloseAutoFocus #(.preventDefault %) - :data-editor-popup-ref (name action)} - :force-popover? true}) + (:block-search :page-search :page-search-hashtag) + (open-editor-popup! action + (if (= :block-search action) + (block-search id format) + (page-search id format)) + {:root-props {:onOpenChange + #(when-not % + (when (contains? + #{:block-search :page-search :page-search-hashtag} + (state/get-editor-action)) + (state/clear-editor-action!)))}}) - :datepicker - (shui/popup-show! - pos (datetime-comp/date-picker id format nil) - {:id :editor.commands/datepicker - :align :start - :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :data-editor-popup-ref "datepicker"} - :force-popover? true}) + :datepicker + (open-editor-popup! :datepicker + (datetime-comp/date-picker id format nil) {}) - :input - (shui/popup-show! - pos (input id - (fn [command m] - (editor-handler/handle-command-input command id format m)) - (fn [] - (editor-handler/handle-command-input-close id))) - {:id :editor.commands/input - :align :start - :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :onCloseAutoFocus #(.preventDefault %) - :data-editor-popup-ref "input"}}) + :input + (open-editor-popup! :input + (input id + (fn [command m] + (editor-handler/handle-command-input command id format m)) + (fn [] + (editor-handler/handle-command-input-close id))) {}) - :select-code-block-mode - (shui/popup-show! - pos (code-block-mode-picker id format) - {:id :editor.commands/code-block-mode-picker - :align :start - :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))} - :content-props {:onOpenAutoFocus #(.preventDefault %) - :data-editor-popup-ref "code-block-mode-picker"} - :force-popover? true}) + :select-code-block-mode + (open-editor-popup! :code-block-mode-picker + (code-block-mode-picker id format) {}) - ;; TODO: try remove local model state - false)] - #(when pid - (shui/popup-hide! pid))))) + :template-search + (open-editor-popup! :template-search + (template-search id format) {}) + + (:property-search :property-value-search) + (open-editor-popup! action + (if (= :property-search action) + (property-search id) (property-value-search id)) + {}) + + :zotero + (open-editor-popup! :zotero + (zotero/zotero-search id) {}) + + ;; TODO: try remove local model state + false)] + #(when pid + (shui/popup-hide! pid)))) [action]) [:<>]) -(rum/defc modals < rum/reactive - "React to atom changes, find and render the correct modal" +(rum/defc command-popups < + rum/reactive + "React to atom changes, find and render the correct popup" [id format] (let [action (state/sub :editor/action)] - [:<> - (shui-modals id format action nil) - (cond - (= :template-search action) - (animated-modal "template-search" (template-search id format) true) - - (= :property-search action) - (animated-modal "property-search" (property-search id) true) - - (= :property-value-search action) - (animated-modal "property-value-search" (property-value-search id) true) - - (= :zotero action) - (animated-modal "zotero-search" (zotero/zotero-search id) false) - - :else - nil)])) + (shui-editor-popups id format action nil))) (defn- editor-on-hide [state value* type e] @@ -916,9 +750,5 @@ [:div.editor-inner.flex.flex-1 {:class (if block "block-editor" "non-block-editor")} (ui/ls-textarea opts) - (mock-textarea content) - (modals id format) - - (when format - (image-uploader id format))])) + (command-popups id format)])) diff --git a/src/main/frontend/components/editor.css b/src/main/frontend/components/editor.css index 98fa4809d..1d37de7bc 100644 --- a/src/main/frontend/components/editor.css +++ b/src/main/frontend/components/editor.css @@ -73,7 +73,7 @@ pre { .ui__popover-content, .ui__dropdown-menu-content { &[data-editor-popup-ref] { - @apply p-1 w-72; + @apply p-1.5 w-72; &[data-side=top] { position: relative; @@ -82,7 +82,7 @@ pre { } &[data-editor-popup-ref=commands] { - @apply px-1 py-1 w-72; + @apply w-72; &[data-side=top] { max-height: min(calc(var(--radix-popover-content-available-height) - 60px), 460px); @@ -96,7 +96,7 @@ pre { &[data-editor-popup-ref=page-search], &[data-editor-popup-ref=block-search], &[data-editor-popup-ref=page-search-hashtag] { - @apply px-1 py-1 w-full sm:w-128; + @apply w-full sm:w-128; } &[data-editor-popup-ref=datepicker] { diff --git a/src/main/frontend/components/file_based/block.cljs b/src/main/frontend/components/file_based/block.cljs index 75fd8b51c..73a9ac37f 100644 --- a/src/main/frontend/components/file_based/block.cljs +++ b/src/main/frontend/components/file_based/block.cljs @@ -40,7 +40,7 @@ (when class (ui/checkbox {:class class :style {:margin-right 5} - :value checked? + :checked checked? :on-pointer-down (fn [e] (util/stop-propagation e)) :on-change (fn [_e] diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index e7d41faeb..3a2ba9e74 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -70,14 +70,16 @@ (if (and (= :default (get-in property [:block/schema :type])) (not (db-property/many? property))) (p/let [existing-value (get block (:db/ident property)) - new-block-id (when-not existing-value (db/new-block-id)) - _ (when-not existing-value + existing-value? (and (some? existing-value) + (not= (:db/ident existing-value) :logseq.property/empty-placeholder)) + new-block-id (when-not existing-value? (db/new-block-id)) + _ (when-not existing-value? (db-property-handler/create-property-text-block! (:db/id block) (:db/id property) value {:new-block-id new-block-id}))] - (or existing-value (db/entity [:block/uuid new-block-id]))) + (if existing-value? existing-value (db/entity [:block/uuid new-block-id]))) (p/let [new-block-id (db/new-block-id) _ (db-property-handler/create-property-text-block! (:db/id block) diff --git a/src/main/frontend/components/repo.css b/src/main/frontend/components/repo.css index abc09497f..0ebe70eee 100644 --- a/src/main/frontend/components/repo.css +++ b/src/main/frontend/components/repo.css @@ -16,27 +16,15 @@ .ui__dropdown-menu-content { &.repos-list { - @apply px-2 pb-[210px] relative overflow-hidden; - @apply min-w-[280px] sm:max-w-[320px] max-h-[66vh]; - - &.no-repos { - @apply pb-[180px]; - } - - &[data-mode=db] { - @apply pb-[114px]; - - &.no-repos { - @apply pb-[109px]; - } - } + @apply px-2 relative overflow-hidden; + @apply min-w-[280px] sm:max-w-[320px]; .ui__dropdown-menu-item { @apply overflow-hidden overflow-ellipsis; } .cp__repos-list-wrap { - @apply max-h-96 overflow-scroll m-[-8px] px-2 pb-6; + @apply max-h-80 overflow-scroll mx-[-8px] px-2 pb-2; } } } @@ -64,8 +52,7 @@ } .cp__repos-quick-actions { - @apply absolute left-[1px] right-[1px] bottom-[1px] bg-gray-01 px-2 py-3 border-t - flex flex-col rounded-b overflow-hidden; + @apply -mx-2 bg-gray-01 px-2 pb-1.5 pt-3 border-t flex flex-col rounded-b overflow-hidden; .ui__button { @apply w-full !py-4 !justify-start opacity-70 font-medium hover:opacity-90 diff --git a/src/main/frontend/components/views.cljs b/src/main/frontend/components/views.cljs index 9f6776d00..1a670a632 100644 --- a/src/main/frontend/components/views.cljs +++ b/src/main/frontend/components/views.cljs @@ -95,7 +95,7 @@ [block property] (let [type (get-in property [:block/schema :type]) many? (= :db.cardinality/many (get property :db/cardinality)) - ref-types (into db-property-type/value-ref-property-types #{:entity}) + ref-types (into db-property-type/ref-property-types #{:entity}) number-type? (= :number type) v (get block (:db/ident property)) v' (if many? v [v]) @@ -871,13 +871,13 @@ (fn [sorting] (set-sorting! sorting) (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property/table-sorting sorting))) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/sorting sorting))) :set-filters! (fn [filters] (let [filters (table-filters->persist-state filters)] (set-filters! filters) (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property/table-filters filters)))) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/filters filters)))) :set-visible-columns! (fn [columns] (let [hidden-columns (vec (keep (fn [[column visible?]] @@ -885,24 +885,24 @@ column)) columns))] (set-visible-columns! columns) (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property/table-hidden-columns hidden-columns)))) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/hidden-columns hidden-columns)))) :set-ordered-columns! (fn [ordered-columns] (let [ids (vec (remove #{:select} ordered-columns))] (set-ordered-columns! ordered-columns) (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property/table-ordered-columns ids))))})) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/ordered-columns ids))))})) (rum/defc view-inner < rum/static [view-entity {:keys [data set-data! columns add-new-object! create-view! title-key] :as option}] (let [[input set-input!] (rum/use-state "") - sorting (:logseq.property/table-sorting view-entity) + sorting (:logseq.property.table/sorting view-entity) [sorting set-sorting!] (rum/use-state (or sorting [{:id :block/updated-at, :asc? false}])) - filters (:logseq.property/table-filters view-entity) + filters (:logseq.property.table/filters view-entity) [filters set-filters!] (rum/use-state (or filters [])) - hidden-columns (:logseq.property/table-hidden-columns view-entity) + hidden-columns (:logseq.property.table/hidden-columns view-entity) [visible-columns set-visible-columns!] (rum/use-state (zipmap hidden-columns (repeat false))) - ordered-columns (vec (concat [:select] (:logseq.property/table-ordered-columns view-entity))) + ordered-columns (vec (concat [:select] (:logseq.property.table/ordered-columns view-entity))) [ordered-columns set-ordered-columns!] (rum/use-state ordered-columns) {:keys [set-sorting! set-filters! set-visible-columns! set-ordered-columns!]} (db-set-table-state! view-entity {:set-sorting! set-sorting! diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 9654d3a5b..8bf5ebc69 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1535,7 +1535,7 @@ (path/get-relative-path current-file-fpath file-path)) file-path)) -(defn upload-asset +(defn upload-asset! "Paste asset and insert link to current editing block" [id ^js files format uploading? drop-or-paste?] (let [repo (state/get-current-repo)] diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index d71da6cbb..6969d5b83 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -56,7 +56,6 @@ [frontend.handler.user :as user-handler] [frontend.handler.property.util :as pu] [frontend.handler.db-based.property.util :as db-pu] - [frontend.handler.file-based.property.util :as property-util] [frontend.handler.property :as property-handler] [frontend.handler.file-based.nfs :as nfs-handler] [frontend.handler.code :as code-handler] @@ -846,19 +845,6 @@ (defmethod handle :graph/save-db-to-disk [[_ _opts]] (persist-db/export-current-graph! {:succ-notification? true})) -(defmethod handle :search/transact-data [[_ repo data]] - (let [file-based? (config/local-file-based-graph? repo) - data' (cond-> data - file-based? - ;; remove built-in properties from content - (update :blocks-to-add - (fn [blocks] - (map #(update % :content - (fn [content] - (property-util/remove-built-in-properties (get % :format :markdown) content))) - blocks))))] - (search/transact-blocks! repo data'))) - (defmethod handle :class/configure [[_ page]] (shui/dialog-open! #(vector :<> diff --git a/src/main/frontend/handler/paste.cljs b/src/main/frontend/handler/paste.cljs index 801e64ce7..246324c3e 100644 --- a/src/main/frontend/handler/paste.cljs +++ b/src/main/frontend/handler/paste.cljs @@ -220,7 +220,7 @@ files (.-files clipboard-data)] (when-let [file (first files)] (when-let [block (state/get-edit-block)] - (editor-handler/upload-asset id #js[file] (:block/format block) + (editor-handler/upload-asset! id #js[file] (:block/format block) editor-handler/*asset-uploading? true))) (util/stop e)))) diff --git a/src/main/frontend/handler/plugin.cljs b/src/main/frontend/handler/plugin.cljs index 91020410b..d8bc12b26 100644 --- a/src/main/frontend/handler/plugin.cljs +++ b/src/main/frontend/handler/plugin.cljs @@ -252,10 +252,18 @@ (js/window.apis.addListener channel listener))) +(defn- normalize-plugin-metadata + [metadata] + (cond-> metadata + (not (string? (:author metadata))) + (assoc :author (or (get-in metadata [:author :name]) "")))) + (defn register-plugin [plugin-metadata] (when-let [pid (keyword (:id plugin-metadata))] - (swap! state/state update-in [:plugin/installed-plugins] assoc pid plugin-metadata))) + (some->> plugin-metadata + (normalize-plugin-metadata) + (swap! state/state update-in [:plugin/installed-plugins] assoc pid)))) (defn host-mounted! [] diff --git a/src/main/frontend/search.cljs b/src/main/frontend/search.cljs index 33ef599d4..f6dbcf4dc 100644 --- a/src/main/frontend/search.cljs +++ b/src/main/frontend/search.cljs @@ -106,11 +106,6 @@ (when-let [engine (get-engine repo)] (protocol/remove-db! engine))) -(defn transact-blocks! - [repo data] - (when-let [engine (get-engine repo)] - (protocol/transact-blocks! engine data))) - (defn get-unlinked-refs "Get matched result from search first, and then filter by worker db" [eid] diff --git a/src/main/frontend/worker/db/migrate.cljs b/src/main/frontend/worker/db/migrate.cljs index f77c3513d..9ad144989 100644 --- a/src/main/frontend/worker/db/migrate.cljs +++ b/src/main/frontend/worker/db/migrate.cljs @@ -72,6 +72,26 @@ datoms)] (concat schema-tx-data value-tx-data))) +(defn- update-table-properties + [conn _search-db] + (let [old-new-props {:logseq.property/table-sorting :logseq.property.table/sorting + :logseq.property/table-filters :logseq.property.table/filters + :logseq.property/table-ordered-columns :logseq.property.table/ordered-columns + :logseq.property/table-hidden-columns :logseq.property.table/hidden-columns} + props-tx (mapv (fn [[old new]] + {:db/id (:db/id (d/entity @conn old)) + :db/ident new}) + old-new-props)] + ;; Property changes need to be in their own tx for subsequent uses of properties to take effect + (ldb/transact! conn props-tx {:db-migrate? true}) + + (mapcat (fn [[old new]] + (->> (d/q '[:find ?b ?prop-v :in $ ?prop :where [?b ?prop ?prop-v]] @conn old) + (mapcat (fn [[id prop-value]] + [[:db/retract id old] + [:db/add id new prop-value]])))) + old-new-props))) + (def schema-version->updates [[3 {:properties [:logseq.property/table-sorting :logseq.property/table-filters :logseq.property/table-hidden-columns :logseq.property/table-ordered-columns] @@ -88,7 +108,8 @@ [7 {:fix replace-original-name-content-with-title}] [8 {:fix replace-object-and-page-type-with-node}] [9 {:fix update-task-ident}] - [10 {:fix property-checkbox-type-non-ref}]]) + [10 {:fix update-table-properties}] + [11 {:fix property-checkbox-type-non-ref}]]) (let [max-schema-version (apply max (map first schema-version->updates))] (assert (<= db-schema/version max-schema-version)) diff --git a/src/main/frontend/worker/rtc/client_op.cljs b/src/main/frontend/worker/rtc/client_op.cljs index f0f9b9a10..347e9566d 100644 --- a/src/main/frontend/worker/rtc/client_op.cljs +++ b/src/main/frontend/worker/rtc/client_op.cljs @@ -85,7 +85,7 @@ (if (> t1 t2) (merge-update-ops update-op2 update-op1) (let [{av-coll1 :av-coll block-uuid :block-uuid} (last update-op1) - {av-coll2 :av-coll} (last update-op1)] + {av-coll2 :av-coll} (last update-op2)] [:update t2 {:block-uuid block-uuid :av-coll (concat av-coll1 av-coll2)}])))) diff --git a/src/test/frontend/handler/paste_test.cljs b/src/test/frontend/handler/paste_test.cljs index 28982901a..73695c3de 100644 --- a/src/test/frontend/handler/paste_test.cljs +++ b/src/test/frontend/handler/paste_test.cljs @@ -241,7 +241,7 @@ reset [state/preferred-pasting-file? (constantly true) ;; paste-file-if-exists mocks below - editor-handler/upload-asset (fn [_id file & _] + editor-handler/upload-asset! (fn [_id file & _] (reset! pasted-file file)) util/stop (constantly nil) state/get-edit-block (constantly {})] diff --git a/src/test/logseq/api_test.cljs b/src/test/logseq/api_test.cljs index 0b6223c66..bf888b404 100644 --- a/src/test/logseq/api_test.cljs +++ b/src/test/logseq/api_test.cljs @@ -12,28 +12,32 @@ (deftest get-block (with-redefs [state/get-current-repo (constantly test-helper/test-db)] (db/transact! test-helper/test-db - [{:db/id 10000 - :block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0" - :block/title "1"} - {:db/id 10001 - :block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" - :block/title "2"} - {:db/id 10002 - :block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556" - :block/parent 10001 - :block/title "3"} - {:db/id 10003 - :block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d" - :block/parent 10002 - :block/title "4"}]) + [{:db/id 10000 + :block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0" + :block/title "1"} + {:db/id 10001 + :block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" + :block/title "2"} + {:db/id 10002 + :block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556" + :block/parent 10001 + :block/title "3"} + {:db/id 10003 + :block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d" + :block/parent 10002 + :block/title "4"}]) (is (= (:title (bean/->clj (api-block/get_block 10000 #js {}))) "1")) (is (= (:title (bean/->clj (api-block/get_block "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2")) (is (= (:title (bean/->clj (api-block/get_block #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2")) (is (= {:id 10001, :title "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :children [["uuid" "adae3006-f03e-4814-a1f5-f17f15b86556"]]} - (select-keys (js->clj (api-block/get_block 10001 #js {:includeChildren false}) :keywordize-keys true) - [:id :title :uuid :children]))) - (is (= {:title "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :id 10001, :children [{:title "3", :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :id 10002, :level 1, :children [{:title "4", :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :id 10003, :level 2, :children []}]}]} - (js->clj (api-block/get_block 10001 #js {:includeChildren true}) :keywordize-keys true))))) + (select-keys (js->clj (api-block/get_block 10001 #js {:includeChildren false}) :keywordize-keys true) + [:id :title :uuid :children]))) + ;; NOTE: `content` key is to be compatible with old APIs + (is (= {:id 10001, :title "2", :content "2" :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" + :children [{:id 10002 :title "3", :content "3" + :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :level 1, + :children [{:id 10003, :title "4", :content "4" :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :level 2, :children []}]}]} + (js->clj (api-block/get_block 10001 #js {:includeChildren true}) :keywordize-keys true))))) #_(cljs.test/run-tests)