-
Notifications
You must be signed in to change notification settings - Fork 8.6k
[CCR] Improve form error handling and general UX #29419
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
Changes from 8 commits
83d6fd4
ff69183
7cd920c
6442d95
c4147f8
3bda0df
79b3590
9f35f2a
3cc75ea
867c1c3
a0c2b92
9a30779
c223154
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,6 @@ import { | |
| FollowerIndexPageTitle, | ||
| RemoteClustersProvider, | ||
| SectionLoading, | ||
| SectionError, | ||
| } from '../../components'; | ||
|
|
||
| export const FollowerIndexAdd = injectI18n( | ||
|
|
@@ -41,7 +40,7 @@ export const FollowerIndexAdd = injectI18n( | |
| } | ||
|
|
||
| render() { | ||
| const { saveFollowerIndex, clearApiError, apiStatus, apiError, intl, match: { url: currentUrl } } = this.props; | ||
| const { saveFollowerIndex, clearApiError, apiStatus, apiError, match: { url: currentUrl } } = this.props; | ||
|
|
||
| return ( | ||
| <EuiPageContent | ||
|
|
@@ -70,20 +69,12 @@ export const FollowerIndexAdd = injectI18n( | |
| ); | ||
| } | ||
|
|
||
| if (error) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this removed, we now show a prompt to the user when there's an error: I'm a bit on the fence about this because it seems inaccurate and could possibly seem "deceptive" to the user. Imagine clicking the "Add remote cluster" button, completing the action, and then being redirected back here only to see this prompt again. At that point I'd be pretty surprised and confused -- there's something wrong but I wouldn't know what. What are your thoughts on this UX?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the previous UX was: the user enters follower indices, he clicks on "Add a follower index" and instead of accessing a form he had a red callout saying that the remote clusters could not be loaded. Unless he looks at the documentation and knows about the remote cluster field, that error message was not very helpful for the user, blocking him from accessing the form. Also, if the list of clusters can't be loaded, he probably won't be able either to add a remote cluster. So that would help him understand better this message here in the add follower index form. |
||
| const title = intl.formatMessage({ | ||
| id: 'xpack.crossClusterReplication.followerIndexCreateForm.loadingRemoteClustersErrorTitle', | ||
| defaultMessage: 'Error loading remote clusters', | ||
| }); | ||
| return <SectionError title={title} error={error} />; | ||
| } | ||
|
|
||
| return ( | ||
| <FollowerIndexForm | ||
| apiStatus={apiStatus} | ||
| apiError={apiError} | ||
| currentUrl={currentUrl} | ||
| remoteClusters={remoteClusters} | ||
| remoteClusters={error ? [] : remoteClusters} | ||
| saveFollowerIndex={saveFollowerIndex} | ||
| clearApiError={clearApiError} | ||
| /> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,12 +7,19 @@ | |
| import React, { PureComponent, Fragment } from 'react'; | ||
| import PropTypes from 'prop-types'; | ||
| import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; | ||
| import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; | ||
| import { | ||
| EuiButton, | ||
| EuiEmptyPrompt, | ||
| EuiFlexGroup, | ||
| EuiFlexItem, | ||
| EuiText, | ||
| EuiSpacer, | ||
| } from '@elastic/eui'; | ||
|
|
||
| import routing from '../../../services/routing'; | ||
| import { extractQueryParams } from '../../../services/query_params'; | ||
| import { API_STATUS } from '../../../constants'; | ||
| import { SectionLoading, SectionError } from '../../../components'; | ||
| import { SectionLoading, SectionError, SectionUnauthorized } from '../../../components'; | ||
| import { AutoFollowPatternTable, DetailPanel } from './components'; | ||
|
|
||
| const REFRESH_RATE_MS = 30000; | ||
|
|
@@ -88,6 +95,71 @@ export const AutoFollowPatternList = injectI18n( | |
| clearInterval(this.interval); | ||
| } | ||
|
|
||
| renderHeader() { | ||
| const { isAuthorized } = this.props; | ||
| return ( | ||
| <Fragment> | ||
| <EuiFlexGroup justifyContent="spaceBetween" alignItems="flexStart"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiText> | ||
| <p> | ||
| <FormattedMessage | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! |
||
| id="xpack.crossClusterReplication.followerIndexList.followerIndicesDescription" | ||
| defaultMessage="Followers replicate operations from the leader index to the follower index." | ||
| /> | ||
| </p> | ||
| </EuiText> | ||
| </EuiFlexItem> | ||
|
|
||
| <EuiFlexItem grow={false}> | ||
| {isAuthorized && ( | ||
| <EuiButton | ||
| {...routing.getRouterLinkProps('/follower_indices/add')} | ||
| fill | ||
| iconType="plusInCircle" | ||
| > | ||
| <FormattedMessage | ||
| id="xpack.crossClusterReplication.followerIndexList.addFollowerButtonLabel" | ||
| defaultMessage="Create a follower index" | ||
| /> | ||
| </EuiButton> | ||
| )} | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
|
|
||
| <EuiSpacer /> | ||
| </Fragment> | ||
| ); | ||
| } | ||
|
|
||
| renderContent(isEmpty) { | ||
| const { apiError, isAuthorized, intl } = this.props; | ||
| if (!isAuthorized) { | ||
| return ( | ||
| <SectionUnauthorized> | ||
| <FormattedMessage | ||
| id="xpack.crossClusterReplication.autoFollowPatternList.noPermissionText" | ||
| defaultMessage="You do not have permission to view or add auto-follow patterns." | ||
| /> | ||
| </SectionUnauthorized> | ||
| ); | ||
| } | ||
|
|
||
| if (apiError) { | ||
| const title = intl.formatMessage({ | ||
| id: 'xpack.crossClusterReplication.autoFollowPatternList.loadingErrorTitle', | ||
| defaultMessage: 'Error loading auto-follow patterns', | ||
| }); | ||
| return <SectionError title={title} error={apiError} />; | ||
| } | ||
|
|
||
| if (isEmpty) { | ||
| return this.renderEmpty(); | ||
| } | ||
|
|
||
| return this.renderList(); | ||
| } | ||
|
|
||
| renderEmpty() { | ||
| return ( | ||
| <EuiEmptyPrompt | ||
|
|
@@ -156,25 +228,15 @@ export const AutoFollowPatternList = injectI18n( | |
| } | ||
|
|
||
| render() { | ||
| const { autoFollowPatterns, apiStatus, apiError, isAuthorized, intl } = this.props; | ||
|
|
||
| if (!isAuthorized) { | ||
| return null; | ||
| } | ||
|
|
||
| if (apiStatus === API_STATUS.IDLE && !autoFollowPatterns.length) { | ||
| return this.renderEmpty(); | ||
| } | ||
| const { autoFollowPatterns, apiStatus, } = this.props; | ||
| const isEmpty = apiStatus === API_STATUS.IDLE && !autoFollowPatterns.length; | ||
|
|
||
| if (apiError) { | ||
| const title = intl.formatMessage({ | ||
| id: 'xpack.crossClusterReplication.autoFollowPatternList.loadingErrorTitle', | ||
| defaultMessage: 'Error loading auto-follow patterns', | ||
| }); | ||
| return <SectionError title={title} error={apiError} />; | ||
| } | ||
|
|
||
| return this.renderList(); | ||
| return ( | ||
| <Fragment> | ||
| {!isEmpty && this.renderHeader()} | ||
| {this.renderContent(isEmpty)} | ||
| </Fragment> | ||
| ); | ||
| } | ||
| } | ||
| ); | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would have been better with a
Math.max(0, parseInt(value, 10))and removing the next line. I'll update it.