fix: prevent empty mode names from being saved (fixes #5766) (#5767)

* fix: prevent empty mode names from being saved (fixes #5766)

- Add frontend validation in ModesView to prevent empty names from being saved
- Add onBlur handler to restore original name if field is left empty
- Add backend validation in CustomModesManager.updateCustomMode using modeConfigSchema
- Provide user feedback when validation fails
- Trim whitespace from mode names before validation

This prevents YAML parsing errors caused by empty mode name fields.

* fix: improve UX by allowing users to empty mode name field

- Remove restriction that prevented users from emptying the name field
- Remove onBlur handler that automatically restored original name
- Allow backend validation to handle empty names and show appropriate errors
- Users can now type freely but invalid saves are prevented by backend validation

Addresses feedback from @daniel-lxs in PR #5767

* fix: allow emptying mode name field but prevent saving when invalid

- Modified onBlur handler to check if name is empty before saving
- If empty, revert to original name instead of saving empty value
- This provides better UX as requested in PR review

* fix: add proper JSON formatting to source map writes for Windows compatibility

---------

Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
roomote[bot] 2025-08-04 11:03:34 -07:00 • committed by GitHub
parent c34e412771
commit 7ca4901024
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 25 additions and 13 deletions

View file

@ -405,9 +405,13 @@ export class CustomModesManager {
// Validate the mode configuration before saving
const validationResult = modeConfigSchema.safeParse(config)
if (!validationResult.success) {
const errors = validationResult.error.errors.map((e) => e.message).join(", ")
logger.error(`Invalid mode configuration for ${slug}`, { errors: validationResult.error.errors })
throw new Error(`Invalid mode configuration: ${errors}`)
const errorMessages = validationResult.error.errors
.map((err) => `${err.path.join(".")}: ${err.message}`)
.join(", ")
const errorMessage = `Invalid mode configuration: ${errorMessages}`
logger.error("Mode validation failed", { slug, errors: validationResult.error.errors })
vscode.window.showErrorMessage(t("common:customModes.errors.updateFailed", { error: errorMessage }))
return
}
const isProjectMode = config.source === "project"
@ -786,7 +790,7 @@ export class CustomModesManager {
// This excludes the rules-{slug} folder from the path
const relativePath = path.relative(modeRulesDir, filePath)
// Normalize path to use forward slashes for cross-platform compatibility
const normalizedRelativePath = relativePath.replace(/\\/g, '/')
const normalizedRelativePath = relativePath.replace(/\\/g, "/")
rulesFiles.push({ relativePath: normalizedRelativePath, content: content.trim() })
}
}

View file

@ -755,17 +755,25 @@ const ModesView = ({ onDone }: ModesViewProps) => {
}
}}
onChange={(e) => {
setLocalModeName(e.target.value)
const newName = e.target.value
// Allow users to type freely, including emptying the field
setLocalModeName(newName)
}}
onBlur={() => {
const customMode = findModeBySlug(visualMode, customModes)
if (customMode && localModeName.trim()) {
if (customMode) {
const trimmedName = localModeName.trim()
// Only update if the name is not empty
updateCustomMode(visualMode, {
...customMode,
name: localModeName,
source: customMode.source || "global",
})
if (trimmedName) {
updateCustomMode(visualMode, {
...customMode,
name: trimmedName,
source: customMode.source || "global",
})
} else {
// Revert to the original name if empty
setLocalModeName(customMode.name)
}
}
// Clear the editing state
setCurrentEditingModeSlug(null)

View file

@ -88,8 +88,8 @@ export function sourcemapPlugin(): Plugin {
})
}
// Write back the updated source map
fs.writeFileSync(mapPath, JSON.stringify(mapContent))
// Write back the updated source map with proper formatting
fs.writeFileSync(mapPath, JSON.stringify(mapContent, null, 2))
console.log(`Updated source map for ${jsFile}`)
} catch (error) {
console.error(`Error processing source map for ${jsFile}:`, error)