diff --git a/deps/graph-parser/src/logseq/graph_parser/extract.cljc b/deps/graph-parser/src/logseq/graph_parser/extract.cljc index fa0998629b..165b2a2017 100644 --- a/deps/graph-parser/src/logseq/graph_parser/extract.cljc +++ b/deps/graph-parser/src/logseq/graph_parser/extract.cljc @@ -208,7 +208,7 @@ pages (remove nil? pages) pages (map (fn [page] (assoc page :block/uuid (d/squuid))) pages) blocks (->> (remove nil? blocks) - (map (fn [b] (dissoc b :block/title :block/body :block/level :block/children :block/meta :block/anchor))))] + (map (fn [b] (dissoc b :block/title :block/body :block/level :block/children :block/meta))))] [pages blocks]) (catch :default e (log/error :exception e)))) diff --git a/deps/graph-parser/src/logseq/graph_parser/property.cljs b/deps/graph-parser/src/logseq/graph_parser/property.cljs index 6354a8d187..47580b6424 100644 --- a/deps/graph-parser/src/logseq/graph_parser/property.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/property.cljs @@ -7,11 +7,11 @@ [goog.string.format])) (def colons "Property delimiter for markdown mode" "::") -(defn colons-org +(defn colons-org "Property delimiter for org mode" [property] (str ":" property ":")) - + (defn ->block-content "Creates a block content string from properties map" [properties] @@ -47,19 +47,23 @@ "Properties used by logseq that user can edit and that can have linkable property values" #{:alias :aliases :tags}) +(def editable-view-and-table-properties + "Properties used by view and table component" + #{;; view props + :logseq.color + ;; table props + :logseq.table.version :logseq.table.compact :logseq.table.headers :logseq.table.hover + :logseq.table.borders :logseq.table.stripes :logseq.table.max-width}) + (defn editable-built-in-properties "Properties used by logseq that user can edit" [] - (into #{:title :icon :template :template-including-parent :public :filters :exclude-from-graph-view - :logseq.query/nlp-date - ;; view props - :logseq.color - ;; table props - :logseq.table.version :logseq.table.compact :logseq.table.headers :logseq.table.hover - :logseq.table.borders :logseq.table.stripes :logseq.table.max-width + (set/union #{:title :icon :template :template-including-parent :public :filters :exclude-from-graph-view + :logseq.query/nlp-date ;; org-mode only - :macro :filetags} - editable-linkable-built-in-properties)) + :macro :filetags} + editable-linkable-built-in-properties + editable-view-and-table-properties)) (defn hidden-built-in-properties "Properties used by logseq that user can't edit or see" diff --git a/e2e-tests/whiteboards.spec.ts b/e2e-tests/whiteboards.spec.ts index 36158ff680..fb10d871de 100644 --- a/e2e-tests/whiteboards.spec.ts +++ b/e2e-tests/whiteboards.spec.ts @@ -126,6 +126,37 @@ test('clone the rectangle', async ({ page }) => { await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2) }) +test('group the rectangles', async ({ page }) => { + await page.keyboard.press(modKey + '+a') + await page.keyboard.press(modKey + '+g') + + await expect(page.locator('.logseq-tldraw .tl-group-container')).toHaveCount(1) +}) + +test('delete the group', async ({ page }) => { + await page.keyboard.press(modKey + '+a') + + await page.keyboard.press('Delete') + + await expect(page.locator('.logseq-tldraw .tl-group-container')).toHaveCount(0) + // should also delete the grouped shapes + await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(0) +}) + +test('undo the group deletion', async ({ page }) => { + await page.keyboard.press(modKey + '+z') + + await expect(page.locator('.logseq-tldraw .tl-group-container')).toHaveCount(1) + await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2) +}) + +test('undo the group action', async ({ page }) => { + await page.keyboard.press(modKey + '+z') + + await expect(page.locator('.logseq-tldraw .tl-group-container')).toHaveCount(0) + await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2) +}) + test('connect rectangles with an arrow', async ({ page }) => { const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 2a01b9b8b9..e9638728e0 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -1792,8 +1792,8 @@ (or (and empty-content? (not edit?) - (not (:block/top? block)) - (not (:block/bottom? block)) + (not (:block.temp/top? block)) + (not (:block.temp/bottom? block)) (not (util/react *control-show?))) (and doc-mode? (not collapsed?) @@ -2066,7 +2066,8 @@ (def hidden-editable-block-properties "Properties that are hidden in a block (block property)" - #{:logseq.query/nlp-date}) + (into #{:logseq.query/nlp-date} + gp-property/editable-view-and-table-properties)) (assert (set/subset? hidden-editable-block-properties (gp-property/editable-built-in-properties)) "Hidden editable page properties must be valid editable properties") @@ -2779,7 +2780,8 @@ block (if ref? (merge block (db/sub-block (:db/id block))) block) - {:block/keys [uuid children pre-block? top? refs level format content properties]} block + {:block/keys [uuid children pre-block? refs level format content properties]} block + {:block.temp/keys [top?]} block config (if navigated? (assoc config :id (str navigating-block)) config) block (merge block (block/parse-title-and-body uuid format pre-block? content)) blocks-container-id (:blocks-container-id config) @@ -2922,7 +2924,7 @@ :should-update (fn [old-state new-state] (let [compare-keys [:block/uuid :block/content :block/parent :block/collapsed? - :block/properties :block/left :block/children :block/_refs :block/bottom? :block/top?] + :block/properties :block/left :block/children :block/_refs :block.temp/bottom? :block.temp/top?] config-compare-keys [:show-cloze? :own-order-list-type :own-order-list-index] b1 (second (:rum/args old-state)) b2 (second (:rum/args new-state)) @@ -3316,8 +3318,8 @@ [config blocks idx item] (let [item (-> (dissoc item :block/meta) - (assoc :block/top? (zero? idx) - :block/bottom? (= (count blocks) (inc idx)))) + (assoc :block.temp/top? (zero? idx) + :block.temp/bottom? (= (count blocks) (inc idx)))) config (assoc config :block/uuid (:block/uuid item))] (rum/with-key (block-container config item) (str (:blocks-container-id config) "-" (:block/uuid item))))) diff --git a/src/main/frontend/extensions/tldraw.cljs b/src/main/frontend/extensions/tldraw.cljs index ff96171fde..13c2ddaac7 100644 --- a/src/main/frontend/extensions/tldraw.cljs +++ b/src/main/frontend/extensions/tldraw.cljs @@ -138,7 +138,8 @@ (when-let [^js api (gobj/get tln "api")] (p/then (when populate-onboarding? (whiteboard-handler/populate-onboarding-whiteboard api)) - #(do (state/focus-whiteboard-shape tln block-id) + #(do (whiteboard-handler/cleanup! (.-currentPage tln)) + (state/focus-whiteboard-shape tln block-id) (set-loaded-app tln))))))] (rum/use-effect! (fn [] (when (and loaded-app block-id) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 3ef23e4361..fe254dc6c0 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -341,8 +341,8 @@ (select-keys properties (property/hidden-properties)) (:block/properties block))] (-> block - (dissoc :block/top? - :block/bottom?) + (dissoc :block.temp/top? + :block.temp/bottom?) (assoc :block/content content :block/properties new-properties) (merge (if level {:block/level level} {}))))) @@ -826,7 +826,7 @@ (let [prev-block' (if (seq (:block/_refs block-e)) (assoc prev-block :block/uuid (:block/uuid block) - :block/additional-properties (:block/properties block)) + :block.temp/additional-properties (:block/properties block)) prev-block)] (delete-block-aux! block delete-children?) (save-block! repo prev-block' new-content {:editor/op :delete})) @@ -2646,7 +2646,7 @@ edit-block' (if next-block-has-refs? (assoc edit-block :block/uuid (:block/uuid next-block) - :block/additional-properties (dissoc (:block/properties next-block) :block/uuid)) + :block.temp/additional-properties (dissoc (:block/properties next-block) :block/uuid)) edit-block)] (outliner-tx/transact! transact-opts (delete-block-aux! next-block false) @@ -2691,7 +2691,7 @@ repo (state/get-current-repo) top-block? (= (:block/left block) (:block/page block)) single-block? (inside-of-single-block (.-target e)) - root-block? (= (:block/container block) (str (:block/uuid block)))] + root-block? (= (:block.temp/container block) (str (:block/uuid block)))] (mark-last-input-time! repo) (cond (not= selected-start selected-end) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 3cbe53a707..aebd5a0e26 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -153,13 +153,14 @@ (compute-tx app tl-page new-id-nonces db-id-nonces page-name replace?) tx-data (concat delete-blocks [page-block] upserted-blocks) new-shapes (get-in metadata [:data :new-shapes]) + deleted-shapes (get-in metadata [:data :deleted-shapes]) metadata' (cond ;; group (some #(= "group" (:type %)) new-shapes) (assoc metadata :whiteboard/op :group) ;; ungroup - (some #(= "group" (:type %)) (get-in metadata [:data :deleted-shapes])) + (and (not-empty deleted-shapes) (every? #(= "group" (:type %)) deleted-shapes)) (assoc metadata :whiteboard/op :un-group) ;; arrow @@ -361,6 +362,11 @@ [^js api ids] (apply (.-selectShapes api) ids)) +(defn cleanup! + [^js tl-page] + (let [shapes (.-shapes tl-page)] + (.cleanup tl-page (map #(.-id %) shapes)))) + (defn update-bindings! [^js tl-page page-name] (when-let [page (db/entity [:block/name page-name])] diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index 91d1cd2069..8e37915e56 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -140,7 +140,7 @@ (assert (ds/outliner-txs-state? txs-state) "db should be satisfied outliner-tx-state?") (let [m (-> (:data this) - (dissoc :block/children :block/meta :block/top? :block/bottom? + (dissoc :block/children :block/meta :block.temp/top? :block.temp/bottom? :block/title :block/body :block/level) (gp-util/remove-nils)) m (if (state/enable-block-timestamps?) (block-with-timestamps m) m) diff --git a/src/main/frontend/modules/outliner/datascript.cljc b/src/main/frontend/modules/outliner/datascript.cljc index 204618fefe..30ebfebfb2 100644 --- a/src/main/frontend/modules/outliner/datascript.cljc +++ b/src/main/frontend/modules/outliner/datascript.cljc @@ -126,9 +126,12 @@ (let [txs (remove-nil-from-transaction txs) txs (map (fn [m] (if (map? m) (dissoc m - :block/children :block/meta :block/top? :block/bottom? :block/anchor - :block/title :block/body :block/level :block/container :db/other-tx - :block/additional-properties) + ;; TODO: Move these attributes to :block.temp when the risk is lower + :block/children :block/meta :block/title :block/body :block/level + :db/other-tx + ;; :block.temp is for temporary block attributes that aren't transacted + :block.temp/container :block.temp/top? :block.temp/bottom? + :block.temp/additional-properties) m)) txs) txs (cond-> txs (:uuid-changed opts) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index d57bbcbc3f..3e102c6051 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -1808,7 +1808,7 @@ Similar to re-frame subscriptions" container (util/get-block-container block-element) block (if container (assoc block - :block/container (gobj/get container "id")) + :block.temp/container (gobj/get container "id")) block) content (string/trim (or content ""))] (swap! state diff --git a/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx b/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx index 87deb97180..908edc1996 100644 --- a/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/QuickLinks/QuickLinks.tsx @@ -25,7 +25,7 @@ export const QuickLinks: TLQuickLinksComponent = observer(({ shape }) => link[0].toLowerCase() !== app.currentPage.name && handlers.getBlockPageName(link[0]) !== app.currentPage.name ) - }, [shape.props.type, shape.props.parentId, shape.props.refs]) + }, [shape.props.id, shape.props.type, shape.props.parentId, shape.props.refs]) if (links.length === 0) return null diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx index 9252d736c1..9e93a28b98 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/GroupShape.tsx @@ -29,7 +29,7 @@ export class GroupShape extends TLGroupShape { const Indicator = this.ReactIndicator return ( - + { + // A group without children needs to be removed + if (this.shapes.length === 0) { + const app = useApp() + app.deleteShapes([this.id]) + + return { + minX: 0, + minY: 0, + maxX: 0, + maxY: 0, + width: 0, + height: 0, + } + } + return BoundsUtils.getCommonBounds(this.shapes.map(s => s.getBounds())) } }