import { EuiBottomBar , EuiButton , EuiButtonEmpty , EuiCallOut , EuiFlexGroup , EuiFlexItem , EuiForm , EuiHealth , EuiLoadingSpinner , EuiSpacer , EuiStat , EuiText , EuiHorizontalRule , } from '@elastic/eui' ; import { i18n } from '@kbn/i18n' ; import React , { useMemo , useState } from 'react' ; import { useHistory } from 'react-router-dom' ; import { useUiTracker } from '../../../../../../../../observability/public' ; import { getOptionLabel } from '../../../../../../../common/agent_configuration/all_option' ; import { AgentConfigurationIntake } from '../../../../../../../common/agent_configuration/configuration_types' ; import { filterByAgent , settingDefinitions , validateSetting , } from '../../../../../../../common/agent_configuration/setting_definitions' ; import { AgentName } from '../../../../../../../typings/es_schemas/ui/fields/agent' ; import { useApmPluginContext } from '../../../../../../context/apm_plugin/use_apm_plugin_context' ; import { FETCH_STATUS } from '../../../../../../hooks/use_fetcher' ; import { saveConfig } from './saveConfig' ; import { SettingFormRow } from './SettingFormRow' ; function removeEmpty ( obj ) { return Object . fromEntries ( Object . entries ( obj ) . filter ( ( [ _ , v ] ) => v != null && v !== '' ) ) ; } export function SettingsPage ( { status , unsavedChanges , newConfig , setNewConfig , resetSettings , isEditMode , onClickEdit , } ) { const history = useHistory ( ) ; const trackApmEvent = useUiTracker ( { app : 'apm' } ) ; const { toasts } = useApmPluginContext ( ) . core . notifications ; const [ isSaving , setIsSaving ] = useState ( false ) ; const unsavedChangesCount = Object . keys ( unsavedChanges ) . length ; const isLoading = status === FETCH_STATUS . LOADING ; const isFormValid = useMemo ( ( ) => { return ( settingDefinitions . filter ( ( { key } ) => { const value = newConfig . settings [ key ] ; return value != null && value !== '' ; } ) . every ( ( def ) => { const value = newConfig . settings [ def . key ] ; return validateSetting ( def , value ) . isValid ; } ) ) ; } , [ newConfig . settings ] ) ; const handleSubmitEvent = async ( ) => { trackApmEvent ( { metric : 'save_agent_configuration' } ) ; const config = { ... newConfig , settings : removeEmpty ( newConfig . settings ) } ; setIsSaving ( true ) ; await saveConfig ( { config , isEditMode , toasts } ) ; setIsSaving ( false ) ; history . push ( { pathname : '/settings/agent-configuration' , search : history . location . search , } ) ; } ; if ( status === FETCH_STATUS . FAILURE ) { return ( < EuiCallOut title = { i18n . translate ( 'xpack.apm.agentConfig.settingsPage.notFound.title' , { defaultMessage : 'Sorry, there was an error' } ) } color = "danger" iconType = "alert" > < p > { i18n . translate ( 'xpack.apm.agentConfig.settingsPage.notFound.message' , { defaultMessage : 'The requested configuration does not exist' } ) } < /p> < /EuiCallOut>); } return ( < > < EuiForm > { } { } < form onKeyPress = { ( e ) => { const didClickEnter = e . which === 13 ; if ( didClickEnter && isFormValid ) { e . preventDefault ( ) ; handleSubmitEvent ( ) ; } } } > { } < EuiFlexGroup > < EuiFlexItem > < EuiStat titleSize = "xs" title = { isLoading ? '-' : getOptionLabel ( newConfig . service . name ) } description = { i18n . translate ( 'xpack.apm.agentConfig.chooseService.service.name.label' , { defaultMessage : 'Service name' } ) } / > < /EuiFlexItem> < EuiFlexItem > < EuiStat titleSize = "xs" title = { isLoading ? '-' : getOptionLabel ( newConfig . service . environment ) } description = { i18n . translate ( 'xpack.apm.agentConfig.chooseService.service.environment.label' , { defaultMessage : 'Environment' } ) } / > < /EuiFlexItem> < EuiFlexItem grow = { false } > { ! isEditMode && ( < EuiButton onClick = { onClickEdit } iconType = "pencil" > { i18n . translate ( 'xpack.apm.agentConfig.chooseService.editButton' , { defaultMessage : 'Edit' } ) } < /EuiButton>)} < /EuiFlexItem> < /EuiFlexGroup> < EuiHorizontalRule / > { } { isLoading ? ( < div style = { { textAlign : 'center' } } > < EuiLoadingSpinner size = "m" / > < /div>) : (renderSettings({ unsavedChanges, newConfig, setNewConfig }))} < /form> < /EuiForm> < EuiSpacer size = "xxl" / > { } { unsavedChangesCount > 0 && ( < EuiBottomBar paddingSize = "s" > < EuiFlexGroup justifyContent = "spaceBetween" alignItems = "center" > < EuiFlexItem grow = { false } style = { { flexDirection : 'row' , alignItems : 'center' , } } > < EuiHealth color = "warning" / > < EuiText color = "ghost" > { i18n . translate ( 'xpack.apm.unsavedChanges' , { defaultMessage : '{unsavedChangesCount, plural, =0{0 unsaved changes} one {1 unsaved change} other {# unsaved changes}} ' , values : { unsavedChangesCount } , } ) } < /EuiText> < /EuiFlexItem> < EuiFlexItem grow = { false } > < EuiFlexGroup justifyContent = "flexEnd" > < EuiFlexItem grow = { false } > < EuiButtonEmpty color = "ghost" onClick = { resetSettings } > { i18n . translate ( 'xpack.apm.agentConfig.settingsPage.discardChangesButton' , { defaultMessage : 'Discard changes' } ) } < /EuiButtonEmpty> < /EuiFlexItem> < EuiFlexItem grow = { false } > < EuiButton onClick = { handleSubmitEvent } fill isLoading = { isSaving } isDisabled = { ! isFormValid } color = "success" iconType = "check" > { i18n . translate ( 'xpack.apm.agentConfig.settingsPage.saveButton' , { defaultMessage : 'Save configuration' } ) } < /EuiButton> < /EuiFlexItem> < /EuiFlexGroup> < /EuiFlexItem> < /EuiFlexGroup> < /EuiBottomBar>)} < />); } function renderSettings ( { newConfig , unsavedChanges , setNewConfig , } ) { return ( settingDefinitions . filter ( filterByAgent ( newConfig . agent_name as AgentName ) ) . map ( ( setting ) => ( < SettingFormRow isUnsaved = { unsavedChanges . hasOwnProperty ( setting . key ) } key = { setting . key } setting = { setting } value = { newConfig . settings [ setting . key ] } onChange = { ( key , value ) => { setNewConfig ( ( prev ) => ( { ... prev , settings : { ... prev . settings , [ key ] : value , } , } ) ) ; } } />))); }