44 * you may not use this file except in compliance with the Elastic License.
55 */
66
7- import React , { useCallback , useEffect , useState } from 'react' ;
7+ import { isEmpty } from 'lodash/fp' ;
8+ import { EuiSpacer , EuiCallOut } from '@elastic/eui' ;
9+ import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
810import deepMerge from 'deepmerge' ;
11+ import ReactMarkdown from 'react-markdown' ;
12+ import styled from 'styled-components' ;
913
1014import { NOTIFICATION_SUPPORTED_ACTION_TYPES_IDS } from '../../../../../common/constants' ;
11- // eslint-disable-next-line @kbn/eslint/no-restricted-paths
12- import { loadActionTypes } from '../../../../../../triggers_actions_ui/public/application/lib/action_connector_api' ;
1315import { SelectField } from '../../../../shared_imports' ;
14- import { ActionForm , ActionType } from '../../../../../../triggers_actions_ui/public' ;
16+ import {
17+ ActionForm ,
18+ ActionType ,
19+ loadActionTypes ,
20+ } from '../../../../../../triggers_actions_ui/public' ;
1521import { AlertAction } from '../../../../../../alerting/common' ;
1622import { useKibana } from '../../../../common/lib/kibana' ;
23+ import { FORM_ERRORS_TITLE } from './translations' ;
1724
1825type ThrottleSelectField = typeof SelectField ;
1926
2027const DEFAULT_ACTION_GROUP_ID = 'default' ;
2128const DEFAULT_ACTION_MESSAGE =
2229 'Rule {{context.rule.name}} generated {{state.signals_count}} signals' ;
2330
31+ const FieldErrorsContainer = styled . div `
32+ p {
33+ margin-bottom: 0;
34+ }
35+ ` ;
36+
2437export const RuleActionsField : ThrottleSelectField = ( { field, messageVariables } ) => {
38+ const [ fieldErrors , setFieldErrors ] = useState < string | null > ( null ) ;
2539 const [ supportedActionTypes , setSupportedActionTypes ] = useState < ActionType [ ] | undefined > ( ) ;
2640 const {
2741 http,
@@ -31,13 +45,18 @@ export const RuleActionsField: ThrottleSelectField = ({ field, messageVariables
3145 application : { capabilities } ,
3246 } = useKibana ( ) . services ;
3347
48+ const actions : AlertAction [ ] = useMemo (
49+ ( ) => ( ! isEmpty ( field . value ) ? ( field . value as AlertAction [ ] ) : [ ] ) ,
50+ [ field . value ]
51+ ) ;
52+
3453 const setActionIdByIndex = useCallback (
3554 ( id : string , index : number ) => {
36- const updatedActions = [ ...( field . value as Array < Partial < AlertAction > > ) ] ;
55+ const updatedActions = [ ...( actions as Array < Partial < AlertAction > > ) ] ;
3756 updatedActions [ index ] = deepMerge ( updatedActions [ index ] , { id } ) ;
3857 field . setValue ( updatedActions ) ;
3958 } ,
40- [ field ]
59+ [ field . setValue , actions ]
4160 ) ;
4261
4362 const setAlertProperty = useCallback (
@@ -48,11 +67,11 @@ export const RuleActionsField: ThrottleSelectField = ({ field, messageVariables
4867 const setActionParamsProperty = useCallback (
4968 // eslint-disable-next-line @typescript-eslint/no-explicit-any
5069 ( key : string , value : any , index : number ) => {
51- const updatedActions = [ ...( field . value as AlertAction [ ] ) ] ;
70+ const updatedActions = [ ...actions ] ;
5271 updatedActions [ index ] . params [ key ] = value ;
5372 field . setValue ( updatedActions ) ;
5473 } ,
55- [ field ]
74+ [ field . setValue , actions ]
5675 ) ;
5776
5877 useEffect ( ( ) => {
@@ -65,23 +84,57 @@ export const RuleActionsField: ThrottleSelectField = ({ field, messageVariables
6584 } ) ( ) ;
6685 } , [ ] ) ;
6786
87+ useEffect ( ( ) => {
88+ if ( field . form . isSubmitting || ! field . errors . length ) {
89+ return setFieldErrors ( null ) ;
90+ }
91+ if (
92+ field . form . isSubmitted &&
93+ ! field . form . isSubmitting &&
94+ field . form . isValid === false &&
95+ field . errors . length
96+ ) {
97+ const errorsString = field . errors . map ( ( { message } ) => message ) . join ( '\n' ) ;
98+ return setFieldErrors ( errorsString ) ;
99+ }
100+ } , [
101+ field . form . isSubmitted ,
102+ field . form . isSubmitting ,
103+ field . isChangingValue ,
104+ field . form . isValid ,
105+ field . errors ,
106+ setFieldErrors ,
107+ ] ) ;
108+
68109 if ( ! supportedActionTypes ) return < > </ > ;
69110
70111 return (
71- < ActionForm
72- actions = { field . value as AlertAction [ ] }
73- messageVariables = { messageVariables }
74- defaultActionGroupId = { DEFAULT_ACTION_GROUP_ID }
75- setActionIdByIndex = { setActionIdByIndex }
76- setAlertProperty = { setAlertProperty }
77- setActionParamsProperty = { setActionParamsProperty }
78- http = { http }
79- actionTypeRegistry = { actionTypeRegistry }
80- actionTypes = { supportedActionTypes }
81- defaultActionMessage = { DEFAULT_ACTION_MESSAGE }
82- toastNotifications = { notifications . toasts }
83- docLinks = { docLinks }
84- capabilities = { capabilities }
85- />
112+ < >
113+ { fieldErrors ? (
114+ < >
115+ < FieldErrorsContainer >
116+ < EuiCallOut title = { FORM_ERRORS_TITLE } color = "danger" iconType = "alert" >
117+ < ReactMarkdown source = { fieldErrors } />
118+ </ EuiCallOut >
119+ </ FieldErrorsContainer >
120+ < EuiSpacer />
121+ </ >
122+ ) : null }
123+ < ActionForm
124+ actions = { actions }
125+ docLinks = { docLinks }
126+ capabilities = { capabilities }
127+ messageVariables = { messageVariables }
128+ defaultActionGroupId = { DEFAULT_ACTION_GROUP_ID }
129+ setActionIdByIndex = { setActionIdByIndex }
130+ setAlertProperty = { setAlertProperty }
131+ setActionParamsProperty = { setActionParamsProperty }
132+ http = { http }
133+ actionTypeRegistry = { actionTypeRegistry }
134+ actionTypes = { supportedActionTypes }
135+ defaultActionMessage = { DEFAULT_ACTION_MESSAGE }
136+ toastNotifications = { notifications . toasts }
137+ />
138+ </ >
86139 ) ;
87140} ;
0 commit comments