diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.js index e0fc691e84e3c..cb1857473b817 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/advanced_settings_fields.js @@ -55,7 +55,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxReadRequestOperationCountLabel', { - defaultMessage: 'Max read request operation count (optional)' + defaultMessage: 'Max read request operation count' } ), defaultValue: getSettingDefault('maxReadRequestOperationCount'), @@ -72,7 +72,7 @@ export const advancedSettingsFields = [ }), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxOutstandingReadRequestsLabel', { - defaultMessage: 'Max outstanding read requests (optional)' + defaultMessage: 'Max outstanding read requests' } ), defaultValue: getSettingDefault('maxOutstandingReadRequests'), @@ -89,7 +89,7 @@ export const advancedSettingsFields = [ }), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxReadRequestSizeLabel', { - defaultMessage: 'Max read request size (optional)' + defaultMessage: 'Max read request size' } ), defaultValue: getSettingDefault('maxReadRequestSize'), @@ -108,7 +108,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteRequestOperationCountLabel', { - defaultMessage: 'Max write request operation count (optional)' + defaultMessage: 'Max write request operation count' } ), defaultValue: getSettingDefault('maxWriteRequestOperationCount'), @@ -127,7 +127,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteRequestSizeLabel', { - defaultMessage: 'Max write request size (optional)' + defaultMessage: 'Max write request size' } ), defaultValue: getSettingDefault('maxWriteRequestSize'), @@ -146,7 +146,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxOutstandingWriteRequestsLabel', { - defaultMessage: 'Max outstanding write requests (optional)' + defaultMessage: 'Max outstanding write requests' } ), defaultValue: getSettingDefault('maxOutstandingWriteRequests'), @@ -167,7 +167,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteBufferCountLabel', { - defaultMessage: 'Max write buffer count (optional)' + defaultMessage: 'Max write buffer count' } ), defaultValue: getSettingDefault('maxWriteBufferCount'), @@ -188,7 +188,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteBufferSizeLabel', { - defaultMessage: 'Max write buffer size (optional)' + defaultMessage: 'Max write buffer size' } ), defaultValue: getSettingDefault('maxWriteBufferSize'), @@ -208,7 +208,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxRetryDelayLabel', { - defaultMessage: 'Max retry delay (optional)' + defaultMessage: 'Max retry delay' } ), defaultValue: getSettingDefault('maxRetryDelay'), @@ -230,7 +230,7 @@ export const advancedSettingsFields = [ ), label: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.readPollTimeoutLabel', { - defaultMessage: 'Read poll timeout (optional)' + defaultMessage: 'Read poll timeout' } ), defaultValue: getSettingDefault('readPollTimeout'), @@ -239,5 +239,13 @@ export const advancedSettingsFields = [ ]; export const emptyAdvancedSettings = advancedSettingsFields.reduce((obj, advancedSetting) => { - return { ...obj, [advancedSetting.field]: '' }; + const { field, defaultValue } = advancedSetting; + return { ...obj, [field]: defaultValue }; }, {}); + +export function areAdvancedSettingsEdited(followerIndex) { + return advancedSettingsFields.some(advancedSetting => { + const { field } = advancedSetting; + return followerIndex[field] !== emptyAdvancedSettings[field]; + }); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js index 67461e156f28b..fbc53e13128f8 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_form/follower_index_form.js @@ -16,7 +16,6 @@ import { EuiButton, EuiButtonEmpty, EuiCallOut, - EuiCode, EuiDescribedFormGroup, EuiFlexGroup, EuiFlexItem, @@ -26,6 +25,7 @@ import { EuiLoadingSpinner, EuiOverlayMask, EuiSpacer, + EuiSwitch, EuiText, EuiTitle, } from '@elastic/eui'; @@ -36,7 +36,11 @@ import { loadIndices } from '../../services/api'; import { API_STATUS } from '../../constants'; import { SectionError } from '../section_error'; import { FormEntryRow } from '../form_entry_row'; -import { advancedSettingsFields, emptyAdvancedSettings } from './advanced_settings_fields'; +import { + advancedSettingsFields, + emptyAdvancedSettings, + areAdvancedSettingsEdited, +} from './advanced_settings_fields'; import { extractQueryParams } from '../../services/query_params'; import { getRemoteClusterName } from '../../services/get_remote_cluster_name'; import { RemoteClustersFormField } from '../remote_clusters_form_field'; @@ -93,9 +97,10 @@ export const FollowerIndexForm = injectI18n( constructor(props) { super(props); - const isNew = this.props.followerIndex === undefined; const { route: { location: { search } } } = routing.reactRouter; const queryParams = extractQueryParams(search); + + const isNew = this.props.followerIndex === undefined; const remoteClusterName = getRemoteClusterName(this.props.remoteClusters, queryParams.cluster); const followerIndex = isNew ? getEmptyFollowerIndex(remoteClusterName) @@ -103,6 +108,9 @@ export const FollowerIndexForm = injectI18n( ...getEmptyFollowerIndex(), ...this.props.followerIndex, }; + const areAdvancedSettingsVisible = isNew ? false : ( // eslint-disable-line no-nested-ternary + areAdvancedSettingsEdited(followerIndex) ? true : false + ); const fieldsErrors = this.getFieldsErrors(followerIndex); @@ -111,10 +119,11 @@ export const FollowerIndexForm = injectI18n( followerIndex, fieldsErrors, areErrorsVisible: false, - areAdvancedSettingsVisible: isNew ? false : true, + areAdvancedSettingsVisible, isValidatingIndexName: false, }; + this.cachedAdvancedSettings = {}; this.validateIndexName = debounce(this.validateIndexName, 500); } @@ -212,34 +221,39 @@ export const FollowerIndexForm = injectI18n( return this.state.followerIndex; }; - toggleAdvancedSettings = () => { - this.setState(({ areAdvancedSettingsVisible, cachedAdvancedSettings }) => { - // Hide settings, clear fields, and create cache. - if (areAdvancedSettingsVisible) { - const fields = this.getFields(); + toggleAdvancedSettings = (event) => { + // If the user edits the advanced settings but then hides them, we need to make sure the + // edited values don't get sent to the API when the user saves, but we *do* want to restore + // these values to the form when the user re-opens the advanced settings. + if (event.target.checked) { + // Apply the cached advanced settings to the advanced settings form. + this.onFieldsChange(this.cachedAdvancedSettings); - const newCachedAdvancedSettings = advancedSettingsFields.reduce((cache, { field }) => { - const value = fields[field]; - if (value !== '') { - cache[field] = value; - } - return cache; - }, {}); + // Reset the cache of the advanced settings. + this.cachedAdvancedSettings = {}; - this.onFieldsChange(emptyAdvancedSettings); + // Show the advanced settings. + return this.setState({ + areAdvancedSettingsVisible: true, + }); + } - return { - areAdvancedSettingsVisible: false, - cachedAdvancedSettings: newCachedAdvancedSettings, - }; + // Clear the advanced settings form. + this.onFieldsChange(emptyAdvancedSettings); + + // Save a cache of the advanced settings. + const fields = this.getFields(); + this.cachedAdvancedSettings = advancedSettingsFields.reduce((cache, { field }) => { + const value = fields[field]; + if (value !== '') { + cache[field] = value; } + return cache; + }, {}); - // Show settings and restore fields from the cache. - this.onFieldsChange(cachedAdvancedSettings); - return { - areAdvancedSettingsVisible: true, - cachedAdvancedSettings: {}, - }; + // Hide the advanced settings. + this.setState({ + areAdvancedSettingsVisible: false, }); } @@ -455,22 +469,7 @@ export const FollowerIndexForm = injectI18n( * Advanced settings */ - const toggleAdvancedSettingButtonLabel = areAdvancedSettingsVisible - ? ( - - ) : ( - - ); - const renderAdvancedSettings = () => { - const { isNew } = this.state; - return ( @@ -480,7 +479,7 @@ export const FollowerIndexForm = injectI18n(

@@ -490,17 +489,21 @@ export const FollowerIndexForm = injectI18n(

- {isNew ? ( - - {toggleAdvancedSettingButtonLabel} - - ) : null} + + + )} + checked={areAdvancedSettingsVisible} + onChange={this.toggleAdvancedSettings} + />
)} fullWidth @@ -512,33 +515,23 @@ export const FollowerIndexForm = injectI18n( {advancedSettingsFields.map((advancedSetting) => { - const { field, title, description, label, helpText, defaultValue } = advancedSetting; + const { field, title, description, label, helpText, defaultValue, type } = advancedSetting; return (

{title}

)} - description={( - - {description} - - - {' '} - {defaultValue} - - - )} + description={description} label={label} helpText={helpText} + type={type} areErrorsVisible={areErrorsVisible} onValueUpdate={this.onFieldsChange} /> diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/form_entry_row.js b/x-pack/plugins/cross_cluster_replication/public/app/components/form_entry_row.js index bfc7d8e3c6c7b..630bc6b7f35ce 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/form_entry_row.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/form_entry_row.js @@ -4,14 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { PureComponent } from 'react'; +import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; +import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiFieldText, - EuiFieldNumber, EuiDescribedFormGroup, + EuiFieldNumber, + EuiFieldText, EuiFormRow, + EuiLink, } from '@elastic/eui'; /** @@ -37,6 +39,10 @@ export class FormEntryRow extends PureComponent { PropTypes.string, PropTypes.number ]).isRequired, + defaultValue: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), isLoading: PropTypes.bool, error: PropTypes.oneOfType([ PropTypes.node, @@ -89,10 +95,31 @@ export class FormEntryRow extends PureComponent { description, helpText, areErrorsVisible, + value, + defaultValue, } = this.props; const hasError = !!error; const isInvalid = hasError && (error.alwaysVisible || areErrorsVisible); + const canBeResetToDefault = defaultValue !== undefined; + const isResetToDefaultVisible = value !== defaultValue; + + const fieldHelpText = ( + + {helpText} + + {canBeResetToDefault && isResetToDefaultVisible && ( +

+ this.onFieldChange(defaultValue)}> + + +

+ )} +
+ ); return (