mirror of https://github.com/logseq/logseq
Merge branch 'feat/db' into refactor/boolean-not-ref-type
commit
ea0a26e744
|
@ -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"
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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?}])}
|
||||
|
|
|
@ -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)]))
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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 :<>
|
||||
|
|
|
@ -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))))
|
||||
|
||||
|
|
|
@ -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!
|
||||
[]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)}]))))
|
||||
|
|
|
@ -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 {})]
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue