Skip to content

Commit a76590f

Browse files
committed
Added fix to check if all mandatory fields have value before submittign a credential
1 parent d76b15d commit a76590f

3 files changed

Lines changed: 42 additions & 9 deletions

File tree

packages/agentflow/src/features/node-editor/AsyncInput.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,19 @@ function AsyncOptionsInput({ inputParam, value, disabled, onChange, nodeName, in
3333
const [createDialogOpen, setCreateDialogOpen] = useState(false)
3434
const [editDialogOpen, setEditDialogOpen] = useState(false)
3535
const [reloadKey, setReloadKey] = useState(0)
36+
// Holds the credential ID that was just created/edited. Passed directly to
37+
// the remounted AsyncOptionsDropdown so it doesn't depend on the parent
38+
// state cascade (which may not have flushed yet when inside ConfigInput).
39+
const [pendingValue, setPendingValue] = useState<string | null>(null)
3640

37-
const selectedCredentialId = isCredential && typeof value === 'string' && value ? value : null
41+
const effectiveValue = pendingValue ?? value
42+
const selectedCredentialId = isCredential && typeof effectiveValue === 'string' && effectiveValue ? effectiveValue : null
3843

3944
const handleCreated = useCallback(
4045
(newCredentialId: string) => {
4146
setCreateDialogOpen(false)
4247
onChange(newCredentialId)
43-
// Changing reloadKey forces AsyncOptionsDropdown to remount, which
44-
// re-runs useAsyncOptions and fetches fresh options including the
45-
// newly created credential — matching original Flowise behaviour.
48+
setPendingValue(newCredentialId)
4649
setReloadKey((k) => k + 1)
4750
},
4851
[onChange]
@@ -52,6 +55,7 @@ function AsyncOptionsInput({ inputParam, value, disabled, onChange, nodeName, in
5255
(credentialId: string) => {
5356
setEditDialogOpen(false)
5457
onChange(credentialId)
58+
setPendingValue(credentialId)
5559
setReloadKey((k) => k + 1)
5660
},
5761
[onChange]
@@ -63,9 +67,12 @@ function AsyncOptionsInput({ inputParam, value, disabled, onChange, nodeName, in
6367
<AsyncOptionsDropdown
6468
key={reloadKey}
6569
inputParam={inputParam}
66-
value={value}
70+
value={pendingValue ?? value}
6771
disabled={disabled}
68-
onChange={onChange}
72+
onChange={(v) => {
73+
setPendingValue(null)
74+
onChange(v)
75+
}}
6976
nodeName={nodeName}
7077
inputValues={inputValues}
7178
isCredential={isCredential}

packages/agentflow/src/features/node-editor/CreateCredentialDialog.test.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,25 @@ describe('CreateCredentialDialog', () => {
212212
})
213213
})
214214

215-
it('Add button is enabled when credential name is filled', async () => {
215+
it('Add button is disabled when required fields are empty', async () => {
216216
render(<CreateCredentialDialog {...defaultProps} />)
217217

218218
await waitFor(() => screen.getByPlaceholderText('OpenAI API'))
219219

220+
// Fill credential name but leave required field empty
220221
fireEvent.change(screen.getByPlaceholderText('OpenAI API'), { target: { value: 'My Key' } })
221222

223+
expect(screen.getByText('Add')).toBeDisabled()
224+
})
225+
226+
it('Add button is enabled when credential name and required fields are filled', async () => {
227+
render(<CreateCredentialDialog {...defaultProps} />)
228+
229+
await waitFor(() => screen.getByPlaceholderText('OpenAI API'))
230+
231+
fireEvent.change(screen.getByPlaceholderText('OpenAI API'), { target: { value: 'My Key' } })
232+
fireEvent.change(screen.getByDisplayValue(''), { target: { value: 'sk-test-key' } })
233+
222234
expect(screen.getByText('Add')).not.toBeDisabled()
223235
})
224236

@@ -228,6 +240,7 @@ describe('CreateCredentialDialog', () => {
228240
await waitFor(() => screen.getByPlaceholderText('OpenAI API'))
229241

230242
fireEvent.change(screen.getByPlaceholderText('OpenAI API'), { target: { value: 'My OpenAI Key' } })
243+
fireEvent.change(screen.getByDisplayValue(''), { target: { value: 'sk-test-key' } })
231244

232245
await act(async () => {
233246
fireEvent.click(screen.getByText('Add'))
@@ -236,7 +249,7 @@ describe('CreateCredentialDialog', () => {
236249
expect(mockCreateCredential).toHaveBeenCalledWith({
237250
name: 'My OpenAI Key',
238251
credentialName: 'openAIApi',
239-
plainDataObj: { openAIApiKey: '' }
252+
plainDataObj: { openAIApiKey: 'sk-test-key' }
240253
})
241254
expect(defaultProps.onCreated).toHaveBeenCalledWith('new-cred-123')
242255
})
@@ -248,6 +261,7 @@ describe('CreateCredentialDialog', () => {
248261
await waitFor(() => screen.getByPlaceholderText('OpenAI API'))
249262

250263
fireEvent.change(screen.getByPlaceholderText('OpenAI API'), { target: { value: 'My Key' } })
264+
fireEvent.change(screen.getByDisplayValue(''), { target: { value: 'sk-test-key' } })
251265

252266
await act(async () => {
253267
fireEvent.click(screen.getByText('Add'))

packages/agentflow/src/features/node-editor/CreateCredentialDialog.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ export function CreateCredentialDialog({ open, credentialNames, onClose, onCreat
170170
if (!submitting) onClose()
171171
}, [submitting, onClose])
172172

173+
// Check if all required fields have values
174+
const hasEmptyRequiredFields = selectedSchema?.inputs
175+
?.filter((input) => !input.hidden && !input.optional)
176+
.some((input) => {
177+
const val = formValues[input.name]
178+
return val === undefined || val === null || val === ''
179+
})
180+
173181
// Schema selection step (multiple credential types)
174182
const showSelection = !loading && !selectedSchema && schemas.length > 1
175183

@@ -259,7 +267,11 @@ export function CreateCredentialDialog({ open, credentialNames, onClose, onCreat
259267
Cancel
260268
</Button>
261269
{selectedSchema && (
262-
<Button variant='contained' onClick={handleSubmit} disabled={!credentialName.trim() || submitting}>
270+
<Button
271+
variant='contained'
272+
onClick={handleSubmit}
273+
disabled={!credentialName.trim() || hasEmptyRequiredFields || submitting}
274+
>
263275
{submitting ? (isEditMode ? 'Saving...' : 'Adding...') : isEditMode ? 'Save' : 'Add'}
264276
</Button>
265277
)}

0 commit comments

Comments
 (0)