diff --git a/x-pack/plugins/cross_cluster_replication/public/app/app.js b/x-pack/plugins/cross_cluster_replication/public/app/app.js index e360d639d4279..e2f724edff63b 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/app.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/app.js @@ -10,7 +10,7 @@ import { Route, Switch, Redirect } from 'react-router-dom'; import chrome from 'ui/chrome'; import { fatalError } from 'ui/notify'; import { i18n } from '@kbn/i18n'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiEmptyPrompt, @@ -36,186 +36,187 @@ import { FollowerIndexEdit, } from './sections'; -export const App = injectI18n( - class extends Component { - static contextTypes = { - router: PropTypes.shape({ - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired - }).isRequired +export class App extends Component { + static contextTypes = { + router: PropTypes.shape({ + history: PropTypes.shape({ + push: PropTypes.func.isRequired, + createHref: PropTypes.func.isRequired }).isRequired - } + }).isRequired + } - constructor(...args) { - super(...args); - this.registerRouter(); + constructor(...args) { + super(...args); + this.registerRouter(); - this.state = { - isFetchingPermissions: false, - fetchPermissionError: undefined, - hasPermission: false, - missingClusterPrivileges: [], - }; - } + this.state = { + isFetchingPermissions: false, + fetchPermissionError: undefined, + hasPermission: false, + missingClusterPrivileges: [], + }; + } - componentWillMount() { - routing.userHasLeftApp = false; - } + componentWillMount() { + routing.userHasLeftApp = false; + } - componentDidMount() { - this.checkPermissions(); - } + componentDidMount() { + this.checkPermissions(); + } - componentWillUnmount() { - routing.userHasLeftApp = true; - } + componentWillUnmount() { + routing.userHasLeftApp = true; + } - async checkPermissions() { - this.setState({ - isFetchingPermissions: true, - }); + async checkPermissions() { + this.setState({ + isFetchingPermissions: true, + }); - try { - const { hasPermission, missingClusterPrivileges } = await loadPermissions(); + try { + const { hasPermission, missingClusterPrivileges } = await loadPermissions(); - this.setState({ + this.setState({ + isFetchingPermissions: false, + hasPermission, + missingClusterPrivileges, + }); + } catch (error) { + // Expect an error in the shape provided by Angular's $http service. + if (error && error.data) { + return this.setState({ isFetchingPermissions: false, - hasPermission, - missingClusterPrivileges, + fetchPermissionError: error, }); - } catch (error) { - // Expect an error in the shape provided by Angular's $http service. - if (error && error.data) { - return this.setState({ - isFetchingPermissions: false, - fetchPermissionError: error, - }); - } - - // This error isn't an HTTP error, so let the fatal error screen tell the user something - // unexpected happened. - fatalError(error, i18n.translate('xpack.crossClusterReplication.app.checkPermissionsFatalErrorTitle', { - defaultMessage: 'Cross Cluster Replication app', - })); } + + // This error isn't an HTTP error, so let the fatal error screen tell the user something + // unexpected happened. + fatalError(error, i18n.translate('xpack.crossClusterReplication.app.checkPermissionsFatalErrorTitle', { + defaultMessage: 'Cross Cluster Replication app', + })); } + } + + registerRouter() { + const { router } = this.context; + routing.reactRouter = router; + } + + render() { + const { + isFetchingPermissions, + fetchPermissionError, + hasPermission, + missingClusterPrivileges, + } = this.state; - registerRouter() { - const { router } = this.context; - routing.reactRouter = router; + if (!isAvailable() || !isActive()) { + return ( + + )} + > + {getReason()} + {' '} + + + + + ); } - render() { - const { - isFetchingPermissions, - fetchPermissionError, - hasPermission, - missingClusterPrivileges, - } = this.state; + if (isFetchingPermissions) { + return ( + + + + + + + + +

+ +

+
+
+
+
+ ); + } - if (!isAvailable() || !isActive()) { - return ( - + )} - > - {getReason()} - {' '} - - - - - ); - } + error={fetchPermissionError} + /> - if (isFetchingPermissions) { - return ( - - - - - - - - -

- -

-
-
-
-
- ); - } + + + ); + } - if (fetchPermissionError) { - return ( - - + - )} - error={fetchPermissionError} - /> - - - - ); - } - - if (!hasPermission) { - return ( - - - - } - body={ -

- -

} - /> -
- ); - } - - return ( -
- - - - - - - - -
+ } + body={ +

+ +

} + /> + ); } + + return ( +
+ + + + + + + + +
+ ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js index 95bb4528e0c84..e48347a171127 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_delete_provider.js @@ -7,7 +7,8 @@ import React, { PureComponent, Fragment } from 'react'; import { connect } from 'react-redux'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, EuiOverlayMask, @@ -16,7 +17,7 @@ import { import { deleteAutoFollowPattern } from '../store/actions'; import { arrify } from '../../../common/services/utils'; -class Provider extends PureComponent { +class AutoFollowPatternDeleteProviderUi extends PureComponent { state = { isModalOpen: false, ids: null @@ -44,18 +45,22 @@ class Provider extends PureComponent { }; renderModal = () => { - const { intl } = this.props; const { ids } = this.state; const isSingle = ids.length === 1; const title = isSingle - ? intl.formatMessage({ - id: 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.deleteSingleTitle', - defaultMessage: 'Remove auto-follow pattern \'{name}\'?', - }, { name: ids[0] }) - : intl.formatMessage({ - id: 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.deleteMultipleTitle', - defaultMessage: 'Remove {count} auto-follow patterns?', - }, { count: ids.length }); + ? i18n.translate( + 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.deleteSingleTitle', + { + defaultMessage: `Remove auto-follow pattern '{name}'?`, + values: { name: ids[0] } + } + ) : i18n.translate( + 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.deleteMultipleTitle', + { + defaultMessage: `Remove {count} auto-follow patterns?`, + values: { count: ids.length } + } + ); return ( @@ -65,17 +70,21 @@ class Provider extends PureComponent { onCancel={this.closeConfirmModal} onConfirm={this.onConfirm} cancelButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.cancelButtonText', - defaultMessage: 'Cancel', - }) + i18n.translate( + 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel' + } + ) } buttonColor="danger" confirmButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.confirmButtonText', - defaultMessage: 'Remove', - }) + i18n.translate( + 'xpack.crossClusterReplication.deleteAutoFollowPattern.confirmModal.confirmButtonText', + { + defaultMessage: 'Remove' + } + ) } onMouseOver={this.onMouseOverModal} > @@ -115,5 +124,5 @@ const mapDispatchToProps = dispatch => ({ export const AutoFollowPatternDeleteProvider = connect( undefined, mapDispatchToProps -)(injectI18n(Provider)); +)(AutoFollowPatternDeleteProviderUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js index 1463560909edb..8e29caab8ad00 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/auto_follow_pattern_form.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -58,7 +59,7 @@ export const updateFormErrors = (errors, existingErrors) => ({ } }); -export class AutoFollowPatternFormUI extends PureComponent { +export class AutoFollowPatternForm extends PureComponent { static propTypes = { saveAutoFollowPattern: PropTypes.func.isRequired, autoFollowPattern: PropTypes.object, @@ -154,11 +155,12 @@ export class AutoFollowPatternFormUI extends PureComponent { const { autoFollowPattern: { leaderIndexPatterns } } = this.state; if (leaderIndexPatterns.includes(leaderIndexPattern)) { - const { intl } = this.props; - const errorMsg = intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternForm.leaderIndexPatternError.duplicateMessage', - defaultMessage: `Duplicate leader index pattern aren't allowed.`, - }); + const errorMsg = i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternForm.leaderIndexPatternError.duplicateMessage', + { + defaultMessage: `Duplicate leader index pattern aren't allowed.` + } + ); const errors = { leaderIndexPatterns: { @@ -212,12 +214,11 @@ export class AutoFollowPatternFormUI extends PureComponent { * Secctions Renders */ renderApiErrors() { - const { apiError, intl } = this.props; + const { apiError } = this.props; if (apiError) { - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternForm.savingErrorTitle', - defaultMessage: `Can't create auto-follow pattern`, + const title = i18n.translate('xpack.crossClusterReplication.autoFollowPatternForm.savingErrorTitle', { + defaultMessage: `Can't create auto-follow pattern` }); return ( @@ -232,7 +233,6 @@ export class AutoFollowPatternFormUI extends PureComponent { } renderForm = () => { - const { intl } = this.props; const { autoFollowPattern: { name, @@ -436,10 +436,12 @@ export class AutoFollowPatternFormUI extends PureComponent { > { +export const AutoFollowPatternIndicesPreview = ({ prefix, suffix, leaderIndexPatterns }) => { const { indicesPreview } = getPreviewIndicesFromAutoFollowPattern({ prefix, suffix, leaderIndexPatterns }); - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewTitle', - defaultMessage: 'Index name examples', - }); + const title = i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewTitle', + { + defaultMessage: 'Index name examples' + } + ); return ( ); -}); +}; 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 84e0d58191d27..d113c348a5a54 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 @@ -160,9 +160,9 @@ export const advancedSettingsFields = [ ), description: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteBufferCountDescription', { - defaultMessage: `The maximum number of operations that can be queued for writing; when this - limit is reached, reads from the remote cluster will be deferred until the number of queued - operations goes below the limit.` + defaultMessage: 'The maximum number of operations that can be queued for writing; when this ' + + 'limit is reached, reads from the remote cluster will be deferred until the number of queued ' + + 'operations goes below the limit.' } ), label: i18n.translate( @@ -181,9 +181,9 @@ export const advancedSettingsFields = [ ), description: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxWriteBufferSizeDescription', { - defaultMessage: `The maximum total bytes of operations that can be queued for writing; when - this limit is reached, reads from the remote cluster will be deferred until the total bytes - of queued operations goes below the limit.` + defaultMessage: 'The maximum total bytes of operations that can be queued for writing; when ' + + 'this limit is reached, reads from the remote cluster will be deferred until the total bytes ' + + 'of queued operations goes below the limit.' } ), label: i18n.translate( @@ -202,8 +202,8 @@ export const advancedSettingsFields = [ ), description: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.maxRetryDelayDescription', { - defaultMessage: `The maximum time to wait before retrying an operation that failed exceptionally; - an exponential backoff strategy is employed when retrying.` + defaultMessage: 'The maximum time to wait before retrying an operation that failed exceptionally; ' + + 'an exponential backoff strategy is employed when retrying.' } ), label: i18n.translate( @@ -222,10 +222,10 @@ export const advancedSettingsFields = [ ), description: i18n.translate( 'xpack.crossClusterReplication.followerIndexForm.advancedSettings.readPollTimeoutDescription', { - defaultMessage: `The maximum time to wait for new operations on the remote cluster when the - follower index is synchronized with the leader index; when the timeout has elapsed, the - poll for operations will return to the follower so that it can update some statistics, and - then the follower will immediately attempt to read from the leader again.` + defaultMessage: 'The maximum time to wait for new operations on the remote cluster when the ' + + 'follower index is synchronized with the leader index; when the timeout has elapsed, the ' + + 'poll for operations will return to the follower so that it can update some statistics, and ' + + 'then the follower will immediately attempt to read from the leader again.' } ), label: i18n.translate( 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 1d3bf8d60db21..8f1347adcfef9 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 @@ -8,7 +8,7 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import { debounce } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices'; import { fatalError } from 'ui/notify'; @@ -83,637 +83,632 @@ export const updateFormErrors = (errors) => ({ fieldsErrors }) => ({ } }); -export const FollowerIndexForm = injectI18n( - class extends PureComponent { - static propTypes = { - saveFollowerIndex: PropTypes.func.isRequired, - clearApiError: PropTypes.func.isRequired, - followerIndex: PropTypes.object, - apiError: PropTypes.object, - apiStatus: PropTypes.string.isRequired, - remoteClusters: PropTypes.array, - saveButtonLabel: PropTypes.node, - } +export class FollowerIndexForm extends PureComponent { + static propTypes = { + saveFollowerIndex: PropTypes.func.isRequired, + clearApiError: PropTypes.func.isRequired, + followerIndex: PropTypes.object, + apiError: PropTypes.object, + apiStatus: PropTypes.string.isRequired, + remoteClusters: PropTypes.array, + saveButtonLabel: PropTypes.node, + } - constructor(props) { - super(props); + constructor(props) { + super(props); - const { route: { location: { search } } } = routing.reactRouter; - const queryParams = extractQueryParams(search); + 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) - : { - ...getEmptyFollowerIndex(), - ...this.props.followerIndex, - }; - const areAdvancedSettingsVisible = isNew ? false : ( // eslint-disable-line no-nested-ternary - areAdvancedSettingsEdited(followerIndex) ? true : false - ); + const isNew = this.props.followerIndex === undefined; + const remoteClusterName = getRemoteClusterName(this.props.remoteClusters, queryParams.cluster); + const followerIndex = isNew + ? getEmptyFollowerIndex(remoteClusterName) + : { + ...getEmptyFollowerIndex(), + ...this.props.followerIndex, + }; + const areAdvancedSettingsVisible = isNew ? false : ( // eslint-disable-line no-nested-ternary + areAdvancedSettingsEdited(followerIndex) ? true : false + ); + + const fieldsErrors = this.getFieldsErrors(followerIndex); + + this.state = { + isNew, + followerIndex, + fieldsErrors, + areErrorsVisible: false, + areAdvancedSettingsVisible, + isValidatingIndexName: false, + }; - const fieldsErrors = this.getFieldsErrors(followerIndex); + this.cachedAdvancedSettings = {}; + this.validateIndexName = debounce(this.validateIndexName, 500); + } - this.state = { - isNew, - followerIndex, - fieldsErrors, - areErrorsVisible: false, - areAdvancedSettingsVisible, - isValidatingIndexName: false, - }; + onFieldsChange = (fields) => { + this.setState(updateFields(fields)); - this.cachedAdvancedSettings = {}; - this.validateIndexName = debounce(this.validateIndexName, 500); - } + const newFields = { + ...this.state.fields, + ...fields, + }; - onFieldsChange = (fields) => { - this.setState(updateFields(fields)); + this.setState(updateFormErrors(this.getFieldsErrors(newFields))); - const newFields = { - ...this.state.fields, - ...fields, - }; + if (this.props.apiError) { + this.props.clearApiError(); + } + }; - this.setState(updateFormErrors(this.getFieldsErrors(newFields))); + getFieldsErrors = (newFields) => { + return Object.keys(newFields).reduce((errors, field) => { + const validator = fieldToValidatorMap[field]; + const value = newFields[field]; - if (this.props.apiError) { - this.props.clearApiError(); + if (validator) { + const error = validator(value); + errors[field] = error; } - }; - getFieldsErrors = (newFields) => { - return Object.keys(newFields).reduce((errors, field) => { - const validator = fieldToValidatorMap[field]; - const value = newFields[field]; + return errors; + }, {}); + }; - if (validator) { - const error = validator(value); - errors[field] = error; - } + onIndexNameChange = ({ name }) => { + this.onFieldsChange({ name }); - return errors; - }, {}); - }; + if (!name || !name.trim()) { + this.setState({ + isValidatingIndexName: false, + }); - onIndexNameChange = ({ name }) => { - this.onFieldsChange({ name }); + return; + } - if (!name || !name.trim()) { - this.setState({ - isValidatingIndexName: false, - }); + this.setState({ + isValidatingIndexName: true, + }); - return; + this.validateIndexName(name); + }; + + validateIndexName = async (name) => { + try { + const indices = await loadIndices(); + const doesExist = indices.some(index => index.name === name); + if (doesExist) { + const error = { + message: ( + + ), + alwaysVisible: true, + }; + + this.setState(updateFormErrors({ name: error })); } this.setState({ - isValidatingIndexName: true, + isValidatingIndexName: false, }); + } catch (error) { + // Expect an error in the shape provided by Angular's $http service. + if (error && error.data) { + // All validation does is check for a name collision, so we can just let the user attempt + // to save the follower index and get an error back from the API. + return this.setState({ + isValidatingIndexName: false, + }); + } - this.validateIndexName(name); - }; + // This error isn't an HTTP error, so let the fatal error screen tell the user something + // unexpected happened. + fatalError(error, i18n.translate('xpack.crossClusterReplication.followerIndexForm.indexNameValidationFatalErrorTitle', { + defaultMessage: 'Follower Index Form index name validation', + })); + } + }; - validateIndexName = async (name) => { - try { - const indices = await loadIndices(); - const doesExist = indices.some(index => index.name === name); - if (doesExist) { - const error = { - message: ( - - ), - alwaysVisible: true, - }; + onClusterChange = (remoteCluster) => { + this.onFieldsChange({ remoteCluster }); + }; - this.setState(updateFormErrors({ name: error })); - } + getFields = () => { + return this.state.followerIndex; + }; - this.setState({ - isValidatingIndexName: false, - }); - } catch (error) { - // Expect an error in the shape provided by Angular's $http service. - if (error && error.data) { - // All validation does is check for a name collision, so we can just let the user attempt - // to save the follower index and get an error back from the API. - return this.setState({ - isValidatingIndexName: false, - }); - } + 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); - // This error isn't an HTTP error, so let the fatal error screen tell the user something - // unexpected happened. - fatalError(error, i18n.translate('xpack.crossClusterReplication.followerIndexForm.indexNameValidationFatalErrorTitle', { - defaultMessage: 'Follower Index Form index name validation', - })); - } - }; + // Reset the cache of the advanced settings. + this.cachedAdvancedSettings = {}; - onClusterChange = (remoteCluster) => { - this.onFieldsChange({ remoteCluster }); - }; + // Show the advanced settings. + return this.setState({ + areAdvancedSettingsVisible: true, + }); + } - getFields = () => { - return this.state.followerIndex; - }; + // Clear the advanced settings form. + this.onFieldsChange(emptyAdvancedSettings); - 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); + // 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; + }, {}); - // Reset the cache of the advanced settings. - this.cachedAdvancedSettings = {}; + // Hide the advanced settings. + this.setState({ + areAdvancedSettingsVisible: false, + }); + } - // Show the advanced settings. - return this.setState({ - areAdvancedSettingsVisible: true, - }); - } + isFormValid() { + return Object.values(this.state.fieldsErrors).every(error => error === undefined || error === null); + } - // Clear the advanced settings form. - this.onFieldsChange(emptyAdvancedSettings); + sendForm = () => { + const isFormValid = this.isFormValid(); - // 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; - }, {}); + this.setState({ areErrorsVisible: !isFormValid }); - // Hide the advanced settings. - this.setState({ - areAdvancedSettingsVisible: false, - }); + if (!isFormValid) { + return; } - isFormValid() { - return Object.values(this.state.fieldsErrors).every(error => error === undefined || error === null); - } + const { name, ...followerIndex } = this.getFields(); - sendForm = () => { - const isFormValid = this.isFormValid(); + this.props.saveFollowerIndex(name, followerIndex); + }; - this.setState({ areErrorsVisible: !isFormValid }); + cancelForm = () => { + routing.navigate('/follower_indices'); + }; - if (!isFormValid) { - return; - } + /** + * Sections Renders + */ + renderApiErrors() { + const { apiError } = this.props; - const { name, ...followerIndex } = this.getFields(); + if (apiError) { + const title = i18n.translate('xpack.crossClusterReplication.followerIndexForm.savingErrorTitle', { + defaultMessage: `Can't create follower index`, + }); + const { leaderIndex } = this.state.followerIndex; + const error = apiError.status === 404 + ? { + data: { + message: i18n.translate('xpack.crossClusterReplication.followerIndexForm.leaderIndexNotFoundError', { + defaultMessage: `The leader index '{leaderIndex}' does not exist.`, + values: { leaderIndex }, + }), + }, + } + : apiError; - this.props.saveFollowerIndex(name, followerIndex); - }; + return ( + + + + + ); + } - cancelForm = () => { - routing.navigate('/follower_indices'); - }; + return null; + } + + renderForm = () => { + const { + followerIndex, + isNew, + areErrorsVisible, + areAdvancedSettingsVisible, + fieldsErrors, + isValidatingIndexName, + } = this.state; /** - * Sections Renders + * Follower index name */ - renderApiErrors() { - const { apiError, intl } = this.props; - - if (apiError) { - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexForm.savingErrorTitle', - defaultMessage: `Can't create follower index`, - }); - const { leaderIndex } = this.state.followerIndex; - const error = apiError.status === 404 - ? { - data: { - message: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexForm.leaderIndexNotFoundError', - defaultMessage: `The leader index '{leaderIndex}' does not exist.`, - }, { leaderIndex }) - } - } - : apiError; - - return ( - - - - - ); - } - - return null; - } - renderForm = () => { - const { - followerIndex, - isNew, - areErrorsVisible, - areAdvancedSettingsVisible, - fieldsErrors, - isValidatingIndexName, - } = this.state; - - /** - * Follower index name - */ - - const indexNameHelpText = ( - - {isValidatingIndexName && ( -

- -

- )} + const indexNameHelpText = ( + + {isValidatingIndexName && (

{indexNameIllegalCharacters} }} + id="xpack.crossClusterReplication.followerIndexForm.indexNameValidatingLabel" + defaultMessage="Checking availability…" />

-
- ); + )} +

+ {indexNameIllegalCharacters} }} + /> +

+
+ ); + + const indexNameLabel = i18n.translate( + 'xpack.crossClusterReplication.followerIndexForm.sectionFollowerIndexNameTitle', + { + defaultMessage: 'Follower index' + } + ); + + const renderFollowerIndexName = () => ( + +

{indexNameLabel}

+ + )} + label={indexNameLabel} + description={i18n.translate('xpack.crossClusterReplication.followerIndexForm.sectionFollowerIndexNameDescription', { + defaultMessage: 'A unique name for your index.' + })} + helpText={indexNameHelpText} + isLoading={isValidatingIndexName} + disabled={!isNew} + areErrorsVisible={areErrorsVisible} + onValueUpdate={this.onIndexNameChange} + /> + ); - const indexNameLabel = i18n.translate( - 'xpack.crossClusterReplication.followerIndexForm.sectionFollowerIndexNameTitle', - { - defaultMessage: 'Follower index' - } - ); + /** + * Remote Cluster + */ + const renderRemoteClusterField = () => { + const { remoteClusters, currentUrl } = this.props; + + const errorMessages = { + noClusterFound: () => ( + + ), + remoteClusterNotConnectedNotEditable: (name) => ({ + title: ( + + ), + description: ( + + ), + }), + remoteClusterDoesNotExist: (name) => ( + + ), + }; - const renderFollowerIndexName = () => ( - -

{indexNameLabel}

+

+ +

)} - label={indexNameLabel} - description={i18n.translate('xpack.crossClusterReplication.followerIndexForm.sectionFollowerIndexNameDescription', { - defaultMessage: 'A unique name for your index.' - })} - helpText={indexNameHelpText} - isLoading={isValidatingIndexName} - disabled={!isNew} - areErrorsVisible={areErrorsVisible} - onValueUpdate={this.onIndexNameChange} - /> + description={( + + )} + fullWidth + > + { + this.setState(updateFormErrors({ remoteCluster: error })); + }} + errorMessages={errorMessages} + /> + ); + }; - /** - * Remote Cluster - */ - const renderRemoteClusterField = () => { - const { remoteClusters, currentUrl } = this.props; + /** + * Leader index + */ - const errorMessages = { - noClusterFound: () => ( - - ), - remoteClusterNotConnectedNotEditable: (name) => ({ - title: ( + const leaderIndexLabel = i18n.translate( + 'xpack.crossClusterReplication.followerIndexForm.sectionLeaderIndexTitle', { + defaultMessage: 'Leader index' + } + ); + + const renderLeaderIndex = () => ( + +

{leaderIndexLabel}

+ + )} + label={leaderIndexLabel} + description={( + +

- ), - description: ( +

+ +

+ + + ) }} /> - ), - }), - remoteClusterDoesNotExist: (name) => ( - - ), - }; +

+
+ )} + helpText={( + {indexNameIllegalCharacters} }} + /> + )} + disabled={!isNew} + areErrorsVisible={areErrorsVisible} + onValueUpdate={this.onFieldsChange} + /> + ); - return ( + /** + * Advanced settings + */ + + const renderAdvancedSettings = () => { + return ( + +

)} description={( - + +

+ +

+ + + )} + checked={areAdvancedSettingsVisible} + onChange={this.toggleAdvancedSettings} + /> +
)} fullWidth > - { - this.setState(updateFormErrors({ remoteCluster: error })); - }} - errorMessages={errorMessages} - /> + {/* Avoid missing `children` warning */}
- ); - }; - - /** - * Leader index - */ - - const leaderIndexLabel = i18n.translate( - 'xpack.crossClusterReplication.followerIndexForm.sectionLeaderIndexTitle', { - defaultMessage: 'Leader index' - } - ); - const renderLeaderIndex = () => ( - -

{leaderIndexLabel}

- - )} - label={leaderIndexLabel} - description={( + {areAdvancedSettingsVisible && ( -

- -

- -

- - - - ) }} - /> -

+ + {advancedSettingsFields.map((advancedSetting) => { + const { field, title, description, label, helpText, defaultValue, type } = advancedSetting; + return ( + +

{title}

+ + )} + description={description} + label={label} + helpText={helpText} + type={type} + areErrorsVisible={areErrorsVisible} + onValueUpdate={this.onFieldsChange} + /> + ); + })}
)} - helpText={( - {indexNameIllegalCharacters} }} - /> - )} - disabled={!isNew} - areErrorsVisible={areErrorsVisible} - onValueUpdate={this.onFieldsChange} - /> + +
); + }; - /** - * Advanced settings - */ + /** + * Form Error warning message + */ + const renderFormErrorWarning = () => { + const { areErrorsVisible } = this.state; + const isFormValid = this.isFormValid(); - const renderAdvancedSettings = () => { - return ( - - - -

- -

- - )} - description={( - -

- -

- - - )} - checked={areAdvancedSettingsVisible} - onChange={this.toggleAdvancedSettings} - /> -
- )} - fullWidth - > - {/* Avoid missing `children` warning */} -
+ if (!areErrorsVisible || isFormValid) { + return null; + } - {areAdvancedSettingsVisible && ( - - - {advancedSettingsFields.map((advancedSetting) => { - const { field, title, description, label, helpText, defaultValue, type } = advancedSetting; - return ( - -

{title}

- - )} - description={description} - label={label} - helpText={helpText} - type={type} - areErrorsVisible={areErrorsVisible} - onValueUpdate={this.onFieldsChange} - /> - ); - })} -
+ return ( + + )} - - - ); - }; - - /** - * Form Error warning message - */ - const renderFormErrorWarning = () => { - const { areErrorsVisible } = this.state; - const isFormValid = this.isFormValid(); - - if (!areErrorsVisible || isFormValid) { - return null; - } + color="danger" + iconType="cross" + /> - return ( - - - )} - color="danger" - iconType="cross" - /> - - - - ); - }; - - /** - * Form Actions - */ - const renderActions = () => { - const { apiStatus, saveButtonLabel } = this.props; - const { areErrorsVisible } = this.state; - - if (apiStatus === API_STATUS.SAVING) { - return ( - - - - - - - - - - - - ); - } + +
+ ); + }; - const isSaveDisabled = areErrorsVisible && !this.isFormValid(); + /** + * Form Actions + */ + const renderActions = () => { + const { apiStatus, saveButtonLabel } = this.props; + const { areErrorsVisible } = this.state; + if (apiStatus === API_STATUS.SAVING) { return ( - + - - {saveButtonLabel} - + - + - + ); - }; + } + + const isSaveDisabled = areErrorsVisible && !this.isFormValid(); return ( - - - {renderRemoteClusterField()} - {renderLeaderIndex()} - {renderFollowerIndexName()} - - {renderAdvancedSettings()} - - - {renderFormErrorWarning()} - {this.renderApiErrors()} - {renderActions()} - + + + + {saveButtonLabel} + + + + + + + + + ); - } + }; - renderLoading = () => { - const { apiStatus } = this.props; + return ( + + + {renderRemoteClusterField()} + {renderLeaderIndex()} + {renderFollowerIndexName()} + + {renderAdvancedSettings()} + + + {renderFormErrorWarning()} + {this.renderApiErrors()} + {renderActions()} + + ); + } - if (apiStatus === API_STATUS.SAVING) { - return ( - - - - ); - } - return null; - } + renderLoading = () => { + const { apiStatus } = this.props; - render() { + if (apiStatus === API_STATUS.SAVING) { return ( - - {this.renderForm()} - {this.renderLoading()} - + + + ); } + return null; } -); - + render() { + return ( + + {this.renderForm()} + {this.renderLoading()} + + ); + } +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_pause_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_pause_provider.js index a745022e12f6a..3beb0353b4e38 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_pause_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_pause_provider.js @@ -7,7 +7,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, EuiOverlayMask, @@ -17,7 +18,7 @@ import { pauseFollowerIndex } from '../store/actions'; import { arrify } from '../../../common/services/utils'; import { areAllSettingsDefault } from '../services/follower_index_default_settings'; -class Provider extends PureComponent { +class FollowerIndexPauseProviderUi extends PureComponent { static propTypes = { onConfirm: PropTypes.func, } @@ -50,18 +51,17 @@ class Provider extends PureComponent { }; renderModal = () => { - const { intl } = this.props; const { indices } = this.state; const isSingle = indices.length === 1; const title = isSingle - ? intl.formatMessage({ - id: 'xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.pauseSingleTitle', - defaultMessage: 'Pause replication to follower index \'{name}\'?', - }, { name: indices[0].name }) - : intl.formatMessage({ - id: 'xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.pauseMultipleTitle', + ? i18n.translate('xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.pauseSingleTitle', { + defaultMessage: `Pause replication to follower index '{name}'?`, + values: { name: indices[0].name }, + }) + : i18n.translate('xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.pauseMultipleTitle', { defaultMessage: 'Pause replication to {count} follower indices?', - }, { count: indices.length }); + values: { count: indices.length }, + }); const hasCustomSettings = indices.some(index => !areAllSettingsDefault(index)); return ( @@ -72,14 +72,12 @@ class Provider extends PureComponent { onCancel={this.closeConfirmModal} onConfirm={this.onConfirm} cancelButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.cancelButtonText', + i18n.translate('xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.cancelButtonText', { defaultMessage: 'Cancel', }) } buttonColor={hasCustomSettings ? 'danger' : 'primary'} - confirmButtonText={intl.formatMessage({ - id: 'xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.confirmButtonText', + confirmButtonText={i18n.translate('xpack.crossClusterReplication.pauseFollowerIndex.confirmModal.confirmButtonText', { defaultMessage: 'Pause replication', })} onMouseOver={this.onMouseOverModal} @@ -141,5 +139,5 @@ const mapDispatchToProps = (dispatch) => ({ export const FollowerIndexPauseProvider = connect( undefined, mapDispatchToProps -)(injectI18n(Provider)); +)(FollowerIndexPauseProviderUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_resume_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_resume_provider.js index a97153f314287..c465a9a107627 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_resume_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_resume_provider.js @@ -7,7 +7,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, EuiLink, @@ -18,7 +19,7 @@ import routing from '../services/routing'; import { resumeFollowerIndex } from '../store/actions'; import { arrify } from '../../../common/services/utils'; -class Provider extends PureComponent { +class FollowerIndexResumeProviderUi extends PureComponent { static propTypes = { onConfirm: PropTypes.func, } @@ -51,18 +52,22 @@ class Provider extends PureComponent { }; renderModal = () => { - const { intl } = this.props; const { ids } = this.state; const isSingle = ids.length === 1; const title = isSingle - ? intl.formatMessage({ - id: 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.resumeSingleTitle', - defaultMessage: 'Resume replication to follower index \'{name}\'?', - }, { name: ids[0] }) - : intl.formatMessage({ - id: 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.resumeMultipleTitle', - defaultMessage: 'Resume replication to {count} follower indices?', - }, { count: ids.length }); + ? i18n.translate( + 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.resumeSingleTitle', + { + defaultMessage: `Resume replication to follower index '{name}'?`, + values: { name: ids[0] } + } + ) : i18n.translate( + 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.resumeMultipleTitle', + { + defaultMessage: `Resume replication to {count} follower indices?`, + values: { count: ids.length } + } + ); return ( @@ -72,17 +77,21 @@ class Provider extends PureComponent { onCancel={this.closeConfirmModal} onConfirm={this.onConfirm} cancelButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.cancelButtonText', - defaultMessage: 'Cancel', - }) + i18n.translate( + 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel' + } + ) } buttonColor="primary" confirmButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.confirmButtonText', - defaultMessage: 'Resume replication', - }) + i18n.translate( + 'xpack.crossClusterReplication.resumeFollowerIndex.confirmModal.confirmButtonText', + { + defaultMessage: 'Resume replication' + } + ) } onMouseOver={this.onMouseOverModal} > @@ -150,5 +159,5 @@ const mapDispatchToProps = (dispatch) => ({ export const FollowerIndexResumeProvider = connect( undefined, mapDispatchToProps -)(injectI18n(Provider)); +)(FollowerIndexResumeProviderUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_unfollow_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_unfollow_provider.js index 2b0f6931044af..07d69cee659c8 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_unfollow_provider.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/follower_index_unfollow_provider.js @@ -7,7 +7,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiConfirmModal, EuiOverlayMask, @@ -16,7 +17,7 @@ import { import { unfollowLeaderIndex } from '../store/actions'; import { arrify } from '../../../common/services/utils'; -class Provider extends PureComponent { +class FollowerIndexUnfollowProviderUi extends PureComponent { static propTypes = { onConfirm: PropTypes.func, } @@ -49,18 +50,22 @@ class Provider extends PureComponent { }; renderModal = () => { - const { intl } = this.props; const { ids } = this.state; const isSingle = ids.length === 1; const title = isSingle - ? intl.formatMessage({ - id: 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.unfollowSingleTitle', - defaultMessage: `Unfollow leader index of '{name}'?`, - }, { name: ids[0] }) - : intl.formatMessage({ - id: 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.unfollowMultipleTitle', - defaultMessage: 'Unfollow {count} leader indices?', - }, { count: ids.length }); + ? i18n.translate( + 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.unfollowSingleTitle', + { + defaultMessage: `Unfollow leader index of '{name}'?`, + values: { name: ids[0] } + } + ) : i18n.translate( + 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.unfollowMultipleTitle', + { + defaultMessage: `Unfollow {count} leader indices?`, + values: { count: ids.length } + } + ); return ( @@ -70,17 +75,21 @@ class Provider extends PureComponent { onCancel={this.closeConfirmModal} onConfirm={this.onConfirm} cancelButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.cancelButtonText', - defaultMessage: 'Cancel', - }) + i18n.translate( + 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.cancelButtonText', + { + defaultMessage: 'Cancel' + } + ) } buttonColor="danger" confirmButtonText={ - intl.formatMessage({ - id: 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.confirmButtonText', - defaultMessage: 'Unfollow leader', - }) + i18n.translate( + 'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.confirmButtonText', + { + defaultMessage: 'Unfollow leader' + } + ) } onMouseOver={this.onMouseOverModal} > @@ -133,5 +142,5 @@ const mapDispatchToProps = (dispatch) => ({ export const FollowerIndexUnfollowProvider = connect( undefined, mapDispatchToProps -)(injectI18n(Provider)); +)(FollowerIndexUnfollowProviderUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_form_field.js b/x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_form_field.js index 224b5f295f7ce..809a81553dcb7 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_form_field.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_form_field.js @@ -6,7 +6,8 @@ import React, { Fragment, PureComponent } from 'react'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiButtonEmpty, @@ -24,298 +25,298 @@ import { BASE_PATH_REMOTE_CLUSTERS } from '../../../common/constants'; const errorMessages = { noClusterFound: () => ( ), remoteClusterNotConnectedEditable: (name) => ({ title: ( ), description: ( ), }), }; -export const RemoteClustersFormField = injectI18n( - class extends PureComponent { - errorMessages = { - ...errorMessages, - ...this.props.errorMessages - } - - componentDidMount() { - const { selected, onError } = this.props; - const { error } = this.validateRemoteCluster(selected); +export class RemoteClustersFormField extends PureComponent { + errorMessages = { + ...errorMessages, + ...this.props.errorMessages + } - onError(error); - } + componentDidMount() { + const { selected, onError } = this.props; + const { error } = this.validateRemoteCluster(selected); - validateRemoteCluster(clusterName) { - const { remoteClusters } = this.props; - const remoteCluster = remoteClusters.find(c => c.name === clusterName); + onError(error); + } - return remoteCluster && remoteCluster.isConnected - ? { error: null } - : { error: { message: ( - - ) } }; - } + validateRemoteCluster(clusterName) { + const { remoteClusters } = this.props; + const remoteCluster = remoteClusters.find(c => c.name === clusterName); - onRemoteClusterChange = (cluster) => { - const { onChange, onError } = this.props; - const { error } = this.validateRemoteCluster(cluster); - onChange(cluster); - onError(error); - }; + return remoteCluster && remoteCluster.isConnected + ? { error: null } + : { error: { message: ( + + ) } }; + } - renderNotEditable = () => { - const { areErrorsVisible } = this.props; - const errorMessage = this.renderErrorMessage(); + onRemoteClusterChange = (cluster) => { + const { onChange, onError } = this.props; + const { error } = this.validateRemoteCluster(cluster); + onChange(cluster); + onError(error); + }; - return ( - - - { areErrorsVisible && Boolean(errorMessage) ? this.renderValidRemoteClusterRequired() : null } - { errorMessage } - - ); - }; + renderNotEditable = () => { + const { areErrorsVisible } = this.props; + const errorMessage = this.renderErrorMessage(); - renderValidRemoteClusterRequired = () => ( - - + - + { areErrorsVisible && Boolean(errorMessage) ? this.renderValidRemoteClusterRequired() : null } + { errorMessage } + ); + }; - renderDropdown = () => { - const { remoteClusters, selected, currentUrl, areErrorsVisible } = this.props; - const hasClusters = Boolean(remoteClusters.length); - const remoteClustersOptions = hasClusters ? remoteClusters.map(({ name, isConnected }) => ({ - value: name, - text: isConnected ? name : this.props.intl.formatMessage({ - id: 'xpack.crossClusterReplication.forms.remoteClusterDropdownNotConnected', - defaultMessage: '{name} (not connected)', - }, { name }), - 'data-test-subj': `option-${name}` - })) : []; - const errorMessage = this.renderErrorMessage(); - - return ( - - { this.onRemoteClusterChange(e.target.value); }} - hasNoInitialSelection={!hasClusters} - isInvalid={areErrorsVisible && Boolean(errorMessage)} - /> - { areErrorsVisible && Boolean(errorMessage) ? this.renderValidRemoteClusterRequired() : null } - { errorMessage } + renderValidRemoteClusterRequired = () => ( + + + + ); - - -
{/* Break out of EuiFormRow's flexbox layout */} - - - -
-
-
- ); - }; + renderDropdown = () => { + const { remoteClusters, selected, currentUrl, areErrorsVisible } = this.props; + const hasClusters = Boolean(remoteClusters.length); + const remoteClustersOptions = hasClusters ? remoteClusters.map(({ name, isConnected }) => ({ + value: name, + text: isConnected ? name : i18n.translate( + 'xpack.crossClusterReplication.remoteClustersFormField.remoteClusterDropdownNotConnected', + { + defaultMessage: '{name} (not connected)', + values: { name }, + } + ), + 'data-test-subj': `option-${name}` + })) : []; + const errorMessage = this.renderErrorMessage(); - renderNoClusterFound = () => { - const { intl, currentUrl } = this.props; - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.forms.emptyRemoteClustersCallOutTitle', - defaultMessage: `You don't have any remote clusters`, - }); + return ( + + { this.onRemoteClusterChange(e.target.value); }} + hasNoInitialSelection={!hasClusters} + isInvalid={areErrorsVisible && Boolean(errorMessage)} + /> + { areErrorsVisible && Boolean(errorMessage) ? this.renderValidRemoteClusterRequired() : null } + { errorMessage } - return ( - -

- { this.errorMessages.noClusterFound() } -

- - +
{/* Break out of EuiFormRow's flexbox layout */} + - - + +
- ); - }; - - renderCurrentRemoteClusterNotConnected = (name, fatal) => { - const { isEditable, currentUrl } = this.props; - const { - remoteClusterNotConnectedEditable, - remoteClusterNotConnectedNotEditable, - } = this.errorMessages; - - const { title, description } = isEditable - ? remoteClusterNotConnectedEditable(name) - : remoteClusterNotConnectedNotEditable(name); - - return ( - -

- { description } -

- - - - -
- ); - }; +
+ ); + }; - renderRemoteClusterDoesNotExist = (name) => { - const { intl, currentUrl } = this.props; - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.forms.remoteClusterNotFoundTitle', - defaultMessage: `Couldn't find remote cluster '{name}'`, - }, { name }); + renderNoClusterFound = () => { + const { currentUrl } = this.props; + const title = i18n.translate('xpack.crossClusterReplication.remoteClustersFormField.emptyRemoteClustersCallOutTitle', { + defaultMessage: `You don't have any remote clusters` + }); - return ( + return ( +

- { this.errorMessages.remoteClusterDoesNotExist(name) } + { this.errorMessages.noClusterFound() }

+
- ); - } +
+ ); + }; - renderErrorMessage = () => { - const { selected, remoteClusters, isEditable } = this.props; - const remoteCluster = remoteClusters.find(c => c.name === selected); - const isSelectedRemoteClusterConnected = remoteCluster && remoteCluster.isConnected; - let error; + renderCurrentRemoteClusterNotConnected = (name, fatal) => { + const { isEditable, currentUrl } = this.props; + const { + remoteClusterNotConnectedEditable, + remoteClusterNotConnectedNotEditable, + } = this.errorMessages; - if (isEditable) { - /* Create */ - const hasClusters = Boolean(remoteClusters.length); - if (hasClusters && !isSelectedRemoteClusterConnected) { - error = this.renderCurrentRemoteClusterNotConnected(selected); - } else if (!hasClusters) { - error = this.renderNoClusterFound(); - } - } else { - /* Edit */ - const doesExists = !!remoteCluster; - if (!doesExists) { - error = this.renderRemoteClusterDoesNotExist(selected); - } else if (!isSelectedRemoteClusterConnected) { - error = this.renderCurrentRemoteClusterNotConnected(selected, true); - } - } + const { title, description } = isEditable + ? remoteClusterNotConnectedEditable(name) + : remoteClusterNotConnectedNotEditable(name); - return error ? ( - - - {error} - - ) : null; - } + return ( + +

+ { description } +

+ + + + +
+ ); + }; + + renderRemoteClusterDoesNotExist = (name) => { + const { currentUrl } = this.props; + const title = i18n.translate('xpack.crossClusterReplication.remoteClustersFormField.remoteClusterNotFoundTitle', { + defaultMessage: `Couldn't find remote cluster '{name}'`, + values: { name } + }); - render() { - const { remoteClusters, selected, isEditable, areErrorsVisible } = this.props; - const remoteCluster = remoteClusters.find(c => c.name === selected); + return ( + +

+ { this.errorMessages.remoteClusterDoesNotExist(name) } +

+ + + +
+ ); + } + + renderErrorMessage = () => { + const { selected, remoteClusters, isEditable } = this.props; + const remoteCluster = remoteClusters.find(c => c.name === selected); + const isSelectedRemoteClusterConnected = remoteCluster && remoteCluster.isConnected; + let error; + + if (isEditable) { + /* Create */ const hasClusters = Boolean(remoteClusters.length); - const isSelectedRemoteClusterConnected = remoteCluster && remoteCluster.isConnected; - const isInvalid = areErrorsVisible && (!hasClusters || !isSelectedRemoteClusterConnected); - let field; + if (hasClusters && !isSelectedRemoteClusterConnected) { + error = this.renderCurrentRemoteClusterNotConnected(selected); + } else if (!hasClusters) { + error = this.renderNoClusterFound(); + } + } else { + /* Edit */ + const doesExists = !!remoteCluster; + if (!doesExists) { + error = this.renderRemoteClusterDoesNotExist(selected); + } else if (!isSelectedRemoteClusterConnected) { + error = this.renderCurrentRemoteClusterNotConnected(selected, true); + } + } - if(isEditable) { - if(hasClusters) { - field = this.renderDropdown(); - } else { - field = this.renderErrorMessage(); - } + return error ? ( + + + {error} + + ) : null; + } + + render() { + const { remoteClusters, selected, isEditable, areErrorsVisible } = this.props; + const remoteCluster = remoteClusters.find(c => c.name === selected); + const hasClusters = Boolean(remoteClusters.length); + const isSelectedRemoteClusterConnected = remoteCluster && remoteCluster.isConnected; + const isInvalid = areErrorsVisible && (!hasClusters || !isSelectedRemoteClusterConnected); + let field; + + if(isEditable) { + if(hasClusters) { + field = this.renderDropdown(); } else { - field = this.renderNotEditable(); + field = this.renderErrorMessage(); } - - return ( - - )} - isInvalid={isInvalid} - fullWidth - > - - {field} - - - ); + } else { + field = this.renderNotEditable(); } + + return ( + + )} + isInvalid={isInvalid} + fullWidth + > + + {field} + + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js index 23b7a5b77295e..4fa0afd2fe579 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js @@ -6,7 +6,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import chrome from 'ui/chrome'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; @@ -22,69 +22,67 @@ import { SectionLoading, } from '../../components'; -export const AutoFollowPatternAdd = injectI18n( - class extends PureComponent { - static propTypes = { - saveAutoFollowPattern: PropTypes.func.isRequired, - clearApiError: PropTypes.func.isRequired, - apiError: PropTypes.object, - apiStatus: PropTypes.string.isRequired, - } +export class AutoFollowPatternAdd extends PureComponent { + static propTypes = { + saveAutoFollowPattern: PropTypes.func.isRequired, + clearApiError: PropTypes.func.isRequired, + apiError: PropTypes.object, + apiStatus: PropTypes.string.isRequired, + } - componentDidMount() { - chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, addBreadcrumb ]); - } + componentDidMount() { + chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, addBreadcrumb ]); + } - componentWillUnmount() { - this.props.clearApiError(); - } + componentWillUnmount() { + this.props.clearApiError(); + } - render() { - const { saveAutoFollowPattern, apiStatus, apiError, match: { url: currentUrl } } = this.props; + render() { + const { saveAutoFollowPattern, apiStatus, apiError, match: { url: currentUrl } } = this.props; - return ( - - - )} - /> - - - {({ isLoading, error, remoteClusters }) => { - if (isLoading) { - return ( - - - - ); - } + return ( + + + )} + /> + + {({ isLoading, error, remoteClusters }) => { + if (isLoading) { return ( - - )} - /> + + + ); - }} - - - ); - } + } + + return ( + + )} + /> + ); + }} + + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js index fe365d0315efd..dd311612e858d 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import chrome from 'ui/chrome'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; @@ -29,156 +30,159 @@ import { } from '../../components'; import { API_STATUS } from '../../constants'; -export const AutoFollowPatternEdit = injectI18n( - class extends PureComponent { - static propTypes = { - getAutoFollowPattern: PropTypes.func.isRequired, - selectAutoFollowPattern: PropTypes.func.isRequired, - saveAutoFollowPattern: PropTypes.func.isRequired, - clearApiError: PropTypes.func.isRequired, - apiError: PropTypes.object.isRequired, - apiStatus: PropTypes.object.isRequired, - autoFollowPattern: PropTypes.object, - autoFollowPatternId: PropTypes.string, - } +export class AutoFollowPatternEdit extends PureComponent { + static propTypes = { + getAutoFollowPattern: PropTypes.func.isRequired, + selectAutoFollowPattern: PropTypes.func.isRequired, + saveAutoFollowPattern: PropTypes.func.isRequired, + clearApiError: PropTypes.func.isRequired, + apiError: PropTypes.object.isRequired, + apiStatus: PropTypes.object.isRequired, + autoFollowPattern: PropTypes.object, + autoFollowPatternId: PropTypes.string, + } - static getDerivedStateFromProps({ autoFollowPatternId }, { lastAutoFollowPatternId }) { - if (lastAutoFollowPatternId !== autoFollowPatternId) { - return { lastAutoFollowPatternId: autoFollowPatternId }; - } - return null; + static getDerivedStateFromProps({ autoFollowPatternId }, { lastAutoFollowPatternId }) { + if (lastAutoFollowPatternId !== autoFollowPatternId) { + return { lastAutoFollowPatternId: autoFollowPatternId }; } + return null; + } - state = { lastAutoFollowPatternId: undefined } + state = { lastAutoFollowPatternId: undefined } - componentDidMount() { - const { match: { params: { id } }, selectAutoFollowPattern } = this.props; - const decodedId = decodeURIComponent(id); + componentDidMount() { + const { match: { params: { id } }, selectAutoFollowPattern } = this.props; + const decodedId = decodeURIComponent(id); - selectAutoFollowPattern(decodedId); + selectAutoFollowPattern(decodedId); - chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, editBreadcrumb ]); - } + chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, editBreadcrumb ]); + } - componentDidUpdate(prevProps, prevState) { - const { autoFollowPattern, getAutoFollowPattern } = this.props; - // Fetch the auto-follow pattern on the server if we don't have it (i.e. page reload) - if (!autoFollowPattern && prevState.lastAutoFollowPatternId !== this.state.lastAutoFollowPatternId) { - getAutoFollowPattern(this.state.lastAutoFollowPatternId); - } + componentDidUpdate(prevProps, prevState) { + const { autoFollowPattern, getAutoFollowPattern } = this.props; + // Fetch the auto-follow pattern on the server if we don't have it (i.e. page reload) + if (!autoFollowPattern && prevState.lastAutoFollowPatternId !== this.state.lastAutoFollowPatternId) { + getAutoFollowPattern(this.state.lastAutoFollowPatternId); } + } - componentWillUnmount() { - this.props.clearApiError(); - } + componentWillUnmount() { + this.props.clearApiError(); + } - renderGetAutoFollowPatternError(error) { - const { intl, match: { params: { id: name } } } = this.props; - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorTitle', - defaultMessage: 'Error loading auto-follow pattern', - }); - const errorMessage = error.status === 404 ? { - data: { - error: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorMessage', + renderGetAutoFollowPatternError(error) { + const { match: { params: { id: name } } } = this.props; + const title = i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorTitle', + { + defaultMessage: 'Error loading auto-follow pattern' + } + ); + const errorMessage = error.status === 404 ? { + data: { + error: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorMessage', + { defaultMessage: `The auto-follow pattern '{name}' does not exist.`, - }, { name }) - } - } : error; - - return ( - - - - - - - - - - - - - - ); - } + values: { name } + } + ) + } + } : error; - renderLoadingAutoFollowPattern() { - return ( - - - - ); - } + return ( + + - render() { - const { saveAutoFollowPattern, apiStatus, apiError, autoFollowPattern, match: { url: currentUrl } } = this.props; + - return ( - - + + - )} - /> + + +
+ + ); + } - {apiStatus.get === API_STATUS.LOADING && this.renderLoadingAutoFollowPattern()} + renderLoadingAutoFollowPattern() { + return ( + + + + ); + } + render() { + const { saveAutoFollowPattern, apiStatus, apiError, autoFollowPattern, match: { url: currentUrl } } = this.props; + + return ( + + + )} + /> + + {apiStatus.get === API_STATUS.LOADING && this.renderLoadingAutoFollowPattern()} - {apiError.get && this.renderGetAutoFollowPatternError(apiError.get)} - {autoFollowPattern && ( - - {({ isLoading, error, remoteClusters }) => { - if (isLoading) { - return ( - - - - ); - } + {apiError.get && this.renderGetAutoFollowPatternError(apiError.get)} + {autoFollowPattern && ( + + {({ isLoading, error, remoteClusters }) => { + if (isLoading) { return ( - - )} - /> + + + ); - }} - - )} - - ); - } + } + + return ( + + )} + /> + ); + }} + + )} + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js index e335d1a1318e0..5aa6097556d8a 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js @@ -6,7 +6,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import chrome from 'ui/chrome'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; @@ -22,73 +22,71 @@ import { SectionLoading, } from '../../components'; -export const FollowerIndexAdd = injectI18n( - class extends PureComponent { - static propTypes = { - saveFollowerIndex: PropTypes.func.isRequired, - clearApiError: PropTypes.func.isRequired, - apiError: PropTypes.object, - apiStatus: PropTypes.string.isRequired, - } +export class FollowerIndexAdd extends PureComponent { + static propTypes = { + saveFollowerIndex: PropTypes.func.isRequired, + clearApiError: PropTypes.func.isRequired, + apiError: PropTypes.object, + apiStatus: PropTypes.string.isRequired, + } - componentDidMount() { - chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, addBreadcrumb ]); - } + componentDidMount() { + chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, addBreadcrumb ]); + } - componentWillUnmount() { - this.props.clearApiError(); - } + componentWillUnmount() { + this.props.clearApiError(); + } - render() { - const { saveFollowerIndex, clearApiError, apiStatus, apiError, match: { url: currentUrl } } = this.props; + render() { + const { saveFollowerIndex, clearApiError, apiStatus, apiError, match: { url: currentUrl } } = this.props; - return ( - - - )} - /> - - - {({ isLoading, error, remoteClusters }) => { - if (isLoading) { - return ( - - - - ); - } + return ( + + + )} + /> + + {({ isLoading, error, remoteClusters }) => { + if (isLoading) { return ( - - )} - /> + + + ); - }} - - - ); - } + } + + return ( + + )} + /> + ); + }} + + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js index 48d8e1894e9a4..8393590cbdc19 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import chrome from 'ui/chrome'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; @@ -31,245 +32,250 @@ import { } from '../../components'; import { API_STATUS } from '../../constants'; -export const FollowerIndexEdit = injectI18n( - class extends PureComponent { - static propTypes = { - getFollowerIndex: PropTypes.func.isRequired, - selectFollowerIndex: PropTypes.func.isRequired, - saveFollowerIndex: PropTypes.func.isRequired, - clearApiError: PropTypes.func.isRequired, - apiError: PropTypes.object.isRequired, - apiStatus: PropTypes.object.isRequired, - followerIndex: PropTypes.object, - followerIndexId: PropTypes.string, - } +export class FollowerIndexEdit extends PureComponent { + static propTypes = { + getFollowerIndex: PropTypes.func.isRequired, + selectFollowerIndex: PropTypes.func.isRequired, + saveFollowerIndex: PropTypes.func.isRequired, + clearApiError: PropTypes.func.isRequired, + apiError: PropTypes.object.isRequired, + apiStatus: PropTypes.object.isRequired, + followerIndex: PropTypes.object, + followerIndexId: PropTypes.string, + } - static getDerivedStateFromProps({ followerIndexId }, { lastFollowerIndexId }) { - if (lastFollowerIndexId !== followerIndexId) { - return { lastFollowerIndexId: followerIndexId }; - } - return null; + static getDerivedStateFromProps({ followerIndexId }, { lastFollowerIndexId }) { + if (lastFollowerIndexId !== followerIndexId) { + return { lastFollowerIndexId: followerIndexId }; } + return null; + } - state = { - lastFollowerIndexId: undefined, - showConfirmModal: false, - } + state = { + lastFollowerIndexId: undefined, + showConfirmModal: false, + } - componentDidMount() { - const { match: { params: { id } }, selectFollowerIndex } = this.props; - let decodedId; - try { - // When we navigate through the router (history.push) we need to decode both the uri and the id - decodedId = decodeURI(id); - decodedId = decodeURIComponent(decodedId); - } catch (e) { - // This is a page load. I guess that AngularJS router does already a decodeURI so it is not - // necessary in this case. - decodedId = decodeURIComponent(id); - } + componentDidMount() { + const { match: { params: { id } }, selectFollowerIndex } = this.props; + let decodedId; + try { + // When we navigate through the router (history.push) we need to decode both the uri and the id + decodedId = decodeURI(id); + decodedId = decodeURIComponent(decodedId); + } catch (e) { + // This is a page load. I guess that AngularJS router does already a decodeURI so it is not + // necessary in this case. + decodedId = decodeURIComponent(id); + } - selectFollowerIndex(decodedId); + selectFollowerIndex(decodedId); - chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, editBreadcrumb ]); - } + chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb, editBreadcrumb ]); + } - componentDidUpdate(prevProps, prevState) { - const { followerIndex, getFollowerIndex } = this.props; - // Fetch the follower index on the server if we don't have it (i.e. page reload) - if (!followerIndex && prevState.lastFollowerIndexId !== this.state.lastFollowerIndexId) { - getFollowerIndex(this.state.lastFollowerIndexId); - } + componentDidUpdate(prevProps, prevState) { + const { followerIndex, getFollowerIndex } = this.props; + // Fetch the follower index on the server if we don't have it (i.e. page reload) + if (!followerIndex && prevState.lastFollowerIndexId !== this.state.lastFollowerIndexId) { + getFollowerIndex(this.state.lastFollowerIndexId); } + } - componentWillUnmount() { - this.props.clearApiError(); - } + componentWillUnmount() { + this.props.clearApiError(); + } - saveFollowerIndex = (name, followerIndex) => { - this.editedFollowerIndexPayload = { name, followerIndex }; - this.showConfirmModal(); - } + saveFollowerIndex = (name, followerIndex) => { + this.editedFollowerIndexPayload = { name, followerIndex }; + this.showConfirmModal(); + } - confirmSaveFollowerIhdex = () => { - const { name, followerIndex } = this.editedFollowerIndexPayload; - this.props.saveFollowerIndex(name, followerIndex); - this.closeConfirmModal(); - } + confirmSaveFollowerIhdex = () => { + const { name, followerIndex } = this.editedFollowerIndexPayload; + this.props.saveFollowerIndex(name, followerIndex); + this.closeConfirmModal(); + } - showConfirmModal = () => this.setState({ showConfirmModal: true }); + showConfirmModal = () => this.setState({ showConfirmModal: true }); - closeConfirmModal = () => this.setState({ showConfirmModal: false }); + closeConfirmModal = () => this.setState({ showConfirmModal: false }); - renderLoadingFollowerIndex() { - return ( - - - - ); - } + renderLoadingFollowerIndex() { + return ( + + + + ); + } - renderGetFollowerIndexError(error) { - const { intl, match: { params: { id: name } } } = this.props; - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexEditForm.loadingErrorTitle', - defaultMessage: 'Error loading follower index', - }); - const errorMessage = error.status === 404 ? { - data: { - error: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexEditForm.loadingErrorMessage', + renderGetFollowerIndexError(error) { + const { match: { params: { id: name } } } = this.props; + const title = i18n.translate('xpack.crossClusterReplication.followerIndexEditForm.loadingErrorTitle', { + defaultMessage: 'Error loading follower index' + }); + const errorMessage = error.status === 404 ? { + data: { + error: i18n.translate( + 'xpack.crossClusterReplication.followerIndexEditForm.loadingErrorMessage', + { defaultMessage: `The follower index '{name}' does not exist.`, - }, { name }) - } - } : error; + values: { name } + } + ) + } + } : error; - return ( - - + return ( + + - + - - - - - - - - - ); - } + + + + + + + + + ); + } - renderConfirmModal = () => { - const { followerIndexId, intl, followerIndex: { isPaused } } = this.props; - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexEditForm.confirmModal.title', - defaultMessage: 'Update follower index \'{id}\'?', - }, { id: followerIndexId }); + renderConfirmModal = () => { + const { followerIndexId, followerIndex: { isPaused } } = this.props; + const title = i18n.translate( + 'xpack.crossClusterReplication.followerIndexEditForm.confirmModal.title', + { + defaultMessage: `Update follower index '{id}'?`, + values: { id: followerIndexId } + } + ); - return ( - - + + ) : ( + + )} + > +

+ {isPaused ? ( ) : ( )} - > -

- {isPaused ? ( - - ) : ( - - )} -

-
-
- ); - } - - render() { - const { - clearApiError, - apiStatus, - apiError, - followerIndex, - match: { url: currentUrl } - } = this.props; +

+ +
+ ); + } - const { showConfirmModal } = this.state; + render() { + const { + clearApiError, + apiStatus, + apiError, + followerIndex, + match: { url: currentUrl } + } = this.props; - /* remove non-editable properties */ - const { shards, ...rest } = followerIndex || {}; // eslint-disable-line no-unused-vars + const { showConfirmModal } = this.state; - return ( - - - )} - /> + /* remove non-editable properties */ + const { shards, ...rest } = followerIndex || {}; // eslint-disable-line no-unused-vars - {apiStatus.get === API_STATUS.LOADING && this.renderLoadingFollowerIndex()} + return ( + + + )} + /> - {apiError.get && this.renderGetFollowerIndexError(apiError.get)} - { followerIndex && ( - - {({ isLoading, error, remoteClusters }) => { - if (isLoading) { - return ( - - - - ); - } + {apiStatus.get === API_STATUS.LOADING && this.renderLoadingFollowerIndex()} + {apiError.get && this.renderGetFollowerIndexError(apiError.get)} + { followerIndex && ( + + {({ isLoading, error, remoteClusters }) => { + if (isLoading) { return ( - - )} - /> + + + ); - }} - - ) } + } - { showConfirmModal && this.renderConfirmModal() } - - ); - } + return ( + + )} + /> + ); + }} + + ) } + + { showConfirmModal && this.renderConfirmModal() } + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js index d9243be3c774a..c25ce7e171a7b 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiEmptyPrompt, @@ -29,228 +30,226 @@ const getQueryParamPattern = ({ location: { search } }) => { return pattern ? decodeURIComponent(pattern) : null; }; -export const AutoFollowPatternList = injectI18n( - class extends PureComponent { - static propTypes = { - loadAutoFollowPatterns: PropTypes.func, - selectAutoFollowPattern: PropTypes.func, - loadAutoFollowStats: PropTypes.func, - autoFollowPatterns: PropTypes.array, - apiStatus: PropTypes.string, - apiError: PropTypes.object, - } +export class AutoFollowPatternList extends PureComponent { + static propTypes = { + loadAutoFollowPatterns: PropTypes.func, + selectAutoFollowPattern: PropTypes.func, + loadAutoFollowStats: PropTypes.func, + autoFollowPatterns: PropTypes.array, + apiStatus: PropTypes.string, + apiError: PropTypes.object, + } - static getDerivedStateFromProps({ autoFollowPatternId }, { lastAutoFollowPatternId }) { - if (autoFollowPatternId !== lastAutoFollowPatternId) { - return { - lastAutoFollowPatternId: autoFollowPatternId, - isDetailPanelOpen: !!autoFollowPatternId, - }; - } - return null; + static getDerivedStateFromProps({ autoFollowPatternId }, { lastAutoFollowPatternId }) { + if (autoFollowPatternId !== lastAutoFollowPatternId) { + return { + lastAutoFollowPatternId: autoFollowPatternId, + isDetailPanelOpen: !!autoFollowPatternId, + }; } + return null; + } - state = { - lastAutoFollowPatternId: null, - isDetailPanelOpen: false, - }; - - componentDidMount() { - const { loadAutoFollowPatterns, loadAutoFollowStats, selectAutoFollowPattern, history } = this.props; + state = { + lastAutoFollowPatternId: null, + isDetailPanelOpen: false, + }; - loadAutoFollowPatterns(); - loadAutoFollowStats(); + componentDidMount() { + const { loadAutoFollowPatterns, loadAutoFollowStats, selectAutoFollowPattern, history } = this.props; - // Select the pattern in the URL query params - selectAutoFollowPattern(getQueryParamPattern(history)); + loadAutoFollowPatterns(); + loadAutoFollowStats(); - // Interval to load auto-follow patterns in the background passing "true" to the fetch method - this.interval = setInterval(() => loadAutoFollowPatterns(true), REFRESH_RATE_MS); - } + // Select the pattern in the URL query params + selectAutoFollowPattern(getQueryParamPattern(history)); - componentDidUpdate(prevProps, prevState) { - const { history, loadAutoFollowStats } = this.props; - const { lastAutoFollowPatternId } = this.state; + // Interval to load auto-follow patterns in the background passing "true" to the fetch method + this.interval = setInterval(() => loadAutoFollowPatterns(true), REFRESH_RATE_MS); + } - /** - * Each time our state is updated (through getDerivedStateFromProps()) - * we persist the auto-follow pattern id to query params for deep linking - */ - if (lastAutoFollowPatternId !== prevState.lastAutoFollowPatternId) { - if(!lastAutoFollowPatternId) { - history.replace({ - search: '', - }); - } else { - history.replace({ - search: `?pattern=${encodeURIComponent(lastAutoFollowPatternId)}`, - }); + componentDidUpdate(prevProps, prevState) { + const { history, loadAutoFollowStats } = this.props; + const { lastAutoFollowPatternId } = this.state; + + /** + * Each time our state is updated (through getDerivedStateFromProps()) + * we persist the auto-follow pattern id to query params for deep linking + */ + if (lastAutoFollowPatternId !== prevState.lastAutoFollowPatternId) { + if(!lastAutoFollowPatternId) { + history.replace({ + search: '', + }); + } else { + history.replace({ + search: `?pattern=${encodeURIComponent(lastAutoFollowPatternId)}`, + }); - loadAutoFollowStats(); - } + loadAutoFollowStats(); } } + } - componentWillUnmount() { - clearInterval(this.interval); - } + componentWillUnmount() { + clearInterval(this.interval); + } + + renderHeader() { + const { isAuthorized } = this.props; + return ( + + + + +

+ +

+
+
+ + + {isAuthorized && ( + + + + )} + +
- renderHeader() { - const { isAuthorized } = this.props; + +
+ ); + } + + renderContent(isEmpty) { + const { apiError, isAuthorized } = this.props; + + if (!isAuthorized) { return ( - - - - -

- -

-
-
+ + )} + > + + + ); + } - - {isAuthorized && ( - - - - )} - -
+ if (apiError) { + const title = i18n.translate('xpack.crossClusterReplication.autoFollowPatternList.loadingErrorTitle', { + defaultMessage: 'Error loading auto-follow patterns' + }); + return ( + + ); } - renderContent(isEmpty) { - const { apiError, isAuthorized, intl } = this.props; - if (!isAuthorized) { - return ( - + + + )} + body={ + +

- )} +

+
+ } + actions={ + -
- ); - } - - if (apiError) { - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.loadingErrorTitle', - defaultMessage: 'Error loading auto-follow patterns', - }); - - return ( - - - - - ); - } + + } + /> + ); + } - if (isEmpty) { - return this.renderEmpty(); - } + renderList() { + const { + selectAutoFollowPattern, + autoFollowPatterns, + apiStatus, + } = this.props; - return this.renderList(); - } + const { isDetailPanelOpen } = this.state; - renderEmpty() { + if (apiStatus === API_STATUS.LOADING) { return ( - - - - )} - body={ - -

- -

-
- } - actions={ - - - - } - /> + + + ); } - renderList() { - const { - selectAutoFollowPattern, - autoFollowPatterns, - apiStatus, - } = this.props; - - const { isDetailPanelOpen } = this.state; - - if (apiStatus === API_STATUS.LOADING) { - return ( - - - - ); - } - - return ( - - - {isDetailPanelOpen && selectAutoFollowPattern(null)} />} - - ); - } + return ( + + + {isDetailPanelOpen && selectAutoFollowPattern(null)} />} + + ); + } - render() { - const { autoFollowPatterns, apiStatus, } = this.props; - const isEmpty = apiStatus === API_STATUS.IDLE && !autoFollowPatterns.length; + render() { + const { autoFollowPatterns, apiStatus, } = this.props; + const isEmpty = apiStatus === API_STATUS.IDLE && !autoFollowPatterns.length; - return ( - - {!isEmpty && this.renderHeader()} - {this.renderContent(isEmpty)} - - ); - } + return ( + + {!isEmpty && this.renderHeader()} + {this.renderContent(isEmpty)} + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js index 58ea095782836..d0f7f365bc4e8 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js @@ -7,7 +7,7 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import { i18n } from '@kbn/i18n'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiButtonIcon, @@ -21,227 +21,237 @@ import { API_STATUS } from '../../../../../constants'; import { AutoFollowPatternDeleteProvider } from '../../../../../components'; import routing from '../../../../../services/routing'; -export const AutoFollowPatternTable = injectI18n( - class extends PureComponent { - static propTypes = { - autoFollowPatterns: PropTypes.array, - selectAutoFollowPattern: PropTypes.func.isRequired, - } +export class AutoFollowPatternTable extends PureComponent { + static propTypes = { + autoFollowPatterns: PropTypes.array, + selectAutoFollowPattern: PropTypes.func.isRequired, + } - state = { - selectedItems: [], - } + state = { + selectedItems: [], + } - onSearch = ({ query }) => { - const { text } = query; - const normalizedSearchText = text.toLowerCase(); - this.setState({ - queryText: normalizedSearchText, - }); - }; + onSearch = ({ query }) => { + const { text } = query; + const normalizedSearchText = text.toLowerCase(); + this.setState({ + queryText: normalizedSearchText, + }); + }; - getFilteredPatterns = () => { - const { autoFollowPatterns } = this.props; - const { queryText } = this.state; + getFilteredPatterns = () => { + const { autoFollowPatterns } = this.props; + const { queryText } = this.state; - if(queryText) { - return autoFollowPatterns.filter(autoFollowPattern => { - const { name, remoteCluster, followIndexPatternPrefix, followIndexPatternSuffix } = autoFollowPattern; + if(queryText) { + return autoFollowPatterns.filter(autoFollowPattern => { + const { name, remoteCluster, followIndexPatternPrefix, followIndexPatternSuffix } = autoFollowPattern; - const inName = name.toLowerCase().includes(queryText); - const inRemoteCluster = remoteCluster.toLowerCase().includes(queryText); - const inPrefix = followIndexPatternPrefix.toLowerCase().includes(queryText); - const inSuffix = followIndexPatternSuffix.toLowerCase().includes(queryText); + const inName = name.toLowerCase().includes(queryText); + const inRemoteCluster = remoteCluster.toLowerCase().includes(queryText); + const inPrefix = followIndexPatternPrefix.toLowerCase().includes(queryText); + const inSuffix = followIndexPatternSuffix.toLowerCase().includes(queryText); - return inName || inRemoteCluster || inPrefix || inSuffix; - }); - } + return inName || inRemoteCluster || inPrefix || inSuffix; + }); + } - return autoFollowPatterns.slice(0); - }; + return autoFollowPatterns.slice(0); + }; - getTableColumns() { - const { intl, selectAutoFollowPattern } = this.props; + getTableColumns() { + const { selectAutoFollowPattern } = this.props; - return [{ - field: 'name', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.nameColumnTitle', - defaultMessage: 'Name', - }), - sortable: true, - truncateText: false, - render: (name) => { - return ( - selectAutoFollowPattern(name)}> - {name} - - ); + return [{ + field: 'name', + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.nameColumnTitle', + { + defaultMessage: 'Name' } - }, { - field: 'remoteCluster', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.clusterColumnTitle', - defaultMessage: 'Remote cluster', - }), - truncateText: true, - sortable: true, - }, { - field: 'leaderIndexPatterns', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.leaderPatternsColumnTitle', - defaultMessage: 'Leader patterns', - }), - render: (leaderPatterns) => leaderPatterns.join(', '), - }, { - field: 'followIndexPatternPrefix', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.prefixColumnTitle', - defaultMessage: 'Follower index prefix', - }), - sortable: true, - }, { - field: 'followIndexPatternSuffix', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.suffixColumnTitle', - defaultMessage: 'Follower index suffix', - }), - sortable: true, - }, { - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.autoFollowPatternList.table.actionsColumnTitle', - defaultMessage: 'Actions', - }), - actions: [ - { - render: ({ name }) => { - const label = i18n.translate( - 'xpack.crossClusterReplication.autoFollowPatternList.table.actionDeleteDescription', - { - defaultMessage: 'Delete auto-follow pattern', - } - ); - - return ( - - - {(deleteAutoFollowPattern) => ( - deleteAutoFollowPattern(name)} - /> - )} - - - ); - }, - }, - { - render: ({ name }) => { - const label = i18n.translate('xpack.crossClusterReplication.autoFollowPatternList.table.actionEditDescription', { - defaultMessage: 'Edit auto-follow pattern', - }); - - return ( - - - - ); - }, - }, - ], - width: '100px', - }]; - } - - renderLoading = () => { - const { apiStatusDelete } = this.props; - - if (apiStatusDelete === API_STATUS.DELETING) { + ), + sortable: true, + truncateText: false, + render: (name) => { return ( - - - + selectAutoFollowPattern(name)}> + {name} + ); } - return null; - }; + }, { + field: 'remoteCluster', + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.clusterColumnTitle', + { + defaultMessage: 'Remote cluster' + } + ), + truncateText: true, + sortable: true, + }, { + field: 'leaderIndexPatterns', + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.leaderPatternsColumnTitle', + { + defaultMessage: 'Leader patterns' + } + ), + render: (leaderPatterns) => leaderPatterns.join(', '), + }, { + field: 'followIndexPatternPrefix', + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.prefixColumnTitle', + { + defaultMessage: 'Follower index prefix' + } + ), + sortable: true, + }, { + field: 'followIndexPatternSuffix', + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.suffixColumnTitle', + { + defaultMessage: 'Follower index suffix' + } + ), + sortable: true, + }, { + name: i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.actionsColumnTitle', + { + defaultMessage: 'Actions' + } + ), + actions: [ + { + render: ({ name }) => { + const label = i18n.translate( + 'xpack.crossClusterReplication.autoFollowPatternList.table.actionDeleteDescription', + { + defaultMessage: 'Delete auto-follow pattern', + } + ); - render() { - const { - selectedItems, - } = this.state; + return ( + + + {(deleteAutoFollowPattern) => ( + deleteAutoFollowPattern(name)} + /> + )} + + + ); + }, + }, + { + render: ({ name }) => { + const label = i18n.translate('xpack.crossClusterReplication.autoFollowPatternList.table.actionEditDescription', { + defaultMessage: 'Edit auto-follow pattern', + }); - const sorting = { - sort: { - field: 'name', - direction: 'asc', - } - }; - - const pagination = { - initialPageSize: 20, - pageSizeOptions: [10, 20, 50] - }; - - const selection = { - onSelectionChange: (selectedItems) => this.setState({ selectedItems }) - }; - - const search = { - toolsLeft: selectedItems.length ? ( - - {(deleteAutoFollowPattern) => ( - deleteAutoFollowPattern(selectedItems.map(({ name }) => name))} + return ( + - - - )} - - ) : undefined, - onChange: this.onSearch, - box: { - incremental: true, + + ); + }, }, - }; + ], + width: '100px', + }]; + } + + renderLoading = () => { + const { apiStatusDelete } = this.props; + if (apiStatusDelete === API_STATUS.DELETING) { return ( - - - {this.renderLoading()} - + + + ); } + return null; + }; + + render() { + const { + selectedItems, + } = this.state; + + const sorting = { + sort: { + field: 'name', + direction: 'asc', + } + }; + + const pagination = { + initialPageSize: 20, + pageSizeOptions: [10, 20, 50] + }; + + const selection = { + onSelectionChange: (selectedItems) => this.setState({ selectedItems }) + }; + + const search = { + toolsLeft: selectedItems.length ? ( + + {(deleteAutoFollowPattern) => ( + deleteAutoFollowPattern(selectedItems.map(({ name }) => name))} + > + + + )} + + ) : undefined, + onChange: this.onSearch, + box: { + incremental: true, + }, + }; + + return ( + + + {this.renderLoading()} + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js index 99e2d4083e96e..2e0e98a4c3c98 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { getIndexListUri } from '../../../../../../../../index_management/public/services/navigation'; @@ -39,7 +39,7 @@ import { import { API_STATUS } from '../../../../../constants'; import routing from '../../../../../services/routing'; -export class DetailPanelUi extends Component { +export class DetailPanel extends Component { static propTypes = { apiStatus: PropTypes.string, autoFollowPatternId: PropTypes.string, @@ -250,7 +250,7 @@ export class DetailPanelUi extends Component { @@ -375,5 +375,3 @@ export class DetailPanelUi extends Component { ); } } - -export const DetailPanel = injectI18n(DetailPanelUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.js index 2f3ffb4cedb74..c33da213809b0 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/context_menu/context_menu.js @@ -5,7 +5,7 @@ */ import React, { PureComponent, Fragment } from 'react'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import PropTypes from 'prop-types'; import { EuiButton, @@ -22,8 +22,7 @@ import { FollowerIndexUnfollowProvider } from '../../../../../components'; -export class ContextMenuUi extends PureComponent { - +export class ContextMenu extends PureComponent { static propTypes = { iconSide: PropTypes.string, iconType: PropTypes.string, @@ -174,5 +173,3 @@ export class ContextMenuUi extends PureComponent { ); } } - -export const ContextMenu = injectI18n(ContextMenuUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js index 4fc0f0f6c3873..db438b093ea27 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { getIndexListUri } from '../../../../../../../../index_management/public/services/navigation'; import { @@ -38,7 +38,7 @@ import { ContextMenu } from '../context_menu'; import { API_STATUS } from '../../../../../constants'; -export class DetailPanelUi extends Component { +export class DetailPanel extends Component { static propTypes = { apiStatus: PropTypes.string, followerIndexId: PropTypes.string, @@ -391,7 +391,7 @@ export class DetailPanelUi extends Component { @@ -518,5 +518,3 @@ export class DetailPanelUi extends Component { ); } } - -export const DetailPanel = injectI18n(DetailPanelUi); diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.js index 8fe4ecc4f3477..0dfa198e2d505 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiHealth, EuiIcon, @@ -24,269 +25,281 @@ import { import routing from '../../../../../services/routing'; import { ContextMenu } from '../context_menu'; -export const FollowerIndicesTable = injectI18n( - class extends PureComponent { - static propTypes = { - followerIndices: PropTypes.array, - selectFollowerIndex: PropTypes.func.isRequired, - } - - state = { - selectedItems: [], - } +export class FollowerIndicesTable extends PureComponent { + static propTypes = { + followerIndices: PropTypes.array, + selectFollowerIndex: PropTypes.func.isRequired, + } - onSearch = ({ query }) => { - const { text } = query; - const normalizedSearchText = text.toLowerCase(); - this.setState({ - queryText: normalizedSearchText, - }); - }; + state = { + selectedItems: [], + } - editFollowerIndex = (id) => { - const uri = routing.getFollowerIndexPath(id, '/edit', false); - routing.navigate(uri); - } + onSearch = ({ query }) => { + const { text } = query; + const normalizedSearchText = text.toLowerCase(); + this.setState({ + queryText: normalizedSearchText, + }); + }; - getFilteredIndices = () => { - const { followerIndices } = this.props; - const { queryText } = this.state; + editFollowerIndex = (id) => { + const uri = routing.getFollowerIndexPath(id, '/edit', false); + routing.navigate(uri); + } - if(queryText) { - return followerIndices.filter(followerIndex => { - const { name, shards } = followerIndex; + getFilteredIndices = () => { + const { followerIndices } = this.props; + const { queryText } = this.state; - const inName = name.toLowerCase().includes(queryText); - const inRemoteCluster = shards[0].remoteCluster.toLowerCase().includes(queryText); - const inLeaderIndex = shards[0].leaderIndex.toLowerCase().includes(queryText); + if(queryText) { + return followerIndices.filter(followerIndex => { + const { name, shards } = followerIndex; - return inName || inRemoteCluster || inLeaderIndex; - }); - } + const inName = name.toLowerCase().includes(queryText); + const inRemoteCluster = shards[0].remoteCluster.toLowerCase().includes(queryText); + const inLeaderIndex = shards[0].leaderIndex.toLowerCase().includes(queryText); - return followerIndices.slice(0); - }; + return inName || inRemoteCluster || inLeaderIndex; + }); + } - getTableColumns() { - const { intl, selectFollowerIndex } = this.props; + return followerIndices.slice(0); + }; - const actions = [ - /* Pause or resume follower index */ - { - render: (followerIndex) => { - const { name, isPaused } = followerIndex; - const label = isPaused - ? intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.actionResumeDescription', - defaultMessage: 'Resume replication', - }) - : intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.actionPauseDescription', - defaultMessage: 'Pause replication', - }); + getTableColumns() { + const { selectFollowerIndex } = this.props; - return isPaused ? ( - - {(resumeFollowerIndex) => ( - resumeFollowerIndex(name)}> - - {label} - - )} - - ) : ( - - {(pauseFollowerIndex) => ( - pauseFollowerIndex(followerIndex)}> - - {label} - - )} - + const actions = [ + /* Pause or resume follower index */ + { + render: (followerIndex) => { + const { name, isPaused } = followerIndex; + const label = isPaused + ? i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.actionResumeDescription', + { + defaultMessage: 'Resume replication' + } + ) : i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.actionPauseDescription', + { + defaultMessage: 'Pause replication' + } ); - }, - }, - /* Edit follower index */ - { - render: ({ name }) => { - const label = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.actionEditDescription', - defaultMessage: 'Edit follower index', - }); - return ( - this.editFollowerIndex(name)}> - - {label} - - ); - }, + return isPaused ? ( + + {(resumeFollowerIndex) => ( + resumeFollowerIndex(name)}> + + {label} + + )} + + ) : ( + + {(pauseFollowerIndex) => ( + pauseFollowerIndex(followerIndex)}> + + {label} + + )} + + ); }, - /* Unfollow leader index */ - { - render: ({ name }) => { - const label = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.actionUnfollowDescription', - defaultMessage: 'Unfollow leader index', - }); + }, + /* Edit follower index */ + { + render: ({ name }) => { + const label = i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.actionEditDescription', + { + defaultMessage: 'Edit follower index' + } + ); - return ( - - {(unfollowLeaderIndex) => ( - unfollowLeaderIndex(name)}> - - {label} - - )} - - ); - }, + return ( + this.editFollowerIndex(name)}> + + {label} + + ); }, - ]; + }, + /* Unfollow leader index */ + { + render: ({ name }) => { + const label = i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.actionUnfollowDescription', + { + defaultMessage: 'Unfollow leader index' + } + ); - return [{ - field: 'name', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.nameColumnTitle', - defaultMessage: 'Name', - }), - sortable: true, - truncateText: false, - render: (name) => { return ( - selectFollowerIndex(name)}> - {name} - + + {(unfollowLeaderIndex) => ( + unfollowLeaderIndex(name)}> + + {label} + + )} + ); + }, + }, + ]; + + return [{ + field: 'name', + name: i18n.translate('xpack.crossClusterReplication.followerIndexList.table.nameColumnTitle', { + defaultMessage: 'Name' + }), + sortable: true, + truncateText: false, + render: (name) => { + return ( + selectFollowerIndex(name)}> + {name} + + ); + } + }, { + field: 'isPaused', + name: i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.statusColumnTitle', + { + defaultMessage: 'Status' } - }, { - field: 'isPaused', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.statusColumnTitle', - defaultMessage: 'Status', - }), - truncateText: true, - sortable: true, - render: (isPaused) => { - return isPaused ? ( - - - - ) : ( - - - - ); + ), + truncateText: true, + sortable: true, + render: (isPaused) => { + return isPaused ? ( + + + + ) : ( + + + + ); + } + }, { + field: 'remoteCluster', + name: i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.clusterColumnTitle', + { + defaultMessage: 'Remote cluster' + } + ), + truncateText: true, + sortable: true, + }, { + field: 'leaderIndex', + name: i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.leaderIndexColumnTitle', + { + defaultMessage: 'Leader index' } - }, { - field: 'remoteCluster', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.clusterColumnTitle', - defaultMessage: 'Remote cluster', - }), - truncateText: true, - sortable: true, - }, { - field: 'leaderIndex', - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.leaderIndexColumnTitle', - defaultMessage: 'Leader index', - }), - truncateText: true, - sortable: true, - }, { - name: intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.table.actionsColumnTitle', - defaultMessage: 'Actions', - }), - actions, - width: '100px', - }]; + ), + truncateText: true, + sortable: true, + }, { + name: i18n.translate( + 'xpack.crossClusterReplication.followerIndexList.table.actionsColumnTitle', + { + defaultMessage: 'Actions' + } + ), + actions, + width: '100px', + }]; + } + + renderLoading = () => { + const { apiStatusDelete } = this.props; + + if (apiStatusDelete === API_STATUS.DELETING) { + return ( + + + + ); } + return null; + }; - renderLoading = () => { - const { apiStatusDelete } = this.props; + render() { + const { + selectedItems, + } = this.state; - if (apiStatusDelete === API_STATUS.DELETING) { - return ( - - - - ); + const sorting = { + sort: { + field: 'name', + direction: 'asc', } - return null; }; - render() { - const { - selectedItems, - } = this.state; - - const sorting = { - sort: { - field: 'name', - direction: 'asc', - } - }; - - const pagination = { - initialPageSize: 20, - pageSizeOptions: [10, 20, 50] - }; + const pagination = { + initialPageSize: 20, + pageSizeOptions: [10, 20, 50] + }; - const selection = { - onSelectionChange: (selectedItems) => this.setState({ selectedItems }) - }; + const selection = { + onSelectionChange: (selectedItems) => this.setState({ selectedItems }) + }; - const search = { - toolsLeft: selectedItems.length ? ( - - ) : undefined, - onChange: this.onSearch, - box: { - incremental: true, - }, - }; + const search = { + toolsLeft: selectedItems.length ? ( + + ) : undefined, + onChange: this.onSearch, + box: { + incremental: true, + }, + }; - return ( - - - {this.renderLoading()} - - ); - } + return ( + + + {this.renderLoading()} + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.js index 693bb304ea306..0f43cbbe7d7d3 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/follower_indices_list.js @@ -6,7 +6,8 @@ import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiEmptyPrompt, @@ -29,223 +30,220 @@ const getQueryParamName = ({ location: { search } }) => { return name ? decodeURIComponent(name) : null; }; -export const FollowerIndicesList = injectI18n( - class extends PureComponent { - static propTypes = { - loadFollowerIndices: PropTypes.func, - selectFollowerIndex: PropTypes.func, - followerIndices: PropTypes.array, - apiStatus: PropTypes.string, - apiError: PropTypes.object, - } +export class FollowerIndicesList extends PureComponent { + static propTypes = { + loadFollowerIndices: PropTypes.func, + selectFollowerIndex: PropTypes.func, + followerIndices: PropTypes.array, + apiStatus: PropTypes.string, + apiError: PropTypes.object, + } - static getDerivedStateFromProps({ followerIndexId }, { lastFollowerIndexId }) { - if (followerIndexId !== lastFollowerIndexId) { - return { - lastFollowerIndexId: followerIndexId, - isDetailPanelOpen: !!followerIndexId, - }; - } - return null; + static getDerivedStateFromProps({ followerIndexId }, { lastFollowerIndexId }) { + if (followerIndexId !== lastFollowerIndexId) { + return { + lastFollowerIndexId: followerIndexId, + isDetailPanelOpen: !!followerIndexId, + }; } + return null; + } - state = { - lastFollowerIndexId: null, - isDetailPanelOpen: false, - }; + state = { + lastFollowerIndexId: null, + isDetailPanelOpen: false, + }; - componentDidMount() { - const { loadFollowerIndices, selectFollowerIndex, history } = this.props; + componentDidMount() { + const { loadFollowerIndices, selectFollowerIndex, history } = this.props; - loadFollowerIndices(); + loadFollowerIndices(); - // Select the pattern in the URL query params - selectFollowerIndex(getQueryParamName(history)); + // Select the pattern in the URL query params + selectFollowerIndex(getQueryParamName(history)); - // Interval to load follower indices in the background passing "true" to the fetch method - this.interval = setInterval(() => loadFollowerIndices(true), REFRESH_RATE_MS); - } + // Interval to load follower indices in the background passing "true" to the fetch method + this.interval = setInterval(() => loadFollowerIndices(true), REFRESH_RATE_MS); + } - componentDidUpdate(prevProps, prevState) { - const { history } = this.props; - const { lastFollowerIndexId } = this.state; - - /** - * Each time our state is updated (through getDerivedStateFromProps()) - * we persist the follower index id to query params for deep linking - */ - if (lastFollowerIndexId !== prevState.lastFollowerIndexId) { - if(!lastFollowerIndexId) { - history.replace({ - search: '', - }); - } else { - history.replace({ - search: `?name=${encodeURIComponent(lastFollowerIndexId)}`, - }); - } + componentDidUpdate(prevProps, prevState) { + const { history } = this.props; + const { lastFollowerIndexId } = this.state; + + /** + * Each time our state is updated (through getDerivedStateFromProps()) + * we persist the follower index id to query params for deep linking + */ + if (lastFollowerIndexId !== prevState.lastFollowerIndexId) { + if(!lastFollowerIndexId) { + history.replace({ + search: '', + }); + } else { + history.replace({ + search: `?name=${encodeURIComponent(lastFollowerIndexId)}`, + }); } } + } - componentWillUnmount() { - clearInterval(this.interval); + componentWillUnmount() { + clearInterval(this.interval); + } + + renderHeader() { + const { isAuthorized } = this.props; + + return ( + + + + +

+ +

+
+
+ + + {isAuthorized && ( + + + + )} + +
+ + +
+ ); + } + + renderContent(isEmpty) { + const { apiError, isAuthorized } = this.props; + + if (!isAuthorized) { + return ( + + )} + > + + + ); } - renderHeader() { - const { isAuthorized } = this.props; + if (apiError) { + const title = i18n.translate('xpack.crossClusterReplication.followerIndexList.loadingErrorTitle', { + defaultMessage: 'Error loading follower indices' + }); return ( - - - -

- -

-
-
- - - {isAuthorized && ( - - - - )} - -
- +
); } - renderContent(isEmpty) { - const { apiError, isAuthorized, intl } = this.props; + if (isEmpty) { + return this.renderEmpty(); + } - if (!isAuthorized) { - return ( - + + + )} + body={ + +

- )} +

+
+ } + actions={ + -
- ); - } - - if (apiError) { - const title = intl.formatMessage({ - id: 'xpack.crossClusterReplication.followerIndexList.loadingErrorTitle', - defaultMessage: 'Error loading follower indices', - }); - - return ( - - - - - ); - } + + } + /> + ); + } - if (isEmpty) { - return this.renderEmpty(); - } + renderList() { + const { + selectFollowerIndex, + followerIndices, + apiStatus, + } = this.props; - return this.renderList(); - } + const { isDetailPanelOpen } = this.state; - renderEmpty() { + if (apiStatus === API_STATUS.LOADING) { return ( - - - - )} - body={ - -

- -

-
- } - actions={ - - - - } - /> + + + ); } - renderList() { - const { - selectFollowerIndex, - followerIndices, - apiStatus, - } = this.props; - - const { isDetailPanelOpen } = this.state; - - if (apiStatus === API_STATUS.LOADING) { - return ( - - - - ); - } - - return ( - - - {isDetailPanelOpen && selectFollowerIndex(null)} />} - - ); - } + return ( + + + {isDetailPanelOpen && selectFollowerIndex(null)} />} + + ); + } - render() { - const { followerIndices, apiStatus } = this.props; - const isEmpty = apiStatus === API_STATUS.IDLE && !followerIndices.length; - return ( - - {!isEmpty && this.renderHeader()} - {this.renderContent(isEmpty)} - - ); - } + render() { + const { followerIndices, apiStatus } = this.props; + const isEmpty = apiStatus === API_STATUS.IDLE && !followerIndices.length; + return ( + + {!isEmpty && this.renderHeader()} + {this.renderContent(isEmpty)} + + ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/home.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/home.js index e987c69ee1afd..1be8c61c54831 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/sections/home/home.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/home.js @@ -6,7 +6,7 @@ import React, { PureComponent } from 'react'; import { Route, Switch } from 'react-router-dom'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import chrome from 'ui/chrome'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; @@ -25,81 +25,79 @@ import routing from '../../services/routing'; import { AutoFollowPatternList } from './auto_follow_pattern_list'; import { FollowerIndicesList } from './follower_indices_list'; -export const CrossClusterReplicationHome = injectI18n( - class extends PureComponent { - state = { - activeSection: 'follower_indices' - } +export class CrossClusterReplicationHome extends PureComponent { + state = { + activeSection: 'follower_indices' + } - tabs = [{ - id: 'follower_indices', - name: ( - - ) - }, { - id: 'auto_follow_patterns', - name: ( - - ) - }] + tabs = [{ + id: 'follower_indices', + name: ( + + ) + }, { + id: 'auto_follow_patterns', + name: ( + + ) + }] - componentDidMount() { - chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb ]); - } + componentDidMount() { + chrome.breadcrumbs.set([ MANAGEMENT_BREADCRUMB, listBreadcrumb ]); + } - static getDerivedStateFromProps(props) { - const { match: { params: { section } } } = props; - return { - activeSection: section - }; - } + static getDerivedStateFromProps(props) { + const { match: { params: { section } } } = props; + return { + activeSection: section + }; + } - onSectionChange = (section) => { - routing.navigate(`/${section}`); - } + onSectionChange = (section) => { + routing.navigate(`/${section}`); + } - render() { - return ( - - - -

- -

-
+ render() { + return ( + + + +

+ +

+
- + - - {this.tabs.map(tab => ( - this.onSectionChange(tab.id)} - isSelected={tab.id === this.state.activeSection} - key={tab.id} - > - {tab.name} - - ))} - + + {this.tabs.map(tab => ( + this.onSectionChange(tab.id)} + isSelected={tab.id === this.state.activeSection} + key={tab.id} + > + {tab.name} + + ))} + - + - - - - -
-
- ); - } + + + + +
+
+ ); } -); +} diff --git a/x-pack/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js b/x-pack/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js index b19d571236827..94a0d34fd4e4b 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/services/auto_follow_pattern_validators.js @@ -38,14 +38,14 @@ export const validateName = (name = '') => { if (name[0] === '_') { errorMsg = i18n.translate( 'xpack.crossClusterReplication.autoFollowPattern.nameValidation.errorUnderscore', - { defaultMessage: "Name can't begin with an underscore." } + { defaultMessage: `Name can't begin with an underscore.` } ); } if (name.includes(',')) { errorMsg = i18n.translate( 'xpack.crossClusterReplication.autoFollowPattern.nameValidation.errorComma', - { defaultMessage: "Commas are not allowed in the name." } + { defaultMessage: 'Commas are not allowed in the name.' } ); } } diff --git a/x-pack/plugins/cross_cluster_replication/public/app/services/input_validation.js b/x-pack/plugins/cross_cluster_replication/public/app/services/input_validation.js index 877fc1d5a6105..31e55bdd8a591 100644 --- a/x-pack/plugins/cross_cluster_replication/public/app/services/input_validation.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/services/input_validation.js @@ -30,7 +30,7 @@ export const indexNameValidator = (value) => { if (isEmpty(value)) { return [( )]; @@ -39,7 +39,7 @@ export const indexNameValidator = (value) => { if (beginsWithPeriod(value)) { return [( )]; @@ -50,7 +50,7 @@ export const indexNameValidator = (value) => { if (illegalCharacters.length) { return [( {illegalCharacters.join(' ')} }} /> @@ -64,7 +64,7 @@ export const leaderIndexValidator = (value) => { if (isEmpty(value)) { return [( )]; @@ -75,7 +75,7 @@ export const leaderIndexValidator = (value) => { if (illegalCharacters.length) { return [( {illegalCharacters.join(' ')} }} /> diff --git a/x-pack/plugins/remote_clusters/public/sections/components/remote_cluster_form/validators/validate_seed.js b/x-pack/plugins/remote_clusters/public/sections/components/remote_cluster_form/validators/validate_seed.js index fda426f86874f..08cb15415319a 100644 --- a/x-pack/plugins/remote_clusters/public/sections/components/remote_cluster_form/validators/validate_seed.js +++ b/x-pack/plugins/remote_clusters/public/sections/components/remote_cluster_form/validators/validate_seed.js @@ -24,8 +24,8 @@ export function validateSeed(seed) { errors.push(i18n.translate( 'xpack.remoteClusters.remoteClusterForm.localSeedError.invalidCharactersMessage', { - defaultMessage: `Seed node must use host:port format. Example: 127.0.0.1:9400, localhost:9400. - Hosts can only consist of letters, numbers, and dashes.`, + defaultMessage: 'Seed node must use host:port format. Example: 127.0.0.1:9400, localhost:9400. ' + + 'Hosts can only consist of letters, numbers, and dashes.', }, )); } diff --git a/x-pack/plugins/remote_clusters/public/sections/remote_cluster_list/components/connection_status/connection_status.js b/x-pack/plugins/remote_clusters/public/sections/remote_cluster_list/components/connection_status/connection_status.js index 71d9e671fdae8..8b0cee5867ce2 100644 --- a/x-pack/plugins/remote_clusters/public/sections/remote_cluster_list/components/connection_status/connection_status.js +++ b/x-pack/plugins/remote_clusters/public/sections/remote_cluster_list/components/connection_status/connection_status.js @@ -45,7 +45,7 @@ export function ConnectionStatus({ isConnected }) { } const seedNodeTooltip = i18n.translate('xpack.remoteClusters.connectedStatus.notConnectedToolTip', { - defaultMessage: "Ensure the seed nodes are configured with the remote cluster's transport port, not the http port.", + defaultMessage: `Ensure the seed nodes are configured with the remote cluster's transport port, not the http port.`, }); return ( diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 146b7798e9cdc..9ef36f13078e2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3720,7 +3720,6 @@ "xpack.crossClusterReplication.autoFollowPattern.removeAction.successSingleNotificationTitle": "自动跟随模式 “{name}” 已删除", "xpack.crossClusterReplication.autoFollowPattern.suffixValidation.illegalCharacters": "从后缀中删除{characterListLength, plural, one {字符} other {字符}} {characterList}。", "xpack.crossClusterReplication.autoFollowPattern.suffixValidation.noEmptySpace": "后缀中不能使用空格。", - "xpack.crossClusterReplication.autoFollowPatternCreateForm.loadingRemoteClusters": "正在加载远程集群……", "xpack.crossClusterReplication.autoFollowPatternDetailPanel.closeButtonLabel": "关闭", "xpack.crossClusterReplication.autoFollowPatternDetailPanel.deleteButtonLabel": "删除", "xpack.crossClusterReplication.autoFollowPatternDetailPanel.editButtonLabel": "编辑", @@ -3736,7 +3735,6 @@ "xpack.crossClusterReplication.autoFollowPatternDetailPanel.suffixLabel": "后缀", "xpack.crossClusterReplication.autoFollowPatternDetailPanel.viewIndicesLink": "在“索引管理”中查看您的 Follower 索引", "xpack.crossClusterReplication.autoFollowPatternEditForm.loadingErrorTitle": "加载自动跟随模式时出错", - "xpack.crossClusterReplication.autoFollowPatternEditForm.loadingRemoteClusters": "正在加载远程集群……", "xpack.crossClusterReplication.autoFollowPatternEditForm.loadingTitle": "正在加载自动跟随模式……", "xpack.crossClusterReplication.autoFollowPatternEditForm.viewAutoFollowPatternsButtonLabel": "查看自动跟随模式", "xpack.crossClusterReplication.autoFollowPatternForm.actions.savingText": "正在保存", @@ -3751,7 +3749,6 @@ "xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewDescription": "上述设置将生成类似下面的索引名称:", "xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewTitle": "索引名称示例", "xpack.crossClusterReplication.autoFollowPatternForm.leaderIndexPatternError.duplicateMessage": "不允许重复的 Leader 索引模式。", - "xpack.crossClusterReplication.autoFollowPatternForm.remoteCluster.fieldClusterLabel": "远程集群", "xpack.crossClusterReplication.autoFollowPatternForm.savingErrorTitle": "创建自动跟随模式时出错", "xpack.crossClusterReplication.autoFollowPatternForm.sectionAutoFollowPatternDescription": "应用于 Follower 索引名称的定制前缀或后缀,以便您可以更容易辨识复制的索引。默认情况下,Follower 索引与 Leader 索引有相同的名称。", "xpack.crossClusterReplication.autoFollowPatternForm.sectionAutoFollowPatternNameDescription": "自动跟随模式的唯一名称。",