Skip to content

Commit 26fef42

Browse files
committed
Merge origin/main (ENG-1403, ENG-1508) into migration-block-init-staging-branch
Resolved 2 import conflicts in canvas files — keep both sides (accessor imports + new canvas sync/posthog imports).
2 parents 19f90c0 + 07bf56a commit 26fef42

5 files changed

Lines changed: 475 additions & 47 deletions

File tree

apps/obsidian/src/components/canvas/utils/tldraw.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
TLDATA_DELIMITER_END,
1515
TLDATA_DELIMITER_START,
1616
TLDRAW_VERSION,
17+
VIEW_TYPE_TLDRAW_DG_PREVIEW,
1718
} from "~/constants";
1819
import DiscourseGraphPlugin from "~/index";
1920
import { checkAndCreateFolder, getNewUniqueFilepath } from "~/utils/file";
@@ -178,8 +179,7 @@ export const createCanvas = async (plugin: DiscourseGraphPlugin) => {
178179
try {
179180
const filename = `Canvas-${format(new Date(), "yyyy-MM-dd-HHmm")}`;
180181
const folderpath = plugin.settings.canvasFolderPath;
181-
const attachmentsFolder =
182-
plugin.settings.canvasAttachmentsFolderPath;
182+
const attachmentsFolder = plugin.settings.canvasAttachmentsFolderPath;
183183

184184
await checkAndCreateFolder(folderpath, plugin.app.vault);
185185
await checkAndCreateFolder(attachmentsFolder, plugin.app.vault);
@@ -193,6 +193,10 @@ export const createCanvas = async (plugin: DiscourseGraphPlugin) => {
193193
const file = await plugin.app.vault.create(fname, content);
194194
const leaf = plugin.app.workspace.getLeaf(false);
195195
await leaf.openFile(file);
196+
await leaf.setViewState({
197+
type: VIEW_TYPE_TLDRAW_DG_PREVIEW,
198+
state: { file: file.path },
199+
});
196200

197201
return file;
198202
} catch (e) {

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

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Icon } from "@blueprintjs/core";
1010
import ExtensionApiContextProvider, {
1111
useExtensionAPI,
1212
} from "roamjs-components/components/ExtensionApiContext";
13-
import { OnloadArgs } from "roamjs-components/types";
13+
import { OnloadArgs, PullBlock } from "roamjs-components/types";
1414
import renderWithUnmount from "roamjs-components/util/renderWithUnmount";
1515

1616
import {
@@ -102,9 +102,12 @@ import { BLOCK_REF_REGEX } from "roamjs-components/dom";
102102
import { defaultHandleExternalTextContent } from "./defaultHandleExternalTextContent";
103103
import {
104104
CanvasSyncMode,
105+
getCanvasSyncMigrationState,
106+
getReadyCanvasStore,
105107
ensureCanvasSyncMode,
106108
getEffectiveCanvasSyncMode,
107-
setCanvasSyncMode,
109+
migrateLocalCanvasToCloud,
110+
setCanvasSyncSettings,
108111
} from "./canvasSyncMode";
109112
import {
110113
CanvasStoreAdapterArgs,
@@ -113,6 +116,7 @@ import {
113116
import posthog from "posthog-js";
114117
import { getPersonalSetting } from "~/components/settings/utils/accessors";
115118
import { PERSONAL_KEYS } from "~/components/settings/utils/settingKeys";
119+
import { json, normalizeProps } from "~/utils/getBlockProps";
116120

117121
declare global {
118122
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
@@ -171,9 +175,44 @@ const TldrawCanvas = ({ title }: { title: string }) => {
171175
setCanvasSyncModeState(ensureCanvasSyncMode({ pageUid }));
172176
}, [pageUid]);
173177

178+
// Convert from local to sync when the block props change
179+
// EG: When UserA sets the canvas sync mode to sync
180+
// UserB's canvas should be converted to sync
181+
useEffect(() => {
182+
if (!pageUid || canvasSyncMode !== "local") return;
183+
184+
const pullWatchProps = [
185+
"[:block/props]",
186+
`[:block/uid "${pageUid}"]`,
187+
(_before: PullBlock | null, after: PullBlock | null) => {
188+
const blockProps = normalizeProps(
189+
(after?.[":block/props"] || {}) as json,
190+
) as Record<string, json>;
191+
const rjsqb = blockProps?.["roamjs-query-builder"] as Record<
192+
string,
193+
unknown
194+
>;
195+
if (rjsqb?.canvasSyncMode !== "sync") return;
196+
setCanvasSyncModeState("sync");
197+
},
198+
] as const;
199+
200+
window.roamAlphaAPI.data.addPullWatch(...pullWatchProps);
201+
return () => {
202+
window.roamAlphaAPI.data.removePullWatch(...pullWatchProps);
203+
};
204+
}, [canvasSyncMode, pageUid]);
205+
174206
const onCanvasSyncModeChange = useCallback(
175207
(mode: CanvasSyncMode) => {
176-
setCanvasSyncMode({ pageUid, mode });
208+
const currentMigrationState = getCanvasSyncMigrationState({ pageUid });
209+
const nextMigrationState =
210+
mode === "sync" && !currentMigrationState ? "pending" : undefined;
211+
setCanvasSyncSettings({
212+
pageUid,
213+
mode,
214+
migrationState: nextMigrationState,
215+
});
177216
setCanvasSyncModeState(mode);
178217
},
179218
[pageUid],
@@ -254,6 +293,7 @@ const useCloudflareCanvasStore = ({
254293
performUpgrade: () => {},
255294
};
256295
};
296+
257297
const TldrawCanvasRoam = ({
258298
title,
259299
pageUid,
@@ -632,7 +672,6 @@ const TldrawCanvasShared = ({
632672
allRelationNames,
633673
allAddReferencedNodeActions,
634674
canvasSyncMode,
635-
onCanvasSyncModeChange,
636675
});
637676

638677
const storeAdapterArgs = useCanvasStoreAdapterArgs({
@@ -643,6 +682,7 @@ const TldrawCanvasShared = ({
643682
allAddReferencedNodeByAction,
644683
});
645684
const {
685+
migrations,
646686
customShapeUtils,
647687
customBindingUtils,
648688
customShapeTypes,
@@ -671,6 +711,8 @@ const TldrawCanvasShared = ({
671711
allNodes,
672712
allRelationNames,
673713
allAddReferencedNodeByAction,
714+
canvasSyncMode,
715+
onCanvasSyncModeChange,
674716
toggleMaximized: handleMaximizedChange,
675717
setConvertToDialogOpen,
676718
discourseContext,
@@ -685,6 +727,55 @@ const TldrawCanvasShared = ({
685727
}, [pageUid]);
686728
const { store, needsUpgrade, performUpgrade, error, isLoading } =
687729
useStoreAdapter(storeAdapterArgs);
730+
const migratedCloudStoreRef = useRef<string | null>(null);
731+
732+
// Migrate local canvas to cloud sync
733+
useEffect(() => {
734+
if (!isCloudflareSync || canvasSyncMode !== "sync") return;
735+
if (getCanvasSyncMigrationState({ pageUid }) !== "pending") return;
736+
737+
const readyStore = getReadyCanvasStore(store);
738+
if (!readyStore) return;
739+
740+
const storeId = `${pageUid}:${readyStore.id}`;
741+
if (migratedCloudStoreRef.current === storeId) return;
742+
migratedCloudStoreRef.current = storeId;
743+
744+
try {
745+
const { migrated } = migrateLocalCanvasToCloud({
746+
pageUid,
747+
store: readyStore,
748+
migrations,
749+
customShapeUtils,
750+
customBindingUtils,
751+
});
752+
if (migrated)
753+
renderToast({
754+
id: "tldraw-cloud-migration",
755+
intent: "success",
756+
content: "Migrated local canvas to cloud sync.",
757+
});
758+
} catch (migrationError) {
759+
migratedCloudStoreRef.current = null;
760+
internalError({
761+
error: migrationError,
762+
type: "Canvas: Local to cloud migration failed",
763+
context: {
764+
pageUid,
765+
title,
766+
},
767+
});
768+
}
769+
}, [
770+
canvasSyncMode,
771+
customBindingUtils,
772+
customShapeUtils,
773+
isCloudflareSync,
774+
migrations,
775+
pageUid,
776+
store,
777+
title,
778+
]);
688779

689780
// ASSETS
690781
const assetLoading = usePreloadAssets(defaultEditorAssetUrls);

0 commit comments

Comments
 (0)