@@ -64,6 +64,7 @@ const ConnectorAddModal = ({
6464 const [ allActionTypes , setAllActionTypes ] = useState < ActionTypeIndex | undefined > ( undefined ) ;
6565 const { isLoading : isSavingConnector , createConnector } = useCreateConnector ( ) ;
6666 const isMounted = useRef ( false ) ;
67+ const containerRef = useRef < HTMLDivElement > ( null ) ;
6768 const [ initialConnector , setInitialConnector ] = useState ( {
6869 actionTypeId : actionType ?. id ?? '' ,
6970 isDeprecated : false ,
@@ -163,6 +164,19 @@ const ConnectorAddModal = ({
163164
164165 const createdConnector = await createConnector ( validConnector ) ;
165166 return createdConnector ;
167+ } else {
168+ // point the user to the first invalid field
169+ const container = containerRef . current ;
170+ if ( ! container ) return ;
171+
172+ const selector = 'input[aria-invalid="true"]' ;
173+ const firstInputInvalid = container . querySelector < HTMLInputElement > ( selector ) ;
174+
175+ if ( firstInputInvalid ) {
176+ window . requestAnimationFrame ( ( ) => {
177+ firstInputInvalid . focus ( { preventScroll : false } ) ;
178+ } ) ;
179+ }
166180 }
167181 } , [ submit , preSubmitValidator , createConnector ] ) ;
168182
@@ -222,108 +236,110 @@ const ConnectorAddModal = ({
222236 className = "actConnectorModal"
223237 css = { css `
224238 z-index : 9000 ;
239+ width : ${ actionTypeRegistry . get ( actionType . id ) . modalWidth } ;
225240 ` }
226241 data-test-subj = "connectorAddModal"
227242 onClose = { closeModal }
228- style = { { width : actionTypeRegistry . get ( actionType . id ) . modalWidth } }
229243 aria-labelledby = { modalTitleId }
230244 >
231- < EuiModalHeader >
232- < EuiFlexGroup gutterSize = "m" alignItems = "center" >
233- { actionTypeModel && actionTypeModel . iconClass ? (
245+ < div ref = { containerRef } >
246+ < EuiModalHeader >
247+ < EuiFlexGroup gutterSize = "m" alignItems = "center" >
248+ { actionTypeModel && actionTypeModel . iconClass ? (
249+ < EuiFlexItem grow = { false } >
250+ < EuiIcon type = { actionTypeModel . iconClass } size = "xl" />
251+ </ EuiFlexItem >
252+ ) : null }
234253 < EuiFlexItem grow = { false } >
235- < EuiIcon type = { actionTypeModel . iconClass } size = "xl" />
254+ < EuiFlexGroup gutterSize = "s" justifyContent = "center" alignItems = "center" >
255+ < EuiFlexItem >
256+ < EuiModalHeaderTitle id = { modalTitleId } size = "s" component = "h3" >
257+ < FormattedMessage
258+ defaultMessage = "{actionTypeName} connector"
259+ id = "xpack.triggersActionsUI.sections.addModalConnectorForm.flyoutTitle"
260+ values = { {
261+ actionTypeName : actionType . name ,
262+ } }
263+ />
264+ </ EuiModalHeaderTitle >
265+ </ EuiFlexItem >
266+ { actionTypeModel && actionTypeModel . isExperimental && (
267+ < EuiFlexItem className = "betaBadgeFlexItem" grow = { false } >
268+ < EuiBetaBadge
269+ label = { TECH_PREVIEW_LABEL }
270+ tooltipContent = { TECH_PREVIEW_DESCRIPTION }
271+ />
272+ </ EuiFlexItem >
273+ ) }
274+ </ EuiFlexGroup >
236275 </ EuiFlexItem >
237- ) : null }
238- < EuiFlexItem grow = { false } >
239- < EuiFlexGroup gutterSize = "s" justifyContent = "center" alignItems = "center" >
240- < EuiFlexItem >
241- < EuiModalHeaderTitle id = { modalTitleId } size = "s" component = "h3" >
242- < FormattedMessage
243- defaultMessage = "{actionTypeName} connector"
244- id = "xpack.triggersActionsUI.sections.addModalConnectorForm.flyoutTitle"
245- values = { {
246- actionTypeName : actionType . name ,
247- } }
248- />
249- </ EuiModalHeaderTitle >
250- </ EuiFlexItem >
251- { actionTypeModel && actionTypeModel . isExperimental && (
252- < EuiFlexItem className = "betaBadgeFlexItem" grow = { false } >
253- < EuiBetaBadge
254- label = { TECH_PREVIEW_LABEL }
255- tooltipContent = { TECH_PREVIEW_DESCRIPTION }
276+ </ EuiFlexGroup >
277+ </ EuiModalHeader >
278+
279+ < EuiModalBody >
280+ { loadingActionTypes ? (
281+ < SectionLoading >
282+ < FormattedMessage
283+ id = "xpack.triggersActionsUI.sections.connectorAddModal.loadingConnectorTypesDescription"
284+ defaultMessage = "Loading connector types…"
285+ />
286+ </ SectionLoading >
287+ ) : (
288+ < >
289+ { groupActionTypeModel && (
290+ < >
291+ < EuiButtonGroup
292+ isFullWidth
293+ buttonSize = "m"
294+ color = "primary"
295+ legend = ""
296+ options = { groupActionButtons }
297+ idSelected = { actionType . id }
298+ onChange = { onChangeGroupAction }
299+ data-test-subj = "slackTypeChangeButton"
256300 />
257- </ EuiFlexItem >
301+ < EuiSpacer size = "xs" />
302+ </ >
258303 ) }
259- </ EuiFlexGroup >
260- </ EuiFlexItem >
261- </ EuiFlexGroup >
262- </ EuiModalHeader >
263-
264- < EuiModalBody >
265- { loadingActionTypes ? (
266- < SectionLoading >
267- < FormattedMessage
268- id = "xpack.triggersActionsUI.sections.connectorAddModal.loadingConnectorTypesDescription"
269- defaultMessage = "Loading connector types…"
270- />
271- </ SectionLoading >
272- ) : (
273- < >
274- { groupActionTypeModel && (
275- < >
276- < EuiButtonGroup
277- isFullWidth
278- buttonSize = "m"
279- color = "primary"
280- legend = ""
281- options = { groupActionButtons }
282- idSelected = { actionType . id }
283- onChange = { onChangeGroupAction }
284- data-test-subj = "slackTypeChangeButton"
285- />
286- < EuiSpacer size = "xs" />
287- </ >
288- ) }
289- < ConnectorForm
290- actionTypeModel = { actionTypeModel }
291- connector = { initialConnector }
292- isEdit = { false }
293- onChange = { setFormState }
294- setResetForm = { setResetForm }
295- />
296- { preSubmitValidationErrorMessage }
297- </ >
298- ) }
299- </ EuiModalBody >
300- < EuiModalFooter >
301- < EuiButtonEmpty onClick = { closeModal } isLoading = { isSaving } >
302- { i18n . translate (
303- 'xpack.triggersActionsUI.sections.addModalConnectorForm.cancelButtonLabel' ,
304- {
305- defaultMessage : 'Cancel' ,
306- }
304+ < ConnectorForm
305+ actionTypeModel = { actionTypeModel }
306+ connector = { initialConnector }
307+ isEdit = { false }
308+ onChange = { setFormState }
309+ setResetForm = { setResetForm }
310+ />
311+ { preSubmitValidationErrorMessage }
312+ </ >
307313 ) }
308- </ EuiButtonEmpty >
309- { canSave ? (
310- < EuiButton
311- fill
312- color = "primary"
313- data-test-subj = "saveActionButtonModal"
314- type = "submit"
315- iconType = "check"
316- isLoading = { isSaving }
317- disabled = { hasErrors }
318- onClick = { onSubmit }
319- >
320- < FormattedMessage
321- id = "xpack.triggersActionsUI.sections.addModalConnectorForm.saveButtonLabel"
322- defaultMessage = "Save"
323- />
324- </ EuiButton >
325- ) : null }
326- </ EuiModalFooter >
314+ </ EuiModalBody >
315+ < EuiModalFooter >
316+ < EuiButtonEmpty onClick = { closeModal } isLoading = { isSaving } >
317+ { i18n . translate (
318+ 'xpack.triggersActionsUI.sections.addModalConnectorForm.cancelButtonLabel' ,
319+ {
320+ defaultMessage : 'Cancel' ,
321+ }
322+ ) }
323+ </ EuiButtonEmpty >
324+ { canSave ? (
325+ < EuiButton
326+ fill
327+ color = "primary"
328+ data-test-subj = "saveActionButtonModal"
329+ type = "submit"
330+ iconType = "check"
331+ isLoading = { isSaving }
332+ disabled = { hasErrors }
333+ onClick = { onSubmit }
334+ >
335+ < FormattedMessage
336+ id = "xpack.triggersActionsUI.sections.addModalConnectorForm.saveButtonLabel"
337+ defaultMessage = "Save"
338+ />
339+ </ EuiButton >
340+ ) : null }
341+ </ EuiModalFooter >
342+ </ div >
327343 </ EuiModal >
328344 ) ;
329345} ;
0 commit comments