-
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
[App Search] Refactor AppLogic to initialize data via props rather than action #92841
Conversation
@elasticmachine merge upstream |
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.
Woo, glad to see us using the props pattern more!
@@ -32,6 +29,11 @@ export interface ConfiguredLimits { | |||
workplaceSearch: WorkplaceSearchConfiguredLimits; | |||
} | |||
|
|||
export interface Access { |
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.
EnterpriseSearchAccess
? I honestly am not sure how much I feel like we should be namespacing these in some way more but Access
feels very generic to me
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.
Maybe ProductAccess
? I think the thing I struggle with with the EnterpriseSearch
prefix is that it feels it either potentially applies to 1. the entire solution, or 2. both products (in this case not correct), or 3. the specific Enterprise Search
overview plugin.
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.
configuredLimits: [props.configuredLimits.appSearch, {}], | ||
ilmEnabled: [props.ilmEnabled, {}], |
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.
(thinking out loud) it seems wrong that these are a part of the logic but never change.
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 had this hesitation at first too, but I think @JasonStoltz managed to convince me it's not all that weird. We do this in a decent amount of our shared logic files, e.g. Kibana values/helpers, and it's easier to think about it as 'shared context' and not 'shared state' (i.e., it doesn't necessarily need to change or update). Kea at this point is basically a standard way of hooking into / sharing static or dynamic data across all our plugins, and from a dev QOL perspective makes accessing that data quick and easy (e.g., no need to use multiple Provider wrappers).
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.
Yeah, this is a bit like you were talking about the other day Byron, about putting configuration in a React Context to pass down throughout your component tree.
This is the same as that, but instead of using a React Context directly, you're using Kea. And the nice thing about that is that you don't have to deal with Contexts AND Kea in your code, you just always use Kea.
@byronhulcher Oh I totally forgot to mention, I'd like to hold off merging this in until your meta engines PR lands, so I can remove your configured Limits EDIT: done f38d6ad |
configuredLimits: Partial<ConfiguredLimits>; | ||
account: Partial<Account>; | ||
myRole: Partial<Role>; | ||
configuredLimits: ConfiguredLimits; |
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.
Oh man, that's so much better.
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.
So much better, thanks for doing this Constance.
- it was being duplicated in server/check_access and InitialAppData + add mock access data to DEFAULT_INITIAL_APP_DATA + update server/ tests to account for access in DEFAULT_INITIAL_APP_DATA
…alizeAppData + update tests to rerender a wrapper rather than doing {...DEFAULT_INITIAL_APP_DATA} repeatedly
- main goal of this PR is to prevent the flash of state between mount and initializeX being called - note: I recommend turning off whitespace changes in the test file
- which it should be in any case in a production environment - note: I could have changed InitialAppData to remove the ? optional notation, but decided on this route instead since InitialAppData affects more than just App Search (e.g. server, WS), and I didn't want this to have potential far-reaching side effects
…otentially undefined - which is mostly just configuredLimits it looks like
💚 Build Succeeded
Metrics [docs]Async chunks
Page load bundle
History
To update your PR or re-run it, just comment with: cc @JasonStoltz |
…an action (elastic#92841) * [Misc cleanup] Move Access type to common - it was being duplicated in server/check_access and InitialAppData + add mock access data to DEFAULT_INITIAL_APP_DATA + update server/ tests to account for access in DEFAULT_INITIAL_APP_DATA * Update AppSearchConfigured to pass props to AppLogic vs calling initializeAppData + update tests to rerender a wrapper rather than doing {...DEFAULT_INITIAL_APP_DATA} repeatedly * Update AppLogic to set values from props rather than a listener - main goal of this PR is to prevent the flash of state between mount and initializeX being called - note: I recommend turning off whitespace changes in the test file * Update AppLogic typing so that app data is always expected - which it should be in any case in a production environment - note: I could have changed InitialAppData to remove the ? optional notation, but decided on this route instead since InitialAppData affects more than just App Search (e.g. server, WS), and I didn't want this to have potential far-reaching side effects * Update type scenarios where AppLogic values were previously thought potentially undefined - which is mostly just configuredLimits it looks like * [PR feedback] Type name
…an action (#92841) (#93292) * [Misc cleanup] Move Access type to common - it was being duplicated in server/check_access and InitialAppData + add mock access data to DEFAULT_INITIAL_APP_DATA + update server/ tests to account for access in DEFAULT_INITIAL_APP_DATA * Update AppSearchConfigured to pass props to AppLogic vs calling initializeAppData + update tests to rerender a wrapper rather than doing {...DEFAULT_INITIAL_APP_DATA} repeatedly * Update AppLogic to set values from props rather than a listener - main goal of this PR is to prevent the flash of state between mount and initializeX being called - note: I recommend turning off whitespace changes in the test file * Update AppLogic typing so that app data is always expected - which it should be in any case in a production environment - note: I could have changed InitialAppData to remove the ? optional notation, but decided on this route instead since InitialAppData affects more than just App Search (e.g. server, WS), and I didn't want this to have potential far-reaching side effects * Update type scenarios where AppLogic values were previously thought potentially undefined - which is mostly just configuredLimits it looks like * [PR feedback] Type name Co-authored-by: Constance <[email protected]>
myRole: { canManageEngines, canManageMetaEngines }, | ||
} = useValues(AppLogic); | ||
} = useValues(AppLogic(props)); |
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.
TIL there is another way to do this. Definitely think what we have is the right solution but it's nice to see that we could do something else in a component, if needed. Particularly if we needed shared props in multiple child components
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.
TIL!!! Thanks Scotty, that's incredibly helpful if we start diving into keyed logic 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.
Yeah, I'm beginning the process of migrating App Search's Role Mappings and see a lot of shared code in our logic files. Thinking of either creating a shared logic file or finding a way to inherit reducers and actions from some sort of shared parent logic file.
Summary
I strongly recommend following along per-commit in this PR. It's relatively small, but there's some jumps/test cleanups, and I also tried to leave very detailed notes in my commit messages.
Before
Per recent discovery from @byronhulcher and @JasonStoltz, we were running into "flash" scenarios due to the way we were initializing data in our AppLogic file. Because we were initializing with default empty objs and then calling
initializeAppData
on load, this was leading to the following scenario:This was particularly problematic on routings wrapped in role capabilities, where one route would briefly and erroneously load before another.
After
With this new fix, any data in
AppLogic
should only be initialized once, never as falsy/undefined (unless something has gone seriously wrong with our config API endpoint, in which case the entirely plugin should not register as loaded):Also, we can now refer to configuredLimits without having to add extra logic for potential falsy-ness all the dang time.
QA
Checklist