-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Management] Index pattern step in React! #15936
[Management] Index pattern step in React! #15936
Conversation
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.
Wow it's amazing how much more readable this becomes once you throw a little React at it! Great job splitting this up and refactoring the code. I had a few suggestions and questions. I know you already noted this in the PR description, but some snapshot tests for the new components would be great at some point.
@@ -124,7 +128,10 @@ <h2 class="euiTitle euiTitle--small euiTextColor euiTextColor--subdued"> | |||
ng-switch="controller.wizardStep" | |||
> | |||
<!-- Specify index pattern --> | |||
<step-index-pattern | |||
<div ng-switch-when="indexPattern"> | |||
<div id="stepIndexPatternReact"></div> |
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.
Why not use ng-react
to create a temporary directive to wrap the component? This way we'd be using a consistent mechanism for bridging angular to react. Here's an example of how I'm defining the toasts directive wrapper and here's an example of how it's consumed.
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.
I guess I didn't think it mattered since this file is going away in #15905
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.
OK your call
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.
I don't use ng-react either.
this.state = { | ||
matchingIndices: [], | ||
isLoadingIndices: false, | ||
query: props.initialQuery || '', |
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.
We can use defaultProps
to pass in an empty string instead of applying a default here.
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.
Sounds good!
@@ -0,0 +1,3 @@ | |||
export function getPaginatedIndices(indices, page, perPage) { |
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.
Tests for this would be great in a later iteration.
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.
I would maybe use the EuiPager component. It already does the math for this for you.
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.
Where can I find that?
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.
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.
Sorry this one's a little hidden... it's with the services: https://github.com/elastic/eui/tree/master/src/services/paging
@@ -0,0 +1,11 @@ | |||
export function isIndexPatternQueryValid(pattern, illegalCharacters) { |
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.
Tests for this would be great in a later iteration.
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.
Done!
<EuiFlexItem grow={false}> | ||
<EuiText> | ||
<EuiTextColor color="subdued"> | ||
Looking for matching indices... |
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.
Can we treat this loading feedback the same way we treated the feedback the same way we treat the loading feedback when checking for indices? With a spinner, left-aligned, etc?
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.
Yup!
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
<EuiSpacer size="s"/> | ||
<div> |
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.
Is this div necessary?
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.
Nope, removing
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.
Looking good. Some tests would be nice to add I think before merging.
let containsErrors = false; | ||
const errors = []; | ||
const characterList = ILLEGAL_CHARACTERS.slice(0, ILLEGAL_CHARACTERS.length - 1).join(', '); | ||
|
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.
Why is this line here? You are taking every character but the last one to display, but don't know why.
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.
Yup, nice catch. I'm excluding the last one because it's an empty space and it looks off in the UI if I show that with a comma. Should I just show it? Or add a comment here?
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd"> | ||
<EuiFlexItem grow={false}> | ||
<EuiForm | ||
isInvalid={showingIndexPatternQueryErrors && containsErrors} |
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.
since you use this twice I would do this above:
const isInvalid = showingIndexPatternQueryErrors && containsErrors;
<EuiButton | ||
iconType="arrowRight" | ||
onClick={() => goToNextStep(query)} | ||
isDisabled={containsErrors || indices.length === 0} |
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.
Same kind of thing as above, maybe a isDisabled constant.
@@ -124,7 +128,10 @@ <h2 class="euiTitle euiTitle--small euiTextColor euiTextColor--subdued"> | |||
ng-switch="controller.wizardStep" | |||
> | |||
<!-- Specify index pattern --> | |||
<step-index-pattern | |||
<div ng-switch-when="indexPattern"> | |||
<div id="stepIndexPatternReact"></div> |
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.
I don't use ng-react either.
this.goToTimeFieldStep(); | ||
$scope.$apply(); | ||
} | ||
)); | ||
}; |
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 seems gross to me, but I'm assuming this code is transitional in nature. If this is just a step along the road to cleaner and more complete reactification, then this is OK. If this is intended as an integration pattern, then I have some issues with this.
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.
Yup, just transitional
@@ -0,0 +1,3 @@ | |||
export function getPaginatedIndices(indices, page, perPage) { |
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.
I would maybe use the EuiPager component. It already does the math for this for you.
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.
LGTM! I had a few suggestions but none of them are blockers.
import sinon from 'sinon'; | ||
|
||
describe('createReasonableWait', () => { | ||
it('should eventually calls the callback', () => { |
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.
I think we should just verify that this function returns a promise (i.e. that the return object provides a then
method). Considering most tests take a few ms to execute, I think forcing this one to take 500 ms is too high a cost for such a simple unit of code.
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.
Good call, I'll change that
}; | ||
|
||
// https://github.com/facebook/jest/issues/1377 | ||
const syncify = async (fn) => { |
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.
Can we migrate this to EUI? We have a test
directory which publishes other test helpers. Seems like this one would be handy.
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.
Sure, sounds good
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.
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.
If you rebase master so you get Jest 22 you don't need syncify
anymore:
await expect(myPromise).rejects.toThrow('failure');
return acceptableIndices.slice(0, MAX_NUMBER_OF_MATCHING_INDICES); | ||
} | ||
|
||
export function getWhitelistedIndices(indices, isIncludingSystemIndices, query, matchingIndices) { |
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.
The word "whitelisted" threw me off in this function name. I kept thinking that it was responsible for whitelisting somehow, but I think that's actually just an implementation detail we can ignore from an interface standpoint. Since you're passing in some initial indices and then getting back different lists of indices which match to various degrees, how about renaming this function to matchIndices
?
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.
Changed!
@@ -0,0 +1,7 @@ | |||
export const canAppendWildcard = ({ data: keyPressed }) => { |
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.
Why destructure an object here if there's only one prop? Why not pass in the keyPressed
argument directly?
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.
You're right, no need
ae7345d
to
7f97352
Compare
return null; | ||
} | ||
|
||
const indices = getMatchedIndices(allIndices, partialMatchedIndices, query, isIncludingSystemIndices); |
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.
We're calling getMatchedIndices
here and on lines 94 and 139. Would it be more efficient to call it once within render()
and then pass the result as an argument to renderStatusMessage()
, renderList()
, and renderHeader()
?
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.
For sure!
@cjcenizal Is this still good to go? |
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.
⛳️ MERGE WORTHY!
Before merging, maybe rebase master (so you get Jest 22), remove
|
@bmcconaghy I'm going to merge this as soon as tests pass so I can move on to the second step, but please let me know if you want any changes. |
a0a84b0
to
16d34d8
Compare
* Index pattern step in React! * Remove dead lines * Ensure this only shows up when applicable * PR feedback * Use pager * Add tests for lib/ * PR feedback * Tests and PR feedback * More tests and PR feedback * New jest functionality
* Index pattern step in React! * Remove dead lines * Ensure this only shows up when applicable * PR feedback * Use pager * Add tests for lib/ * PR feedback * Tests and PR feedback * More tests and PR feedback * New jest functionality
Backport 6.x: 0b36c0a |
Hey @chrisronline, Is 6.2 really the earliest version that this change got into? I'm a bit confused, I see this https://github.com/elastic/kibana/blob/6.2/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/constants/index.js together with this "old" piece of code https://github.com/elastic/kibana/blob/6.2/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js#L32-L38 |
6.2 just got a single part of the wizard in React, but when I did the original work, I did it all in a single branch and attempted to break it out into separate branches to make the PR process better as well as allowing us to incrementally test each section. I think what happened is that constants file was used in the full branch but not necessary in this one but slipped in accidentally |
Relates to #15905
Resolves #15922
Background
This PR is the first step at refactoring the index pattern creation wizard from Angular to React. The management team decided to do both the EUI and React refactor at the same time.
Details
This PR removes all existing angular code around the index pattern step (which is the first step, where you select an index pattern). It replaces it with React code and also creates a different separation than previously existed.
The file structure looks like:
components/
- This contains all the parts of the index pattern creation wizard, including this stepconstants/
- This is where the constants used throughout index pattern creation are storedlib/
- This is where helper functions exist, isolated and dependency-freeFurther Work
Currently, the
index.js
withincomponents/step_index_pattern
exposes a function that does the actual React rendering, but this will eventually be deprecated as the shell (the code directly withinsections/indices/create_index_pattern_wizard
) has been converted.Tests
Screenshots