Fix editor showing unsaved changes when switching conditional branches (#4588)
This commit is contained in:
@@ -857,9 +857,14 @@ function FlowRenderer({
|
|||||||
doLayout(tempNodes, edges);
|
doLayout(tempNodes, edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only track changes after initial load is complete
|
// Only track changes after initial load is complete and not during internal updates
|
||||||
|
// (e.g., switching conditional branches which is UI state, not workflow data)
|
||||||
|
// Use getState() to get real-time value (not stale closure from render time)
|
||||||
|
const isInternalUpdate =
|
||||||
|
useWorkflowHasChangesStore.getState().isInternalUpdate;
|
||||||
if (
|
if (
|
||||||
!isInitialLoadRef.current &&
|
!isInitialLoadRef.current &&
|
||||||
|
!isInternalUpdate &&
|
||||||
changes.some((change) => {
|
changes.some((change) => {
|
||||||
return (
|
return (
|
||||||
change.type === "add" ||
|
change.type === "add" ||
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { cn } from "@/util/utils";
|
import { cn } from "@/util/utils";
|
||||||
|
import { useWorkflowHasChangesStore } from "@/store/WorkflowHasChangesStore";
|
||||||
import { useUpdate } from "../../useUpdate";
|
import { useUpdate } from "../../useUpdate";
|
||||||
import { NodeHeader } from "../components/NodeHeader";
|
import { NodeHeader } from "../components/NodeHeader";
|
||||||
import { AppNode, isWorkflowBlockNode } from "..";
|
import { AppNode, isWorkflowBlockNode } from "..";
|
||||||
@@ -44,6 +45,7 @@ function ConditionalNodeComponent({ id, data }: NodeProps<ConditionalNode>) {
|
|||||||
const nodes = useNodes<AppNode>();
|
const nodes = useNodes<AppNode>();
|
||||||
const { setNodes, setEdges } = useReactFlow();
|
const { setNodes, setEdges } = useReactFlow();
|
||||||
const node = nodes.find((n) => n.id === id);
|
const node = nodes.find((n) => n.id === id);
|
||||||
|
const { setIsInternalUpdate } = useWorkflowHasChangesStore();
|
||||||
|
|
||||||
const update = useUpdate<ConditionalNodeData>({
|
const update = useUpdate<ConditionalNodeData>({
|
||||||
id,
|
id,
|
||||||
@@ -109,11 +111,17 @@ function ConditionalNodeComponent({ id, data }: NodeProps<ConditionalNode>) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data.activeBranchId && orderedBranches.length > 0) {
|
if (!data.activeBranchId && orderedBranches.length > 0) {
|
||||||
|
// Mark as internal update to prevent triggering "unsaved changes" dialog
|
||||||
|
setIsInternalUpdate(true);
|
||||||
update({
|
update({
|
||||||
activeBranchId: orderedBranches[0]?.id ?? null,
|
activeBranchId: orderedBranches[0]?.id ?? null,
|
||||||
});
|
});
|
||||||
|
// Clear the flag after layout completes
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsInternalUpdate(false);
|
||||||
|
}, 50);
|
||||||
}
|
}
|
||||||
}, [data.activeBranchId, orderedBranches, update]);
|
}, [data.activeBranchId, orderedBranches, update, setIsInternalUpdate]);
|
||||||
|
|
||||||
// Toggle visibility of branch nodes/edges when activeBranchId changes
|
// Toggle visibility of branch nodes/edges when activeBranchId changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -271,7 +279,14 @@ function ConditionalNodeComponent({ id, data }: NodeProps<ConditionalNode>) {
|
|||||||
if (!data.editable) {
|
if (!data.editable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Mark as internal update to prevent triggering "unsaved changes" dialog
|
||||||
|
// Switching branches is UI state, not actual workflow data changes
|
||||||
|
setIsInternalUpdate(true);
|
||||||
update({ activeBranchId: branchId });
|
update({ activeBranchId: branchId });
|
||||||
|
// Clear the flag after layout completes (layout uses setTimeout(10))
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsInternalUpdate(false);
|
||||||
|
}, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveBranch = (branchId: string) => {
|
const handleRemoveBranch = (branchId: string) => {
|
||||||
|
|||||||
@@ -31,11 +31,13 @@ type WorkflowHasChangesStore = {
|
|||||||
saveIsPending: boolean;
|
saveIsPending: boolean;
|
||||||
saidOkToCodeCacheDeletion: boolean;
|
saidOkToCodeCacheDeletion: boolean;
|
||||||
showConfirmCodeCacheDeletion: boolean;
|
showConfirmCodeCacheDeletion: boolean;
|
||||||
|
isInternalUpdate: boolean;
|
||||||
setGetSaveData: (getSaveData: () => SaveData) => void;
|
setGetSaveData: (getSaveData: () => SaveData) => void;
|
||||||
setHasChanges: (hasChanges: boolean) => void;
|
setHasChanges: (hasChanges: boolean) => void;
|
||||||
setSaveIsPending: (isPending: boolean) => void;
|
setSaveIsPending: (isPending: boolean) => void;
|
||||||
setSaidOkToCodeCacheDeletion: (saidOkToCodeCacheDeletion: boolean) => void;
|
setSaidOkToCodeCacheDeletion: (saidOkToCodeCacheDeletion: boolean) => void;
|
||||||
setShowConfirmCodeCacheDeletion: (show: boolean) => void;
|
setShowConfirmCodeCacheDeletion: (show: boolean) => void;
|
||||||
|
setIsInternalUpdate: (isInternalUpdate: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface WorkflowSaveOpts {
|
interface WorkflowSaveOpts {
|
||||||
@@ -48,6 +50,7 @@ const useWorkflowHasChangesStore = create<WorkflowHasChangesStore>((set) => {
|
|||||||
saveIsPending: false,
|
saveIsPending: false,
|
||||||
saidOkToCodeCacheDeletion: false,
|
saidOkToCodeCacheDeletion: false,
|
||||||
showConfirmCodeCacheDeletion: false,
|
showConfirmCodeCacheDeletion: false,
|
||||||
|
isInternalUpdate: false,
|
||||||
getSaveData: () => null,
|
getSaveData: () => null,
|
||||||
setGetSaveData: (getSaveData: () => SaveData) => {
|
setGetSaveData: (getSaveData: () => SaveData) => {
|
||||||
set({ getSaveData });
|
set({ getSaveData });
|
||||||
@@ -64,6 +67,9 @@ const useWorkflowHasChangesStore = create<WorkflowHasChangesStore>((set) => {
|
|||||||
setShowConfirmCodeCacheDeletion: (show: boolean) => {
|
setShowConfirmCodeCacheDeletion: (show: boolean) => {
|
||||||
set({ showConfirmCodeCacheDeletion: show });
|
set({ showConfirmCodeCacheDeletion: show });
|
||||||
},
|
},
|
||||||
|
setIsInternalUpdate: (isInternalUpdate: boolean) => {
|
||||||
|
set({ isInternalUpdate });
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user