Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CCR] Show remote cluster validation in CCR forms, and add edit follower index #28778

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
298803d
[CCR] Advanced settings component
sebelga Jan 8, 2019
5d81b44
Remove preview active on toggle settings
sebelga Jan 8, 2019
0094099
Add client side validation of advanced settings form
sebelga Jan 9, 2019
a2f6bea
Move form entry row to separate component
sebelga Jan 9, 2019
842f88a
Add title to panel
sebelga Jan 9, 2019
5211cf5
Add i18n translation of advanced settings
sebelga Jan 9, 2019
dd9b8bf
Update Follower index form with toggle for advanced settings
sebelga Jan 10, 2019
4530329
Add server side serialisation for advanced settings
sebelga Jan 10, 2019
72c266b
Make code review changes
sebelga Jan 11, 2019
ae4762f
Merge branch 'feature/ccr' into feature/ccr_follower_advanced_settings
sebelga Jan 11, 2019
cb1467d
Merge branch 'feature/ccr' into feature/ccr_follower_advanced_settings
sebelga Jan 12, 2019
f6360ea
Fix test: mock constant dependency
sebelga Jan 13, 2019
5fdd053
Merge branch 'feature/ccr' into feature/ccr_follower_advanced_settings
sebelga Jan 14, 2019
9aaab0e
Add section to edit follower index
sebelga Jan 11, 2019
7c7eb75
Show confirm modal before updating follower index
sebelga Jan 11, 2019
958b77f
Add edit icon in table + update server endpoint to pause / resume
sebelga Jan 14, 2019
9d9a959
[CCR] Show remote cluster validation in follower index form & auto-fo…
sebelga Jan 15, 2019
f45553a
Merge remote-tracking branch 'upstream/feature/ccr' into feature/ccr_…
jen-huang Jan 17, 2019
3ae6be7
PR feedback, cleanup form sizes, add redirect to edit remote cluster
jen-huang Jan 17, 2019
df3107f
Fix routing, remove unused code, adjust auto follow pattern edit load…
jen-huang Jan 17, 2019
8d6293c
Merge remote-tracking branch 'upstream/feature/ccr_seb-temp-2' into f…
jen-huang Jan 18, 2019
da359c8
Adjust error messages and make remote cluster not found edit page the…
jen-huang Jan 18, 2019
e3c20a5
Merge remote-tracking branch 'upstream/feature/ccr' into feature/ccr_…
jen-huang Jan 18, 2019
91e9978
Fix functionality as result of merge
jen-huang Jan 18, 2019
c95982b
Fix validation, reorder actions, fix tests, and address feedback
jen-huang Jan 18, 2019
844df58
PR feedback and fix validation pt 2
jen-huang Jan 18, 2019
6082bf5
Adjust remote cluster validation
jen-huang Jan 19, 2019
8189efe
Fix i18n
jen-huang Jan 22, 2019
10c0a19
Fix api error not showing on add follower form
jen-huang Jan 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions x-pack/plugins/cross_cluster_replication/common/services/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ export const wait = (time = 1000) => (data) => {
setTimeout(() => resolve(data), time);
});
};

/**
* Utility to remove empty fields ("") from a request body
*/
export const removeEmptyFields = (body) => (
Object.entries(body).reduce((acc, [key, value]) => {
if (value !== '') {
acc[key] = value;
}
return acc;
}, {})
);
2 changes: 2 additions & 0 deletions x-pack/plugins/cross_cluster_replication/public/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
AutoFollowPatternAdd,
AutoFollowPatternEdit,
FollowerIndexAdd,
FollowerIndexEdit,
} from './sections';

export class App extends Component {
Expand Down Expand Up @@ -54,6 +55,7 @@ export class App extends Component {
<Route exact path={`${BASE_PATH}/auto_follow_patterns/add`} component={AutoFollowPatternAdd} />
<Route exact path={`${BASE_PATH}/auto_follow_patterns/edit/:id`} component={AutoFollowPatternEdit} />
<Route exact path={`${BASE_PATH}/follower_indices/add`} component={FollowerIndexAdd} />
<Route exact path={`${BASE_PATH}/follower_indices/edit/:id`} component={FollowerIndexEdit} />
<Route exact path={`${BASE_PATH}/:section`} component={CrossClusterReplicationHome} />
</Switch>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ import {
EuiSpacer,
EuiText,
EuiTitle,
EuiSuperSelect,
} from '@elastic/eui';

import { INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/index_patterns';
import { INDEX_ILLEGAL_CHARACTERS_VISIBLE } from 'ui/indices';

import routing from '../services/routing';
import { extractQueryParams } from '../services/query_params';
import { API_STATUS } from '../constants';
import { SectionError, AutoFollowPatternIndicesPreview } from './';
import { SectionError } from './section_error';
import { AutoFollowPatternIndicesPreview } from './auto_follow_pattern_indices_preview';
import { RemoteClustersFormField } from './remote_clusters_form_field';
import { validateAutoFollowPattern, validateLeaderIndexPattern } from '../services/auto_follow_pattern_validators';

const indexPatternIllegalCharacters = INDEX_PATTERN_ILLEGAL_CHARACTERS_VISIBLE.join(' ');
Expand All @@ -46,12 +48,22 @@ const getFirstConnectedCluster = (clusters) => {
return clusters[i];
}
}
return {};

/**
* No cluster connected, we return the first one in the list
*/
return clusters.length ? clusters[0] : {};
};

const getEmptyAutoFollowPattern = (remoteClusters) => ({
const getRemoteClusterName = (remoteClusters, selected) => {
return selected && remoteClusters.some(c => c.name === selected)
? selected
: getFirstConnectedCluster(remoteClusters).name;
};

const getEmptyAutoFollowPattern = (remoteClusters, remoteClusterSelected) => ({
name: '',
remoteCluster: getFirstConnectedCluster(remoteClusters).name,
remoteCluster: getRemoteClusterName(remoteClusters, remoteClusterSelected),
leaderIndexPatterns: [],
followIndexPatternPrefix: '',
followIndexPatternSuffix: '',
Expand All @@ -70,16 +82,18 @@ export class AutoFollowPatternFormUI extends PureComponent {
autoFollowPattern: PropTypes.object,
apiError: PropTypes.object,
apiStatus: PropTypes.string.isRequired,
remoteClusters: PropTypes.array.isRequired,
currentUrl: PropTypes.string.isRequired,
remoteClusters: PropTypes.array,
}

constructor(props) {
super(props);

const isNew = this.props.autoFollowPattern === undefined;

const { route: { location: { search } } } = routing.reactRouter;
const queryParams = extractQueryParams(search);
const autoFollowPattern = isNew
? getEmptyAutoFollowPattern(this.props.remoteClusters)
? getEmptyAutoFollowPattern(this.props.remoteClusters, queryParams.cluster)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to call getRemoteClusterName here and pass in the remote cluster instead of these two arguments, since that's really what getEmptyAutoFollowPattern is concerned with.

const getEmptyAutoFollowPattern = (remoteCluster) => ({
  name: '',
  remoteCluster,
  leaderIndexPatterns: [],
  followIndexPatternPrefix: '',
  followIndexPatternSuffix: '',
});

/* ... */

const remoteCluster = getRemoteClusterName(this.props.remoteClusters, queryParams.cluster);
const autoFollowPattern = isNew
  ? getEmptyAutoFollowPattern(remoteCluster)
  : {
    ...this.props.autoFollowPattern,
  };

: {
...this.props.autoFollowPattern,
};
Expand All @@ -101,9 +115,11 @@ export class AutoFollowPatternFormUI extends PureComponent {
}));

const errors = validateAutoFollowPattern(fields);
this.setState(({ fieldsErrors }) => updateFormErrors(errors, fieldsErrors));
this.onFieldsErrorChange(errors);
};

onFieldsErrorChange = (errors) => this.setState(({ fieldsErrors }) => updateFormErrors(errors, fieldsErrors));

onClusterChange = (remoteCluster) => {
this.onFieldsChange({ remoteCluster });
};
Expand Down Expand Up @@ -169,8 +185,8 @@ export class AutoFollowPatternFormUI extends PureComponent {

this.setState(({ fieldsErrors }) => updateFormErrors(errors, fieldsErrors));
} else {
this.setState(({ fieldsErrors, autoFollowPattern }) => {
const errors = validateAutoFollowPattern(autoFollowPattern);
this.setState(({ fieldsErrors, autoFollowPattern: { leaderIndexPatterns } }) => {
const errors = validateAutoFollowPattern({ leaderIndexPatterns });
return updateFormErrors(errors, fieldsErrors);
});
}
Expand Down Expand Up @@ -293,12 +309,26 @@ export class AutoFollowPatternFormUI extends PureComponent {
* Remote Cluster
*/
const renderRemoteClusterField = () => {
const remoteClustersOptions = this.props.remoteClusters.map(({ name, isConnected }) => ({
value: name,
inputDisplay: isConnected ? name : `${name} (not connected)`,
disabled: !isConnected,
'data-test-subj': `option-${name}`
}));
const { remoteClusters, currentUrl } = this.props;

const errorMessages = {
noClusterFound: () => (<FormattedMessage
id="xpack.crossClusterReplication.autoFollowPatternForm.emptyRemoteClustersCallOutDescription"
defaultMessage="Auto-follow patterns capture indices on remote clusters. You must add a remote cluster."
/>),
remoteClusterNotConnectedNotEditable: (name) => (<FormattedMessage
id="xpack.crossClusterReplication.autoFollowPatternForm.currentRemoteClusterNotConnectedCallOutDescription"
defaultMessage="The remote cluster '{name}' is not connected.
You need to connect it before editing the auto-follow pattern."
values={{ name }}
/>),
remoteClusterDoesNotExist: (name) => (<FormattedMessage
id="xpack.crossClusterReplication.autoFollowPatternForm.currentRemoteClusterNotFoundCallOutDescription"
defaultMessage="The remote cluster '{name}' was not found. It might have been removed.
In order to edit the auto-follow pattern, you need to add a remote cluster with the same name."
values={{ name }}
/>)
};

return (
<EuiDescribedFormGroup
Expand All @@ -320,32 +350,16 @@ export class AutoFollowPatternFormUI extends PureComponent {
)}
fullWidth
>
<EuiFormRow
label={(
<FormattedMessage
id="xpack.crossClusterReplication.autoFollowPatternForm.remoteCluster.fieldClusterLabel"
defaultMessage="Remote cluster"
/>
)}
fullWidth
>
<Fragment>
{ isNew && (
<EuiSuperSelect
options={remoteClustersOptions}
valueOfSelected={remoteCluster}
onChange={this.onClusterChange}
/>
)}
{ !isNew && (
<EuiFieldText
value={remoteCluster}
fullWidth
disabled={true}
/>
)}
</Fragment>
</EuiFormRow>
<RemoteClustersFormField
selected={remoteCluster ? remoteCluster : null}
remoteClusters={remoteClusters}
currentUrl={currentUrl}
isEditable={isNew}
areErrorsVisible={areErrorsVisible}
onChange={this.onClusterChange}
onError={(error) => this.onFieldsErrorChange({ remoteCluster: error })}
errorMessages={errorMessages}
/>
</EuiDescribedFormGroup>
);
};
Expand Down
Loading