fix(ui): prevent duplicate chatflow creation on rapid save clicks#6611
fix(ui): prevent duplicate chatflow creation on rapid save clicks#6611iruzen-dono wants to merge 1 commit into
Conversation
When users click the Save/Create button multiple times in quick succession before the first API request completes, multiple chatflows are created. Fix by: 1. Adding a `loading` prop to SaveChatflowDialog that disables the confirm button while the save request is in progress 2. Tracking saving state in CanvasHeader and passing it to the dialog 3. Preventing dialog close while save is in progress Fixes FlowiseAI#6502
There was a problem hiding this comment.
Code Review
This pull request introduces a loading state to the SaveChatflowDialog component to prevent multiple submissions and disable interactions while a save operation is in progress. The reviewer suggests keeping the dialog open if the save operation fails, rather than closing it unconditionally in the .finally() block, to prevent the user from losing their input.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (savePromise && typeof savePromise.then === 'function') { | ||
| savePromise.finally(() => { | ||
| setFlowDialogOpen(false) | ||
| setFlowDialogLoading(false) | ||
| }) | ||
| } else { | ||
| setFlowDialogOpen(false) | ||
| setFlowDialogLoading(false) | ||
| } |
There was a problem hiding this comment.
If the save operation fails (i.e., the promise rejects), closing the dialog will cause the user to lose the flow name they just typed. It is better to keep the dialog open on failure so the user can correct any issues or try again, and only close it on a successful save.
if (savePromise && typeof savePromise.then === 'function') {
savePromise
.then(() => {
setFlowDialogOpen(false)
})
.catch(() => {
// Keep dialog open on error so user doesn't lose input
})
.finally(() => {
setFlowDialogLoading(false)
})
} else {
setFlowDialogOpen(false)
setFlowDialogLoading(false)
}There was a problem hiding this comment.
Pull request overview
This PR addresses a UI race where rapidly clicking Save/Create in the save-name dialog can trigger multiple chatflow creation requests by introducing a dialog-level loading state and wiring it into the canvas header save flow.
Changes:
- Added a
loadingprop toSaveChatflowDialogto disable confirm (and Enter) while a save is in flight, and disable cancel during loading. - Added
flowDialogLoadingstate inCanvasHeaderand attempted to keep the dialog disabled untilhandleSaveFlowcompletes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/ui/src/views/canvas/CanvasHeader.jsx | Tracks save-dialog loading state and attempts to close/reset it when handleSaveFlow completes. |
| packages/ui/src/ui-component/dialog/SaveChatflowDialog.jsx | Adds loading support to disable confirm/enter and cancel while saving. |
Comments suppressed due to low confidence (1)
packages/ui/src/ui-component/dialog/SaveChatflowDialog.jsx:27
- The new
loadingprop disables the Cancel button, but the dialog can still be closed via backdrop click or Escape becauseDialogalways callsonClose={onCancel}. This can defeat the “prevent closing while saving” guarantee unless every caller wrapsonCancel. GuardonClosebased onloadingand disable Escape while loading.
<Dialog
open={show}
fullWidth
maxWidth='xs'
onClose={onCancel}
aria-labelledby='alert-dialog-title'
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const onConfirmSaveName = (flowName) => { | ||
| setFlowDialogOpen(false) | ||
| setFlowDialogLoading(true) | ||
| setSavePermission(isAgentCanvas ? 'agentflows:update' : 'chatflows:update') | ||
| handleSaveFlow(flowName) | ||
| const savePromise = handleSaveFlow(flowName) | ||
| if (savePromise && typeof savePromise.then === 'function') { |
| const savePromise = handleSaveFlow(flowName) | ||
| if (savePromise && typeof savePromise.then === 'function') { | ||
| savePromise.finally(() => { | ||
| setFlowDialogOpen(false) | ||
| setFlowDialogLoading(false) |
What
Prevents multiple chatflows from being created when the Save/Create button is clicked repeatedly.
Root cause
The save dialog button has no loading state — it fires
onConfirmon every click regardless of whether a save request is already in flight.Fix
loadingprop — when true, the confirm button and Enter key are disabled, and the cancel button is also disabled to prevent closing while savingflowDialogLoadingstate — set to true when save starts, waits forhandleSaveFlowto resolve (if it returns a promise), then resetsReferences
Closes #6502