@@ -19,6 +19,7 @@ import {
1919 ModeConfig ,
2020 GroupEntry ,
2121} from "../../../../src/shared/modes"
22+ import { CustomModeSchema } from "../../../../src/core/config/CustomModesSchema"
2223import {
2324 supportPrompt ,
2425 SupportPromptType ,
@@ -157,15 +158,34 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
157158 const [ newModeGroups , setNewModeGroups ] = useState < GroupEntry [ ] > ( availableGroups )
158159 const [ newModeSource , setNewModeSource ] = useState < ModeSource > ( "global" )
159160
161+ // Field-specific error states
162+ const [ nameError , setNameError ] = useState < string > ( "" )
163+ const [ slugError , setSlugError ] = useState < string > ( "" )
164+ const [ roleDefinitionError , setRoleDefinitionError ] = useState < string > ( "" )
165+ const [ groupsError , setGroupsError ] = useState < string > ( "" )
166+
167+ // Helper to reset form state
168+ const resetFormState = useCallback ( ( ) => {
169+ // Reset form fields
170+ setNewModeName ( "" )
171+ setNewModeSlug ( "" )
172+ setNewModeGroups ( availableGroups )
173+ setNewModeRoleDefinition ( "" )
174+ setNewModeCustomInstructions ( "" )
175+ setNewModeSource ( "global" )
176+ // Reset error states
177+ setNameError ( "" )
178+ setSlugError ( "" )
179+ setRoleDefinitionError ( "" )
180+ setGroupsError ( "" )
181+ } , [ ] )
182+
160183 // Reset form fields when dialog opens
161184 useEffect ( ( ) => {
162185 if ( isCreateModeDialogOpen ) {
163- setNewModeGroups ( availableGroups )
164- setNewModeRoleDefinition ( "" )
165- setNewModeCustomInstructions ( "" )
166- setNewModeSource ( "global" )
186+ resetFormState ( )
167187 }
168- } , [ isCreateModeDialogOpen ] )
188+ } , [ isCreateModeDialogOpen , resetFormState ] )
169189
170190 // Helper function to generate a unique slug from a name
171191 const generateSlug = useCallback ( ( name : string , attempt = 0 ) : string => {
@@ -186,26 +206,52 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
186206 )
187207
188208 const handleCreateMode = useCallback ( ( ) => {
189- if ( ! newModeName . trim ( ) || ! newModeSlug . trim ( ) ) return
209+ // Clear previous errors
210+ setNameError ( "" )
211+ setSlugError ( "" )
212+ setRoleDefinitionError ( "" )
213+ setGroupsError ( "" )
190214
191215 const source = newModeSource
192216 const newMode : ModeConfig = {
193217 slug : newModeSlug ,
194218 name : newModeName ,
195- roleDefinition : newModeRoleDefinition . trim ( ) || "" ,
219+ roleDefinition : newModeRoleDefinition . trim ( ) ,
196220 customInstructions : newModeCustomInstructions . trim ( ) || undefined ,
197221 groups : newModeGroups ,
198222 source,
199223 }
224+
225+ // Validate the mode against the schema
226+ const result = CustomModeSchema . safeParse ( newMode )
227+ if ( ! result . success ) {
228+ // Map Zod errors to specific fields
229+ result . error . errors . forEach ( ( error ) => {
230+ const field = error . path [ 0 ] as string
231+ const message = error . message
232+
233+ switch ( field ) {
234+ case "name" :
235+ setNameError ( message )
236+ break
237+ case "slug" :
238+ setSlugError ( message )
239+ break
240+ case "roleDefinition" :
241+ setRoleDefinitionError ( message )
242+ break
243+ case "groups" :
244+ setGroupsError ( message )
245+ break
246+ }
247+ } )
248+ return
249+ }
250+
200251 updateCustomMode ( newModeSlug , newMode )
201252 switchMode ( newModeSlug )
202253 setIsCreateModeDialogOpen ( false )
203- setNewModeName ( "" )
204- setNewModeSlug ( "" )
205- setNewModeRoleDefinition ( "" )
206- setNewModeCustomInstructions ( "" )
207- setNewModeGroups ( availableGroups )
208- setNewModeSource ( "global" )
254+ resetFormState ( )
209255 // eslint-disable-next-line react-hooks/exhaustive-deps
210256 } , [
211257 newModeName ,
@@ -431,7 +477,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
431477
432478 < div className = "mt-5" >
433479 < div onClick = { ( e ) => e . stopPropagation ( ) } className = "flex justify-between items-center mb-3" >
434- < h3 className = "text-vscode-foreground m-0" > Mode-Specific Prompts </ h3 >
480+ < h3 className = "text-vscode-foreground m-0" > Modes </ h3 >
435481 < div className = "flex gap-2" >
436482 < VSCodeButton appearance = "icon" onClick = { openCreateModeDialog } title = "Create new mode" >
437483 < span className = "codicon codicon-add" > </ span >
@@ -727,7 +773,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
727773 alignItems : "center" ,
728774 marginBottom : "4px" ,
729775 } } >
730- < div style = { { fontWeight : "bold" } } > Mode-specific Custom Instructions</ div >
776+ < div style = { { fontWeight : "bold" } } > Mode-specific Custom Instructions (optional) </ div >
731777 { ! findModeBySlug ( mode , customModes ) && (
732778 < VSCodeButton
733779 appearance = "icon"
@@ -1069,6 +1115,9 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
10691115 } }
10701116 style = { { width : "100%" } }
10711117 />
1118+ { nameError && (
1119+ < div className = "text-xs text-vscode-errorForeground mt-1" > { nameError } </ div >
1120+ ) }
10721121 </ div >
10731122 < div style = { { marginBottom : "16px" } } >
10741123 < div style = { { fontWeight : "bold" , marginBottom : "4px" } } > Slug</ div >
@@ -1091,6 +1140,9 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
10911140 The slug is used in URLs and file names. It should be lowercase and contain only
10921141 letters, numbers, and hyphens.
10931142 </ div >
1143+ { slugError && (
1144+ < div className = "text-xs text-vscode-errorForeground mt-1" > { slugError } </ div >
1145+ ) }
10941146 </ div >
10951147 < div style = { { marginBottom : "16px" } } >
10961148 < div style = { { fontWeight : "bold" , marginBottom : "4px" } } > Save Location</ div >
@@ -1147,6 +1199,11 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
11471199 resize = "vertical"
11481200 style = { { width : "100%" } }
11491201 />
1202+ { roleDefinitionError && (
1203+ < div className = "text-xs text-vscode-errorForeground mt-1" >
1204+ { roleDefinitionError }
1205+ </ div >
1206+ ) }
11501207 </ div >
11511208 < div style = { { marginBottom : "16px" } } >
11521209 < div style = { { fontWeight : "bold" , marginBottom : "4px" } } > Available Tools</ div >
@@ -1184,9 +1241,14 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
11841241 </ VSCodeCheckbox >
11851242 ) ) }
11861243 </ div >
1244+ { groupsError && (
1245+ < div className = "text-xs text-vscode-errorForeground mt-1" > { groupsError } </ div >
1246+ ) }
11871247 </ div >
11881248 < div style = { { marginBottom : "16px" } } >
1189- < div style = { { fontWeight : "bold" , marginBottom : "4px" } } > Custom Instructions</ div >
1249+ < div style = { { fontWeight : "bold" , marginBottom : "4px" } } >
1250+ Custom Instructions (optional)
1251+ </ div >
11901252 < div
11911253 style = { {
11921254 fontSize : "13px" ,
@@ -1219,10 +1281,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
12191281 backgroundColor : "var(--vscode-editor-background)" ,
12201282 } } >
12211283 < VSCodeButton onClick = { ( ) => setIsCreateModeDialogOpen ( false ) } > Cancel</ VSCodeButton >
1222- < VSCodeButton
1223- appearance = "primary"
1224- onClick = { handleCreateMode }
1225- disabled = { ! newModeName . trim ( ) || ! newModeSlug . trim ( ) } >
1284+ < VSCodeButton appearance = "primary" onClick = { handleCreateMode } >
12261285 Create Mode
12271286 </ VSCodeButton >
12281287 </ div >
0 commit comments