Skip to content

Commit 2458751

Browse files
authored
fix: prevent empty mode names from being saved (#5766) (#5794)
1 parent a92ee56 commit 2458751

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/core/config/CustomModesManager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,14 @@ export class CustomModesManager {
401401

402402
public async updateCustomMode(slug: string, config: ModeConfig): Promise<void> {
403403
try {
404+
// Validate the mode configuration before saving
405+
const validationResult = modeConfigSchema.safeParse(config)
406+
if (!validationResult.success) {
407+
const errors = validationResult.error.errors.map((e) => e.message).join(", ")
408+
logger.error(`Invalid mode configuration for ${slug}`, { errors: validationResult.error.errors })
409+
throw new Error(`Invalid mode configuration: ${errors}`)
410+
}
411+
404412
const isProjectMode = config.source === "project"
405413
let targetPath: string
406414

webview-ui/src/components/modes/ModesView.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ const ModesView = ({ onDone }: ModesViewProps) => {
110110
const [searchValue, setSearchValue] = useState("")
111111
const searchInputRef = useRef<HTMLInputElement>(null)
112112

113+
// Local state for mode name input to allow visual emptying
114+
const [localModeName, setLocalModeName] = useState<string>("")
115+
const [currentEditingModeSlug, setCurrentEditingModeSlug] = useState<string | null>(null)
116+
113117
// Direct update functions
114118
const updateAgentPrompt = useCallback(
115119
(mode: Mode, promptData: PromptComponent) => {
@@ -218,6 +222,14 @@ const ModesView = ({ onDone }: ModesViewProps) => {
218222
}
219223
}, [getCurrentMode, checkRulesDirectory, hasRulesToExport])
220224

225+
// Reset local name state when mode changes
226+
useEffect(() => {
227+
if (currentEditingModeSlug && currentEditingModeSlug !== visualMode) {
228+
setCurrentEditingModeSlug(null)
229+
setLocalModeName("")
230+
}
231+
}, [visualMode, currentEditingModeSlug])
232+
221233
// Helper function to safely access mode properties
222234
const getModeProperty = <T extends keyof ModeConfig>(
223235
mode: ModeConfig | undefined,
@@ -725,16 +737,34 @@ const ModesView = ({ onDone }: ModesViewProps) => {
725737
<div className="flex gap-2">
726738
<Input
727739
type="text"
728-
value={getModeProperty(findModeBySlug(visualMode, customModes), "name") ?? ""}
729-
onChange={(e) => {
740+
value={
741+
currentEditingModeSlug === visualMode
742+
? localModeName
743+
: (getModeProperty(findModeBySlug(visualMode, customModes), "name") ??
744+
"")
745+
}
746+
onFocus={() => {
730747
const customMode = findModeBySlug(visualMode, customModes)
731748
if (customMode) {
749+
setCurrentEditingModeSlug(visualMode)
750+
setLocalModeName(customMode.name)
751+
}
752+
}}
753+
onChange={(e) => {
754+
setLocalModeName(e.target.value)
755+
}}
756+
onBlur={() => {
757+
const customMode = findModeBySlug(visualMode, customModes)
758+
if (customMode && localModeName.trim()) {
759+
// Only update if the name is not empty
732760
updateCustomMode(visualMode, {
733761
...customMode,
734-
name: e.target.value,
762+
name: localModeName,
735763
source: customMode.source || "global",
736764
})
737765
}
766+
// Clear the editing state
767+
setCurrentEditingModeSlug(null)
738768
}}
739769
className="w-full"
740770
/>

0 commit comments

Comments
 (0)