Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -591,12 +591,11 @@ export function DeployModal({
)}
{activeTab === 'api' && (
<ModalFooter className='items-center justify-between'>
<div>
<div />
<div className='flex items-center gap-2'>
<Button variant='default' onClick={() => setIsApiInfoModalOpen(true)}>
Edit API Info
</Button>
</div>
<div className='flex items-center gap-2'>
<Button
variant='tertiary'
onClick={() => setIsCreateKeyModalOpen(true)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function CodeEditor({
placeholder = '',
className = '',
gutterClassName = '',
minHeight = '360px',
minHeight,
highlightVariables = true,
onKeyDown,
disabled = false,
Expand Down Expand Up @@ -186,7 +186,7 @@ export function CodeEditor({
}

return (
<Code.Container className={className} style={{ minHeight }}>
<Code.Container className={className} style={minHeight ? { minHeight } : undefined}>
{showWandButton && onWandClick && (
<Button
variant='ghost'
Expand Down Expand Up @@ -220,7 +220,7 @@ export function CodeEditor({
disabled={disabled}
{...getCodeEditorProps({ disabled })}
className={cn(getCodeEditorProps({ disabled }).className, 'h-full')}
style={{ minHeight }}
style={minHeight ? { minHeight } : undefined}
textareaClassName={cn(
getCodeEditorProps({ disabled }).textareaClassName,
'!block !h-full !min-h-full'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ export function CustomToolModal({
const [codeError, setCodeError] = useState<string | null>(null)
const [isEditing, setIsEditing] = useState(false)
const [toolId, setToolId] = useState<string | undefined>(undefined)
const [initialJsonSchema, setInitialJsonSchema] = useState('')
const [initialFunctionCode, setInitialFunctionCode] = useState('')
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
const [isSchemaPromptActive, setIsSchemaPromptActive] = useState(false)
const [schemaPromptInput, setSchemaPromptInput] = useState('')
const [schemaPromptSummary, setSchemaPromptSummary] = useState<string | null>(null)
const schemaPromptInputRef = useRef<HTMLInputElement | null>(null)

const [isCodePromptActive, setIsCodePromptActive] = useState(false)
const [codePromptInput, setCodePromptInput] = useState('')
const [codePromptSummary, setCodePromptSummary] = useState<string | null>(null)
const codePromptInputRef = useRef<HTMLInputElement | null>(null)

const schemaGeneration = useWand({
Expand Down Expand Up @@ -272,12 +272,15 @@ try {

if (initialValues) {
try {
setJsonSchema(
const schemaValue =
typeof initialValues.schema === 'string'
? initialValues.schema
: JSON.stringify(initialValues.schema, null, 2)
)
setFunctionCode(initialValues.code || '')
const codeValue = initialValues.code || ''
setJsonSchema(schemaValue)
setFunctionCode(codeValue)
setInitialJsonSchema(schemaValue)
setInitialFunctionCode(codeValue)
setIsEditing(true)
setToolId(initialValues.id)
} catch (error) {
Expand All @@ -304,13 +307,13 @@ try {
const resetForm = () => {
setJsonSchema('')
setFunctionCode('')
setInitialJsonSchema('')
setInitialFunctionCode('')
setSchemaError(null)
setCodeError(null)
setActiveSection('schema')
setIsEditing(false)
setToolId(undefined)
setSchemaPromptSummary(null)
setCodePromptSummary(null)
setIsSchemaPromptActive(false)
setIsCodePromptActive(false)
setSchemaPromptInput('')
Expand Down Expand Up @@ -376,6 +379,11 @@ try {

const isSchemaValid = useMemo(() => validateJsonSchema(jsonSchema), [jsonSchema])

const hasChanges = useMemo(() => {
if (!isEditing) return true
return jsonSchema !== initialJsonSchema || functionCode !== initialFunctionCode
}, [isEditing, jsonSchema, initialJsonSchema, functionCode, initialFunctionCode])

const handleSave = async () => {
try {
if (!jsonSchema) {
Expand Down Expand Up @@ -483,17 +491,9 @@ try {
}

onSave(customTool)

setSchemaPromptSummary(null)
setCodePromptSummary(null)

handleClose()
} catch (error) {
logger.error('Error saving custom tool:', { error })

setSchemaPromptSummary(null)
setCodePromptSummary(null)

const errorMessage = error instanceof Error ? error.message : 'Failed to save custom tool'

if (errorMessage.includes('Cannot change function name')) {
Expand Down Expand Up @@ -667,6 +667,41 @@ try {
}
}

// Global keyboard handler for schema params dropdown (like EnvVarDropdown)
useEffect(() => {
if (!showSchemaParams || schemaParameters.length === 0) return

const handleKeyboardEvent = (e: KeyboardEvent) => {
switch (e.key) {
case 'ArrowDown':
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.min(prev + 1, schemaParameters.length - 1))
break
case 'ArrowUp':
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.max(prev - 1, 0))
break
case 'Enter':
e.preventDefault()
e.stopPropagation()
if (schemaParamSelectedIndex >= 0 && schemaParamSelectedIndex < schemaParameters.length) {
handleSchemaParamSelect(schemaParameters[schemaParamSelectedIndex].name)
}
break
case 'Escape':
e.preventDefault()
e.stopPropagation()
setShowSchemaParams(false)
break
}
}

window.addEventListener('keydown', handleKeyboardEvent, true)
return () => window.removeEventListener('keydown', handleKeyboardEvent, true)
}, [showSchemaParams, schemaParamSelectedIndex, schemaParameters])
Comment thread
waleedlatif1 marked this conversation as resolved.
Outdated
Comment thread
waleedlatif1 marked this conversation as resolved.
Outdated

const handleKeyDown = (e: React.KeyboardEvent) => {
const isSchemaPromptVisible = activeSection === 'schema' && schemaGeneration.isPromptVisible
const isCodePromptVisible = activeSection === 'code' && codeGeneration.isPromptVisible
Expand Down Expand Up @@ -709,27 +744,32 @@ try {
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.min(prev + 1, schemaParameters.length - 1))
break
return
case 'ArrowUp':
e.preventDefault()
e.stopPropagation()
setSchemaParamSelectedIndex((prev) => Math.max(prev - 1, 0))
break
return
case 'Enter':
e.preventDefault()
e.stopPropagation()
if (schemaParamSelectedIndex >= 0 && schemaParamSelectedIndex < schemaParameters.length) {
const selectedParam = schemaParameters[schemaParamSelectedIndex]
handleSchemaParamSelect(selectedParam.name)
}
break
return
case 'Escape':
e.preventDefault()
e.stopPropagation()
setShowSchemaParams(false)
return
case ' ':
case 'Tab':
// Close dropdown but let the key event continue (don't prevent default)
// This allows the space/tab character to be typed normally
setShowSchemaParams(false)
break
Comment thread
waleedlatif1 marked this conversation as resolved.
Outdated
}
return
}

if (showEnvVars || showTags) {
Expand All @@ -743,7 +783,7 @@ try {
const handleSchemaWandClick = () => {
if (schemaGeneration.isLoading || schemaGeneration.isStreaming) return
setIsSchemaPromptActive(true)
setSchemaPromptInput(schemaPromptSummary ?? '')
setSchemaPromptInput('')
setTimeout(() => {
schemaPromptInputRef.current?.focus()
}, 0)
Expand All @@ -762,7 +802,6 @@ try {
const handleSchemaPromptSubmit = () => {
const trimmedPrompt = schemaPromptInput.trim()
if (!trimmedPrompt || schemaGeneration.isLoading || schemaGeneration.isStreaming) return
setSchemaPromptSummary(trimmedPrompt)
schemaGeneration.generateStream({ prompt: trimmedPrompt })
setSchemaPromptInput('')
setIsSchemaPromptActive(false)
Expand All @@ -782,7 +821,7 @@ try {
const handleCodeWandClick = () => {
if (codeGeneration.isLoading || codeGeneration.isStreaming) return
setIsCodePromptActive(true)
setCodePromptInput(codePromptSummary ?? '')
setCodePromptInput('')
setTimeout(() => {
codePromptInputRef.current?.focus()
}, 0)
Expand All @@ -801,7 +840,6 @@ try {
const handleCodePromptSubmit = () => {
const trimmedPrompt = codePromptInput.trim()
if (!trimmedPrompt || codeGeneration.isLoading || codeGeneration.isStreaming) return
setCodePromptSummary(trimmedPrompt)
codeGeneration.generateStream({ prompt: trimmedPrompt })
setCodePromptInput('')
setIsCodePromptActive(false)
Expand Down Expand Up @@ -1130,6 +1168,30 @@ try {
collisionPadding={6}
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
onKeyDown={(e) => {
if (e.key === 'ArrowDown') {
e.preventDefault()
setSchemaParamSelectedIndex((prev) =>
Math.min(prev + 1, schemaParameters.length - 1)
)
} else if (e.key === 'ArrowUp') {
e.preventDefault()
setSchemaParamSelectedIndex((prev) => Math.max(prev - 1, 0))
} else if (e.key === 'Enter') {
e.preventDefault()
if (
schemaParamSelectedIndex >= 0 &&
schemaParamSelectedIndex < schemaParameters.length
) {
handleSchemaParamSelect(
schemaParameters[schemaParamSelectedIndex].name
)
}
} else if (e.key === 'Escape') {
e.preventDefault()
setShowSchemaParams(false)
}
}}
>
<PopoverScrollArea>
<PopoverSection>Available Parameters</PopoverSection>
Expand Down Expand Up @@ -1211,7 +1273,7 @@ try {
<Button
variant='tertiary'
onClick={handleSave}
disabled={!isSchemaValid || !!schemaError}
disabled={!isSchemaValid || !!schemaError || !hasChanges}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancel button bypasses unsaved changes confirmation

Medium Severity

The Cancel buttons call handleClose directly instead of handleCloseAttempt, bypassing the newly-added unsaved changes confirmation. This creates inconsistent behavior where pressing Escape or clicking outside shows a discard confirmation dialog, but clicking Cancel closes immediately without warning, potentially causing users to lose their work unexpectedly.

Additional Locations (1)

Fix in Cursor Fix in Web

>
{isEditing ? 'Update Tool' : 'Save Tool'}
</Button>
Expand Down