Skip to content

Commit cce0ff1

Browse files
authored
ENG-1138 Migrate canvas shape node type to discourse-node (#894)
* Refactor Discourse Node Handling and Introduce Node Type ID - Replaced the use of createNodeShapeUtils with DiscourseNodeUtil across components to streamline discourse node management. - Introduced DISCOURSE_NODE_SHAPE_TYPE constant for consistent node type identification. - Updated various components to utilize nodeTypeId for better clarity and functionality in shape creation and manipulation. - Enhanced migration logic to accommodate new node type structure, ensuring backward compatibility and improved data integrity. This refactor improves the maintainability and readability of the codebase while ensuring that new features can be integrated more seamlessly. * Fix clipboard discourse node shape typing * Fix missed discourse node type checks * Keep legacy node shape utils for cloud sync * Refactor Discourse Relation Shape Utilities - Introduced utility functions to determine relation and bindable discourse node shape types for improved clarity in shape handling. - Updated migration logic to clarify assumptions regarding node and relation type IDs. - Added a TODO comment to rename the migration file for better organization as it serves both relation and node shapes. * Enhance Clipboard Component with TypeId for Discourse Nodes - Introduced a new type definition, ClipboardDiscourseNode, to include typeId for better structure and clarity. - Updated state management in ClipboardPageSection to utilize the new type, improving type safety and consistency. - Adjusted logic to map and retrieve typeId from discourse nodes, ensuring accurate handling of node types throughout the component. * .
1 parent 5ec2734 commit cce0ff1

15 files changed

Lines changed: 356 additions & 134 deletions

apps/roam/src/components/Export.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ import {
6262
} from "@tldraw/editor";
6363
import calcCanvasNodeSizeAndImg from "~/utils/calcCanvasNodeSizeAndImg";
6464
import {
65-
createNodeShapeUtils,
65+
DiscourseNodeUtil,
66+
DISCOURSE_NODE_SHAPE_TYPE,
6667
DiscourseNodeShape,
6768
} from "~/components/canvas/DiscourseNodeUtil";
6869
import { discourseContext, MAX_WIDTH } from "~/components/canvas/Tldraw";
@@ -362,7 +363,7 @@ const ExportDialog: ExportDialogComponent = ({
362363
);
363364

364365
// UTILS
365-
const discourseNodeUtils = createNodeShapeUtils(allNodes);
366+
const discourseNodeUtils = [DiscourseNodeUtil];
366367
const discourseRelationUtils =
367368
createAllRelationShapeUtils(allRelationIds);
368369
const referencedNodeUtils = createAllReferencedNodeUtils(
@@ -552,12 +553,13 @@ const ExportDialog: ExportDialogComponent = ({
552553
index: currentIndex,
553554
rotation: 0,
554555
isLocked: false,
555-
type: nodeType,
556+
type: DISCOURSE_NODE_SHAPE_TYPE,
556557
props: {
557558
w,
558559
h,
559560
uid: r.uid,
560561
title: String(r[firstColumnKey]),
562+
nodeTypeId: nodeType,
561563
imageUrl,
562564
size: "s",
563565
fontFamily: "sans",

apps/roam/src/components/canvas/CanvasDrawer.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import { Editor, useEditor, TLShapeId } from "tldraw";
1818
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
1919
import getCurrentPageUid from "roamjs-components/dom/getCurrentPageUid";
2020
import getDiscourseNodes from "~/utils/getDiscourseNodes";
21-
import { DiscourseNodeShape } from "./DiscourseNodeUtil";
21+
import {
22+
DISCOURSE_NODE_SHAPE_TYPE,
23+
DiscourseNodeShape,
24+
getDiscourseNodeTypeId,
25+
} from "./DiscourseNodeUtil";
2226
import { formatHexColor } from "~/components/settings/DiscourseNodeCanvasSettings";
2327
import posthog from "posthog-js";
2428

@@ -56,14 +60,15 @@ export const CanvasDrawerContent = ({
5660
const entries: NodeGroup[] = Object.entries(groupedShapes).map(
5761
([uid, shapes]) => {
5862
const primaryShape = shapes[0];
63+
const nodeTypeId = getDiscourseNodeTypeId({ shape: primaryShape });
5964
const typeLabel =
60-
discourseNodes.find((n) => n.type === primaryShape.type)?.text ||
61-
primaryShape.type ||
65+
discourseNodes.find((n) => n.type === nodeTypeId)?.text ||
66+
nodeTypeId ||
6267
"Unknown";
6368
return {
6469
uid,
6570
title: primaryShape.props.title,
66-
type: primaryShape.type,
71+
type: nodeTypeId,
6772
typeLabel,
6873
shapes,
6974
isDuplicate: shapes.length > 1,
@@ -400,10 +405,20 @@ export const CanvasDrawerPanel = () => {
400405
useEffect(() => {
401406
const updateGroupedShapes = () => {
402407
const allRecords = editor.store.allRecords();
408+
const nodeTypeSet = new Set(getDiscourseNodes().map((node) => node.type));
403409
const shapes = allRecords.filter((record) => {
404410
if (record.typeName !== "shape") return false;
405411
const shape = record as DiscourseNodeShape;
406-
return !!shape.props?.uid;
412+
if (
413+
record.type !== DISCOURSE_NODE_SHAPE_TYPE &&
414+
!nodeTypeSet.has(record.type)
415+
) {
416+
return false;
417+
}
418+
return (
419+
!!shape.props?.uid &&
420+
nodeTypeSet.has(getDiscourseNodeTypeId({ shape }))
421+
);
407422
}) as DiscourseNodeShape[];
408423

409424
const grouped = shapes.reduce((acc: GroupedShapes, shape) => {

apps/roam/src/components/canvas/Clipboard.tsx

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
TLDefaultSizeStyle,
4141
TLDefaultFontStyle,
4242
FONT_FAMILIES,
43+
TLShapePartial,
4344
} from "tldraw";
4445
import { useAtom } from "@tldraw/state-react";
4546
import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
@@ -49,7 +50,9 @@ import getAllReferencesOnPage from "~/utils/getAllReferencesOnPage";
4950
import {
5051
DiscourseNodeShape,
5152
DEFAULT_STYLE_PROPS,
53+
DISCOURSE_NODE_SHAPE_TYPE,
5254
FONT_SIZES,
55+
getDiscourseNodeTypeId,
5356
} from "./DiscourseNodeUtil";
5457
import { openBlockInSidebar, createBlock } from "roamjs-components/writes";
5558
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
@@ -391,10 +394,18 @@ type NodeGroup = {
391394
uid: string;
392395
text: string;
393396
type: string;
397+
typeId: string;
394398
shapes: DiscourseNodeShape[];
395399
isDuplicate: boolean;
396400
};
397401

402+
type ClipboardDiscourseNode = {
403+
uid: string;
404+
text: string;
405+
type: string;
406+
typeId: string;
407+
};
408+
398409
type DragState =
399410
| {
400411
name: "idle";
@@ -437,7 +448,7 @@ const ClipboardPageSection = ({
437448
}) => {
438449
const [isOpen, setIsOpen] = useState(true);
439450
const [discourseNodes, setDiscourseNodes] = useState<
440-
Array<{ uid: string; text: string; type: string }>
451+
ClipboardDiscourseNode[]
441452
>([]);
442453
const [isLoading, setIsLoading] = useState(false);
443454
const [openSections, setOpenSections] = useState<Record<string, boolean>>({});
@@ -469,6 +480,7 @@ const ClipboardPageSection = ({
469480
uid: refPage.uid,
470481
text: refPage.text,
471482
type: discourseNode.text,
483+
typeId: discourseNode.type,
472484
},
473485
];
474486
});
@@ -531,10 +543,18 @@ const ClipboardPageSection = ({
531543
const shapesByUid = useMemo(() => {
532544
void storeVersion;
533545
const groupedShapes = new Map<string, DiscourseNodeShape[]>();
546+
const nodeTypeIds = new Set(discourseNodes.map((node) => node.typeId));
534547
const allRecords = editor.store.allRecords();
535548
allRecords.forEach((record) => {
536549
if (record.typeName !== "shape") return;
550+
if (
551+
record.type !== DISCOURSE_NODE_SHAPE_TYPE &&
552+
!nodeTypeIds.has(record.type)
553+
) {
554+
return;
555+
}
537556
const shape = record as DiscourseNodeShape;
557+
if (!nodeTypeIds.has(getDiscourseNodeTypeId({ shape }))) return;
538558
const uid = shape.props?.uid;
539559
if (!uid) return;
540560
const currentShapes = groupedShapes.get(uid);
@@ -545,7 +565,7 @@ const ClipboardPageSection = ({
545565
}
546566
});
547567
return groupedShapes;
548-
}, [editor.store, storeVersion]);
568+
}, [discourseNodes, editor.store, storeVersion]);
549569

550570
const groupedNodes = useMemo(() => {
551571
const groups: NodeGroup[] = discourseNodes.map((node) => {
@@ -554,6 +574,7 @@ const ClipboardPageSection = ({
554574
uid: node.uid,
555575
text: node.text,
556576
type: node.type,
577+
typeId: node.typeId,
557578
shapes,
558579
isDuplicate: shapes.length > 1,
559580
};
@@ -670,10 +691,20 @@ const ClipboardPageSection = ({
670691
async (node: { uid: string; text: string }, pagePoint: Vec) => {
671692
if (!extensionAPI) return;
672693
if (!showNodesOnCanvas) {
694+
const nodeTypeIds = new Set(discourseNodes.map((node) => node.typeId));
673695
const nodeExistsOnCanvas = editor.store.allRecords().some((record) => {
674696
if (record.typeName !== "shape") return false;
697+
if (
698+
record.type !== DISCOURSE_NODE_SHAPE_TYPE &&
699+
!nodeTypeIds.has(record.type)
700+
) {
701+
return false;
702+
}
675703
const shape = record as DiscourseNodeShape;
676-
return shape.props?.uid === node.uid;
704+
return (
705+
nodeTypeIds.has(getDiscourseNodeTypeId({ shape })) &&
706+
shape.props?.uid === node.uid
707+
);
677708
});
678709
if (nodeExistsOnCanvas) return;
679710
}
@@ -697,9 +728,9 @@ const ClipboardPageSection = ({
697728
});
698729

699730
const shapeId = createShapeId();
700-
const shape = {
731+
const shape: TLShapePartial<DiscourseNodeShape> = {
701732
id: shapeId,
702-
type: nodeType.type,
733+
type: DISCOURSE_NODE_SHAPE_TYPE,
703734
x: pagePoint.x - w / 2,
704735
y: pagePoint.y - h / 2,
705736
props: {
@@ -710,11 +741,12 @@ const ClipboardPageSection = ({
710741
imageUrl,
711742
size: "s" as TLDefaultSizeStyle,
712743
fontFamily: "sans" as TLDefaultFontStyle,
744+
nodeTypeId: nodeType.type,
713745
},
714746
};
715747
editor.createShape<DiscourseNodeShape>(shape);
716748
},
717-
[editor, extensionAPI, showNodesOnCanvas],
749+
[discourseNodes, editor, extensionAPI, showNodesOnCanvas],
718750
);
719751

720752
// Drag and drop handlers

0 commit comments

Comments
 (0)