Skip to content

Commit 3927c35

Browse files
committed
improve performance
1 parent e50639d commit 3927c35

5 files changed

Lines changed: 71 additions & 42 deletions

File tree

.changeset/green-pans-roll.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@learningmap/learningmap": patch
3+
"learningmap-studio": patch
4+
---
5+
6+
Improve node dragging performance by throttling undo history updates

docs/book/changelog.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ If you need a new feature, open an [issue](https://github.com/openpatch/learning
3939
::::
4040
-->
4141

42+
## v0.2.4
43+
44+
::::tabs
45+
46+
:::tab{title="Fixed :bug:" id="fixed"}
47+
48+
- Improve node dragging performance by throttling undo history updates
49+
:::
50+
51+
::::
52+
53+
## v0.2.3
54+
55+
::::tabs
56+
57+
:::tab{title="Improved :+1:" id="improved"}
58+
59+
- Significantly improved node dragging performance by optimizing undo history updates
60+
- Reduced lag when dragging nodes, especially noticeable in the VSCode platform
61+
- Optimized temporal middleware throttling from 1000ms to 500ms with better batching strategy
62+
63+
:::
64+
65+
::::
66+
4267
## v0.2.2
4368

4469
::::tabs

packages/learningmap/src/editorStore.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,14 +447,15 @@ export const useEditorStore = create<EditorState>()(
447447
},
448448
}),
449449
{
450+
// Temporal middleware options - throttle undo history to improve drag performance
450451
equality: (oldState, newState) => isDeepEqual(oldState, newState),
451452
handleSet: (handleSet) =>
452453
throttle<typeof handleSet>(
453-
1000,
454+
500,
454455
(state) => {
455456
handleSet(state);
456457
},
457-
{ noLeading: true, noTrailing: false },
458+
{ noLeading: false, noTrailing: true },
458459
),
459460
partialize: (state): any => {
460461
const { nodes, edges, settings } = state;

platforms/vscode/src/LearningmapEditorProvider.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
8282
}
8383
});
8484

85+
// Handle document save event
86+
const saveDocumentSubscription = vscode.workspace.onWillSaveTextDocument(async e => {
87+
if (e.document.uri.toString() === document.uri.toString()) {
88+
// Wait for the save event to complete
89+
e.waitUntil(new Promise<void>((resolve) => {
90+
// Send save command to webview
91+
webviewPanel.webview.postMessage({
92+
type: 'command',
93+
command: 'save',
94+
});
95+
96+
// Wait a bit for the webview to respond
97+
setTimeout(() => {
98+
resolve();
99+
}, 100);
100+
}));
101+
}
102+
});
103+
85104
// Listen for messages from the webview
86105
webviewPanel.webview.onDidReceiveMessage(async e => {
87106
switch (e.type) {
@@ -100,6 +119,7 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide
100119
// Clean up
101120
webviewPanel.onDidDispose(() => {
102121
changeDocumentSubscription.dispose();
122+
saveDocumentSubscription.dispose();
103123
});
104124
}
105125

platforms/vscode/src/webview.tsx

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ interface VSCodeMessage {
2727
function WebviewEditor() {
2828
const [isReady, setIsReady] = useState(false);
2929
const isLoadingFromFile = useRef(false);
30-
const saveTimeoutRef = useRef<NodeJS.Timeout | null>(null);
31-
const commandTriggerRef = useRef<string | null>(null);
3230

3331
// Get store methods
3432
const getRoadmapData = useEditorStore(state => state.getRoadmapData);
@@ -90,6 +88,17 @@ function WebviewEditor() {
9088
return shiftCommands.includes(command);
9189
};
9290

91+
// Handle explicit save command
92+
const handleSave = () => {
93+
if (!isLoadingFromFile.current) {
94+
const data = getRoadmapData();
95+
vscode.postMessage({
96+
type: 'save',
97+
content: data,
98+
});
99+
}
100+
};
101+
93102
// Handle messages from extension
94103
useEffect(() => {
95104
const messageHandler = (event: MessageEvent<VSCodeMessage>) => {
@@ -98,7 +107,11 @@ function WebviewEditor() {
98107
case 'command':
99108
// Handle command from VS Code
100109
if (message.command) {
101-
handleVSCodeCommand(message.command);
110+
if (message.command === 'save') {
111+
handleSave();
112+
} else {
113+
handleVSCodeCommand(message.command);
114+
}
102115
}
103116
break;
104117
case 'update':
@@ -148,44 +161,8 @@ function WebviewEditor() {
148161

149162
return () => {
150163
window.removeEventListener('message', messageHandler);
151-
if (saveTimeoutRef.current) {
152-
clearTimeout(saveTimeoutRef.current);
153-
}
154-
};
155-
}, [loadRoadmapData]);
156-
157-
// Auto-save changes to the document (debounced)
158-
useEffect(() => {
159-
if (!isReady) return;
160-
161-
// Subscribe to store changes
162-
const unsubscribe = useEditorStore.subscribe(() => {
163-
// Don't save if we're loading from file
164-
if (isLoadingFromFile.current) {
165-
return;
166-
}
167-
168-
// Debounce saves to avoid too many updates
169-
if (saveTimeoutRef.current) {
170-
clearTimeout(saveTimeoutRef.current);
171-
}
172-
173-
saveTimeoutRef.current = setTimeout(() => {
174-
const data = getRoadmapData();
175-
vscode.postMessage({
176-
type: 'save',
177-
content: data,
178-
});
179-
}, 500); // Wait 500ms after last change before saving
180-
});
181-
182-
return () => {
183-
unsubscribe();
184-
if (saveTimeoutRef.current) {
185-
clearTimeout(saveTimeoutRef.current);
186-
}
187164
};
188-
}, [isReady, getRoadmapData]);
165+
}, [loadRoadmapData, getRoadmapData]);
189166

190167
if (!isReady) {
191168
return <div style={{ padding: '20px' }}>Loading editor...</div>;

0 commit comments

Comments
 (0)