Skip to content

Commit db491db

Browse files
authored
Merge pull request #82 from ClayPulse/hotfix
Fix app snapshot states change too often bug
2 parents 1b0d2c8 + 6cef9de commit db491db

File tree

10 files changed

+55
-22
lines changed

10 files changed

+55
-22
lines changed

.changeset/odd-hounds-enjoy.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@pulse-editor/shared-utils": patch
3+
"@pulse-editor/react-api": patch
4+
---
5+
6+
Fix snapshot restore triggers at every state changes

.changeset/pre.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"large-moose-tap",
4040
"lazy-zebras-mate",
4141
"mighty-ghosts-crash",
42+
"odd-hounds-enjoy",
4243
"petite-memes-fix",
4344
"polite-lines-dance",
4445
"polite-rules-switch",

npm-packages/react-api/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @pulse-editor/react-api
22

3+
## 0.1.1-alpha.47
4+
5+
### Patch Changes
6+
7+
- Fix snapshot restore triggers at every state changes
8+
- Updated dependencies
9+
- @pulse-editor/shared-utils@0.1.1-alpha.47
10+
311
## 0.1.1-alpha.46
412

513
### Patch Changes

npm-packages/react-api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pulse-editor/react-api",
3-
"version": "0.1.1-alpha.46",
3+
"version": "0.1.1-alpha.47",
44
"main": "dist/main.js",
55
"files": [
66
"dist"
@@ -38,7 +38,7 @@
3838
"typescript-eslint": "^8.30.1"
3939
},
4040
"peerDependencies": {
41-
"@pulse-editor/shared-utils": "0.1.1-alpha.46",
41+
"@pulse-editor/shared-utils": "0.1.1-alpha.47",
4242
"react": "^19.0.0",
4343
"react-dom": "^19.0.0"
4444
}

npm-packages/react-api/src/hooks/editor/use-snapshot-state.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useContext, useEffect, useState } from "react";
1+
import { useContext, useEffect, useRef, useState } from "react";
22
import { SnapshotContext } from "../../providers/snapshot-provider";
33

44
export default function useSnapShotState<T>(
@@ -7,25 +7,23 @@ export default function useSnapShotState<T>(
77
onRestore?: (value: T) => void
88
) {
99
const snapshotContext = useContext(SnapshotContext);
10-
1110
if (!snapshotContext) {
1211
throw new Error("useSnapShotState must be used within a SnapshotProvider");
1312
}
1413

1514
const { states, setStates } = snapshotContext;
16-
17-
// Initialize state with the value from context or the initial value
1815
const [state, setState] = useState<T>(
1916
states[key] !== undefined ? states[key] : initialValue
2017
);
2118

22-
// Update context whenever state changes
19+
const isLocalUpdate = useRef(false);
20+
2321
const setSnapshotState: React.Dispatch<React.SetStateAction<T>> = (value) => {
2422
setState((prev) => {
2523
const newValue =
2624
typeof value === "function" ? (value as (prev: T) => T)(prev) : value;
2725

28-
// Defer the setStates call to next microtask, outside render phase
26+
isLocalUpdate.current = true; // mark as local
2927
Promise.resolve().then(() => {
3028
setStates((prevStates) => ({
3129
...prevStates,
@@ -37,26 +35,31 @@ export default function useSnapShotState<T>(
3735
});
3836
};
3937

40-
// Set the initial value in context if not already set
38+
// Initialize context with initial value
4139
useEffect(() => {
42-
// Only set if the key does not exist in the context
4340
if (states[key] === undefined && initialValue !== undefined) {
44-
setStates((prevStates) => ({
45-
...prevStates,
41+
setStates((prev) => ({
42+
...prev,
4643
[key]: initialValue,
4744
}));
4845
}
4946
}, []);
5047

51-
// Restore state from context when key or states change
48+
// Only restore when external changes occur
5249
useEffect(() => {
53-
console.log("Restoring state for key:", key, states[key]);
50+
const contextValue = states[key];
51+
if (contextValue === undefined) return;
52+
53+
if (isLocalUpdate.current) {
54+
// skip this run because we caused it ourselves
55+
isLocalUpdate.current = false;
56+
return;
57+
}
5458

55-
if (states[key] !== undefined && states[key] !== state) {
56-
setState(states[key]);
57-
if (onRestore) {
58-
onRestore(states[key]);
59-
}
59+
if (contextValue !== state) {
60+
console.log("Restoring state for key:", key, contextValue);
61+
setState(contextValue);
62+
onRestore?.(contextValue);
6063
}
6164
}, [states[key]]);
6265

npm-packages/shared-utils/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @pulse-editor/shared-utils
22

3+
## 0.1.1-alpha.47
4+
5+
### Patch Changes
6+
7+
- Fix snapshot restore triggers at every state changes
8+
39
## 0.1.1-alpha.46
410

511
### Patch Changes

npm-packages/shared-utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pulse-editor/shared-utils",
3-
"version": "0.1.1-alpha.46",
3+
"version": "0.1.1-alpha.47",
44
"main": "dist/main.js",
55
"files": [
66
"dist"

web/components/marketplace/app/app-gallery.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ export default function AppGallery() {
143143
<div className="flex flex-col gap-y-2">
144144
<div className="flex flex-col items-center">
145145
<Select
146+
label="Filter apps"
147+
size="sm"
146148
className="w-fit min-w-48"
147149
items={selectLabels}
148150
startContent={

web/components/marketplace/workflow/workflow-gallery.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ export default function WorkflowGallery() {
8484
<div className="flex flex-col gap-y-2">
8585
<div className="flex flex-col items-center">
8686
<Select
87+
label="Filter workflows"
88+
size="sm"
8789
className="w-fit min-w-48"
8890
items={selectLabels}
8991
startContent={

web/lib/hooks/use-canvas-workflow.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export default function useCanvasWorkflow(
3838
ReactFlowNode<AppNodeData> | undefined
3939
>(initialWorkflowContent?.defaultEntryPoint);
4040

41+
const [isRestored, setIsRestored] = useState(false);
42+
4143
// Update entry points
4244
useEffect(() => {
4345
debouncedGetEntryPoint();
@@ -47,14 +49,17 @@ export default function useCanvasWorkflow(
4749
useEffect(() => {
4850
async function restore() {
4951
if (!imcContext) return;
52+
else if (isRestored) return;
53+
else if (!initialWorkflowContent) return;
54+
setIsRestored(true);
5055

51-
if (initialWorkflowContent?.snapshotStates) {
56+
if (initialWorkflowContent.snapshotStates) {
5257
await restoreAppsSnapshotStates(initialWorkflowContent);
5358
}
5459
}
5560

5661
restore();
57-
}, [initialWorkflowContent, imcContext]);
62+
}, [initialWorkflowContent, imcContext, isRestored]);
5863

5964
async function startWorkflow() {
6065
// DAG traversal using Kahn's algorithm (topological sort)

0 commit comments

Comments
 (0)