1- import { AppBar , Box , Grid , Tab , Tabs , Typography } from '@mui/material'
1+ import { AppBar , Box , Grid , Tab , Tabs , Tooltip , Typography } from '@mui/material'
22import { TextField } from 'components/forms/TextField'
33import { Autocomplete } from 'components/forms/Autocomplete'
44import { AutoResizableTextarea } from 'components/forms/TextArea'
@@ -8,7 +8,7 @@ import React, { useEffect, useState } from 'react'
88import { FormProvider , Resolver , useForm } from 'react-hook-form'
99import { yupResolver } from '@hookform/resolvers/yup'
1010import { Redirect , RouteComponentProps } from 'react-router-dom'
11- import { isEqual } from 'lodash'
11+ import { isEmpty , isEqual } from 'lodash'
1212import {
1313 CreateAplAgentApiArg ,
1414 useCreateAplAgentMutation ,
@@ -60,9 +60,24 @@ export default function AgentsCreateEditPage({
6060
6161 const [ tab , setTab ] = useState ( 0 )
6262 const handleTabChange = ( event , newTab ) => {
63- setTab ( newTab )
63+ setTab ( newTab as number )
6464 }
6565
66+ const tabHasErrors = ( tabIndex : number ) : boolean => {
67+ switch ( tabIndex ) {
68+ case 0 : // Settings tab
69+ return ! ! ( errors . metadata ?. name || errors . spec ?. foundationModel )
70+ case 1 : // Playground tab
71+ return ! ! errors . spec ?. agentInstructions
72+ case 2 : // Workflow resources tab
73+ return ! ! ( errors . spec ?. tools || errors . spec ?. routes )
74+ default :
75+ return false
76+ }
77+ }
78+
79+ const DEFAULT_AGENT_INSTRUCTIONS = 'You are a helpful assistant. Give clear answers to the users.'
80+
6681 type FormType = CreateAplAgentApiArg [ 'body' ]
6782
6883 const defaultValues : FormType = {
@@ -90,6 +105,7 @@ export default function AgentsCreateEditPage({
90105 watch,
91106 formState : { errors } ,
92107 setValue,
108+ trigger,
93109 } = methods
94110
95111 useEffect ( ( ) => {
@@ -103,6 +119,17 @@ export default function AgentsCreateEditPage({
103119 else create ( { teamId, body } )
104120 }
105121
122+ const handleFormSubmit = async ( ) => {
123+ const formData = watch ( )
124+ if ( isEmpty ( formData . spec . agentInstructions ) ) {
125+ setValue ( 'spec.agentInstructions' , DEFAULT_AGENT_INSTRUCTIONS )
126+ await trigger ( 'spec.agentInstructions' )
127+ }
128+ handleSubmit ( onSubmit ) ( )
129+ }
130+
131+ const requiredFieldsFilled = ! ! watch ( 'metadata.name' ) && ! ! watch ( 'spec.foundationModel' )
132+
106133 const mutating = isLoadingCreate || isLoadingUpdate || isLoadingDelete
107134 if ( ! mutating && ( isSuccessCreate || isSuccessUpdate || isSuccessDelete ) )
108135 return < Redirect to = { `/teams/${ teamId } /agents` } />
@@ -111,6 +138,48 @@ export default function AgentsCreateEditPage({
111138
112139 if ( loading ) return < PaperLayout loading title = { t ( 'TITLE_AGENT' ) } />
113140
141+ const formButtons = (
142+ < Box >
143+ { agentName && (
144+ < DeleteButton
145+ onDelete = { ( ) => del ( { teamId, agentName } ) }
146+ resourceName = { watch ( 'metadata.name' ) }
147+ resourceType = 'agent'
148+ data-cy = 'button-delete-agent'
149+ sx = { { float : 'right' , textTransform : 'capitalize' , ml : 2 } }
150+ loading = { isLoadingDelete }
151+ disabled = { isLoadingDelete || isLoadingCreate || isLoadingUpdate }
152+ />
153+ ) }
154+ < Tooltip
155+ title = {
156+ ! agentName && ! requiredFieldsFilled
157+ ? 'Please fill in required fields: Agent name, Foundation model, and Instructions'
158+ : ''
159+ }
160+ >
161+ < Box sx = { { float : 'right' } } >
162+ < LoadingButton
163+ onClick = { handleFormSubmit }
164+ variant = 'contained'
165+ color = 'primary'
166+ sx = { { textTransform : 'none' } }
167+ loading = { isLoadingCreate || isLoadingUpdate }
168+ disabled = {
169+ isLoadingCreate ||
170+ isLoadingUpdate ||
171+ isLoadingDelete ||
172+ ( ! agentName && ! requiredFieldsFilled ) ||
173+ ( agentName && data && isEqual ( data , watch ( ) ) )
174+ }
175+ >
176+ { agentName ? 'Save Changes' : 'Create Agent' }
177+ </ LoadingButton >
178+ </ Box >
179+ </ Tooltip >
180+ </ Box >
181+ )
182+
114183 return (
115184 < Grid >
116185 < PaperLayout loading = { loading || isError } title = { t ( 'TITLE_AGENT' ) } >
@@ -130,18 +199,54 @@ export default function AgentsCreateEditPage({
130199 } ,
131200 } }
132201 >
133- < Tab label = 'Settings' value = { 0 } sx = { { textTransform : 'capitalize' , padding : '12px 16px' } } />
134- < Tab label = 'Playground' value = { 1 } sx = { { textTransform : 'capitalize' , padding : '12px 16px' } } />
135- < Tab label = 'Workflow resources' value = { 2 } sx = { { textTransform : 'capitalize' , padding : '12px 16px' } } />
202+ < Tab
203+ label = 'Settings'
204+ value = { 0 }
205+ sx = { {
206+ textTransform : 'capitalize' ,
207+ padding : '12px 16px' ,
208+ ...( tab !== 0 &&
209+ tabHasErrors ( 0 ) && {
210+ borderBottom : '2px solid' ,
211+ borderBottomColor : 'error.main' ,
212+ } ) ,
213+ } }
214+ />
215+ < Tab
216+ label = 'Playground'
217+ value = { 1 }
218+ sx = { {
219+ textTransform : 'capitalize' ,
220+ padding : '12px 16px' ,
221+ ...( tab !== 1 &&
222+ tabHasErrors ( 1 ) && {
223+ borderBottom : '2px solid' ,
224+ borderBottomColor : 'error.main' ,
225+ } ) ,
226+ } }
227+ />
228+ < Tab
229+ label = 'Workflow resources'
230+ value = { 2 }
231+ sx = { {
232+ textTransform : 'capitalize' ,
233+ padding : '12px 16px' ,
234+ ...( tab !== 2 &&
235+ tabHasErrors ( 2 ) && {
236+ borderBottom : '2px solid' ,
237+ borderBottomColor : 'error.main' ,
238+ } ) ,
239+ } }
240+ />
136241 </ Tabs >
137242 </ AppBar >
138243 < FormProvider { ...methods } >
139- < form onSubmit = { handleSubmit ( onSubmit ) } >
244+ < form >
140245 < TabPanel value = { tab } index = { 0 } >
141246 < Section noPaddingTop >
142247 < FormRow spacing = { 10 } >
143248 < TextField
144- label = 'Agent name'
249+ label = 'Agent name * '
145250 width = 'large'
146251 placeholder = 'my-agent'
147252 { ...register ( 'metadata.name' ) }
@@ -159,7 +264,7 @@ export default function AgentsCreateEditPage({
159264
160265 < FormRow spacing = { 10 } >
161266 < Autocomplete
162- label = 'Foundation model'
267+ label = 'Foundation model * '
163268 width = 'large'
164269 placeholder = 'Select a foundation model'
165270 options = {
@@ -181,37 +286,15 @@ export default function AgentsCreateEditPage({
181286 </ FormRow >
182287 </ Section >
183288
184- { agentName && (
185- < DeleteButton
186- onDelete = { ( ) => del ( { teamId, agentName } ) }
187- resourceName = { watch ( 'metadata.name' ) }
188- resourceType = 'agent'
189- data-cy = 'button-delete-agent'
190- sx = { { float : 'right' , textTransform : 'capitalize' , ml : 2 } }
191- loading = { isLoadingDelete }
192- disabled = { isLoadingDelete || isLoadingCreate || isLoadingUpdate }
193- />
194- ) }
195- < LoadingButton
196- type = 'submit'
197- variant = 'contained'
198- color = 'primary'
199- sx = { { float : 'right' , textTransform : 'none' } }
200- loading = { isLoadingCreate || isLoadingUpdate }
201- disabled = {
202- isLoadingCreate || isLoadingUpdate || isLoadingDelete || ( agentName && data && isEqual ( data , watch ( ) ) )
203- }
204- >
205- { agentName ? 'Save Changes' : 'Create Agent' }
206- </ LoadingButton >
289+ { formButtons }
207290 </ TabPanel >
208291
209292 < TabPanel value = { tab } index = { 1 } >
210293 < Section noPaddingTop >
211294 < FormRow spacing = { 10 } >
212295 < AutoResizableTextarea
213- label = 'Instructions'
214- placeholder = ' Enter agent instructions...'
296+ label = 'Instructions * '
297+ placeholder = { ` Enter agent instructions... (Leave empty to use the default: ' ${ DEFAULT_AGENT_INSTRUCTIONS } ')` }
215298 minRows = { 12 }
216299 maxRows = { 40 }
217300 minWidth = { 400 }
@@ -226,34 +309,7 @@ export default function AgentsCreateEditPage({
226309 </ FormRow >
227310 </ Section >
228311
229- < Box sx = { { my : 2 } } >
230- { agentName && (
231- < DeleteButton
232- onDelete = { ( ) => del ( { teamId, agentName } ) }
233- resourceName = { watch ( 'metadata.name' ) }
234- resourceType = 'agent'
235- data-cy = 'button-delete-agent'
236- sx = { { float : 'right' , textTransform : 'capitalize' , ml : 2 } }
237- loading = { isLoadingDelete }
238- disabled = { isLoadingDelete || isLoadingCreate || isLoadingUpdate }
239- />
240- ) }
241- < LoadingButton
242- type = 'submit'
243- variant = 'contained'
244- color = 'primary'
245- sx = { { float : 'right' , textTransform : 'none' } }
246- loading = { isLoadingCreate || isLoadingUpdate }
247- disabled = {
248- isLoadingCreate ||
249- isLoadingUpdate ||
250- isLoadingDelete ||
251- ( agentName && data && isEqual ( data , watch ( ) ) )
252- }
253- >
254- { agentName ? 'Save Changes' : 'Create Agent' }
255- </ LoadingButton >
256- </ Box >
312+ < Box sx = { { my : 2 } } > { formButtons } </ Box >
257313
258314 { agentName ? (
259315 < Box sx = { { clear : 'both' } } >
@@ -303,7 +359,6 @@ export default function AgentsCreateEditPage({
303359 } }
304360 />
305361 </ FormRow >
306-
307362 < Divider spacingBottom = { 10 } />
308363 < AgentResources
309364 title = 'Agent route(s)'
@@ -348,29 +403,7 @@ export default function AgentsCreateEditPage({
348403 />
349404 </ Section >
350405
351- { agentName && (
352- < DeleteButton
353- onDelete = { ( ) => del ( { teamId, agentName } ) }
354- resourceName = { watch ( 'metadata.name' ) }
355- resourceType = 'agent'
356- data-cy = 'button-delete-agent'
357- sx = { { float : 'right' , textTransform : 'capitalize' , ml : 2 } }
358- loading = { isLoadingDelete }
359- disabled = { isLoadingDelete || isLoadingCreate || isLoadingUpdate }
360- />
361- ) }
362- < LoadingButton
363- type = 'submit'
364- variant = 'contained'
365- color = 'primary'
366- sx = { { float : 'right' , textTransform : 'none' } }
367- loading = { isLoadingCreate || isLoadingUpdate }
368- disabled = {
369- isLoadingCreate || isLoadingUpdate || isLoadingDelete || ( agentName && data && isEqual ( data , watch ( ) ) )
370- }
371- >
372- { agentName ? 'Save Changes' : 'Create Agent' }
373- </ LoadingButton >
406+ { formButtons }
374407 </ TabPanel >
375408 </ form >
376409 </ FormProvider >
0 commit comments