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

perf(RHIF-167): get rid of activeApps in redux #1754

Merged
merged 6 commits into from
Feb 22, 2023

Conversation

mkholjuraev
Copy link
Contributor

@mkholjuraev mkholjuraev commented Feb 1, 2023

This is the second step of improving the Inventory details page by getting rid of using the redux store to render active apps in the Main section tab. Now, an active application that needs to be displayed will be decided by the appName in the URL. If it is not set, the first application in appsList prop will get displayed. Also, this PR introduces wrapping general information sections with Card component as a result of this UX ask. This PR is backward compatible. There are a few extra components that needs to be removed once all apps migrate to new approach safely.

Benefits of this refactor:

  1. Better tab layout. No need to render the tab menu separate from the tab content.
  2. Consumer apps can adopt DetailHeader as a presentation component if it has its own data to populate.
  3. AppInfo component is being removed with activeApps in redux which will decrease complexity.
  4. No redux involved in changing, or rendering the tab. The URL parameter appName is used to change tabs, render the default tab
  5. General information cards are separated as a card for better design
  6. Inventory header component and Main section where the tab and apps render are decoupled. Now, both can load independently
  7. InventoryDetail component truly renders the whole Inventory detail page. Before it would render the header, while main section needed to be rendered using AppInfo

Regarding consumer applications dealing with InventoryDetailHead and AppInfo components in the fed-mod, I have been working to remove AppInfo component and passing inventoryId into DetailsWrapper component to directly use DetailHeader as presentational component. This gives those apps more freedom, and reduces the complexity of how we deal with federated modules. In the following commit/PR I will target consuming InventoryDetailHeader and DetailWrapper in fed-modules.

General information tab before:

image

General information tab after:
image

@mkholjuraev mkholjuraev requested a review from a team as a code owner February 1, 2023 18:42
@mkholjuraev mkholjuraev requested a review from karelhala February 2, 2023 09:35
@mkholjuraev
Copy link
Contributor Author

Putting this in the draft state to merge Karel's PR and this together as a unified refactoring approach.

@mkholjuraev mkholjuraev marked this pull request as draft February 6, 2023 10:38
@mkholjuraev mkholjuraev marked this pull request as ready for review February 9, 2023 13:24
@codecov-commenter
Copy link

codecov-commenter commented Feb 10, 2023

Codecov Report

Base: 73.29% // Head: 73.02% // Decreases project coverage by -0.27% ⚠️

Coverage data is based on head (6637e28) compared to base (6343202).
Patch coverage: 32.00% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1754      +/-   ##
==========================================
- Coverage   73.29%   73.02%   -0.27%     
==========================================
  Files          97       98       +1     
  Lines        2127     2143      +16     
  Branches      823      829       +6     
==========================================
+ Hits         1559     1565       +6     
- Misses        568      578      +10     
Impacted Files Coverage Δ
src/Routes.js 0.00% <0.00%> (ø)
...c/components/InventoryDetail/ApplicationDetails.js 0.00% <0.00%> (ø)
src/components/InventoryDetail/DetailHeader.js 0.00% <0.00%> (ø)
src/components/InventoryDetail/InventoryDetail.js 0.00% <0.00%> (ø)
src/modules/DetailHeader.js 0.00% <0.00%> (ø)
src/modules/InventoryDetail.js 0.00% <ø> (ø)
src/routes/InventoryDetail.js 0.00% <0.00%> (ø)
src/store/action-types.js 100.00% <ø> (ø)
src/store/entityDetails.js 3.84% <ø> (+0.27%) ⬆️
src/store/inventory-actions.js 79.54% <ø> (-0.46%) ⬇️
... and 8 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Copy link
Contributor

@adonispuente adonispuente left a comment

Choose a reason for hiding this comment

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

While testing this PR I was unable to find any change/errors other than the intended changes like layout/performance.
I'd prefer another person take a look as well, but I was unable to find any issues. Great Job!

@mkholjuraev mkholjuraev requested a review from a team February 14, 2023 00:46
Copy link
Contributor

@karelhala karelhala left a comment

Choose a reason for hiding this comment

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

Looking good! Just a few minor questions and adjustments. I'll test it locally later on.

@@ -60,7 +60,7 @@ class GeneralInformation extends Component {
};

componentDidMount() {
this.props.loadSystemDetail && this.props.loadSystemDetail(this.props.entity.id);
this.props.loadSystemDetail && this.props.loadSystemDetail(this.props.inventoryId);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd change this so we don't make the inventoryId required yet (edge for instance doesn't pass it yet)

Suggested change
this.props.loadSystemDetail && this.props.loadSystemDetail(this.props.inventoryId);
this.props.loadSystemDetail?.(this.props.inventoryId || this.props.entity.id);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aha, I will do so

Comment on lines 12 to 66
const DetailHeader = ({
entity,
hideInvLink,
loaded,
addNotification,
deleteEntity,
onBackToListClick,
actions,
UUIDWrapper,
LastSeenWrapper,
children,
showInventoryDrawer,
shouldWrapAsPage,
BreadcrumbWrapper,
additionalClasses,
showDelete,
showTags,
TitleWrapper,
TagsWrapper,
DeleteWrapper,
ActionsWrapper
}) => {
const HeaderInfo = (<Fragment>
<TopBar
entity={entity}
loaded={loaded}
onBackToListClick={onBackToListClick}
actions={actions}
deleteEntity={deleteEntity}
addNotification={addNotification}
hideInvLink={hideInvLink}
showInventoryDrawer={showInventoryDrawer}
showDelete={showDelete}
showTags={showTags}
TitleWrapper={TitleWrapper}
TagsWrapper={TagsWrapper}
DeleteWrapper={DeleteWrapper}
ActionsWrapper={ActionsWrapper}
/>
<FactsInfo
loaded={loaded}
entity={entity}
UUIDWrapper={UUIDWrapper}
LastSeenWrapper={LastSeenWrapper}
/>
{(loaded && verifyCulledInsightsClient(entity?.per_reporter_staleness)) && <InsightsPrompt />}
{children}
</Fragment>);

return (shouldWrapAsPage ?
(<PageHeader className={classnames('pf-m-light ins-inventory-detail', additionalClasses)} >
{BreadcrumbWrapper}
{HeaderInfo}
</PageHeader>) : HeaderInfo);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not a good idea to create new component on each render (especially with so many props). How about we'd split it into two components?

Suggested change
const DetailHeader = ({
entity,
hideInvLink,
loaded,
addNotification,
deleteEntity,
onBackToListClick,
actions,
UUIDWrapper,
LastSeenWrapper,
children,
showInventoryDrawer,
shouldWrapAsPage,
BreadcrumbWrapper,
additionalClasses,
showDelete,
showTags,
TitleWrapper,
TagsWrapper,
DeleteWrapper,
ActionsWrapper
}) => {
const HeaderInfo = (<Fragment>
<TopBar
entity={entity}
loaded={loaded}
onBackToListClick={onBackToListClick}
actions={actions}
deleteEntity={deleteEntity}
addNotification={addNotification}
hideInvLink={hideInvLink}
showInventoryDrawer={showInventoryDrawer}
showDelete={showDelete}
showTags={showTags}
TitleWrapper={TitleWrapper}
TagsWrapper={TagsWrapper}
DeleteWrapper={DeleteWrapper}
ActionsWrapper={ActionsWrapper}
/>
<FactsInfo
loaded={loaded}
entity={entity}
UUIDWrapper={UUIDWrapper}
LastSeenWrapper={LastSeenWrapper}
/>
{(loaded && verifyCulledInsightsClient(entity?.per_reporter_staleness)) && <InsightsPrompt />}
{children}
</Fragment>);
return (shouldWrapAsPage ?
(<PageHeader className={classnames('pf-m-light ins-inventory-detail', additionalClasses)} >
{BreadcrumbWrapper}
{HeaderInfo}
</PageHeader>) : HeaderInfo);
};
const HeaderInfo = ({ entity, loaded, UUIDWrapper, LastSeenWrapper, children, ...props }) => (<Fragment>
<TopBar
entity={entity}
loaded={loaded}
{...props}
/>
<FactsInfo
loaded={loaded}
entity={entity}
UUIDWrapper={UUIDWrapper}
LastSeenWrapper={LastSeenWrapper}
/>
{(loaded && verifyCulledInsightsClient(entity?.per_reporter_staleness)) && <InsightsPrompt />}
{children}
</Fragment>);
const DetailHeader = ({ shouldWrapAsPage, ...props }) => {
return (shouldWrapAsPage ?
(<PageHeader className={classnames('pf-m-light ins-inventory-detail', additionalClasses)} >
{BreadcrumbWrapper}
<HeaderInfo {...props} />
</PageHeader>) : <HeaderInfo {...props} />);
};
HeaderInfo.propTypes = DetailHeader.propTypes;

I am not sure if I didn't missaligned anything, better to try this locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course. I missed this caveat. I will adopt the suggestion

Comment on lines 27 to 31
useEffect(() => {
if (!entity || !(entity?.id === inventoryId) || !loaded) {
dispatch(loadEntity(inventoryId, { hasItems: true }, { showTags }));
}
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

What if app doesn't send inventoryId? Wouldn't this cause constant re-renders? Also, if entity is changed via selector no new re-calculation is not triggered

Suggested change
useEffect(() => {
if (!entity || !(entity?.id === inventoryId) || !loaded) {
dispatch(loadEntity(inventoryId, { hasItems: true }, { showTags }));
}
}, []);
useEffect(() => {
if (!entity || !(entity?.id === inventoryId) || !loaded) {
dispatch(loadEntity(inventoryId, { hasItems: true }, { showTags }));
}
}, [entity, inventoryId, loaded]);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am just thinking about why the entity would change on this page. But, maybe there is something that I am not aware of.

useEffect(() => {
chrome?.hideGlobalFilter?.(true);
chrome.appAction('system-detail');
clearNotifications();
const appName = searchParams.get('appName');
if (appName) {
dispatch(detailSelect(appName));
Copy link
Contributor

Choose a reason for hiding this comment

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

I remember removing this action caused incorrect tab activation. I guess the new refs deal with this, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, this is resolved by refs

history.push({
search
});
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

You should add at least to list of dependencies searchParams.

@mkholjuraev
Copy link
Contributor Author

@karelhala I have adopted all the necessary adjustments. Please have a look one more time

@mkholjuraev
Copy link
Contributor Author

@karelhala Hopefully, everything is as expected now. Here is the edge PR to align the app with this refactoring. Please run these apps to verify. The important thing is that with this PR, inventoryId prop will be used as a main factor to fetch host detail. Thus this prop is marked as required. This enables apps to independently render the header and the main section.

Copy link
Contributor

@karelhala karelhala left a comment

Choose a reason for hiding this comment

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

Looking good! Tested it locally and everything seems to be working!

@mkholjuraev mkholjuraev merged commit 11be618 into RedHatInsights:master Feb 22, 2023
gkarat pushed a commit that referenced this pull request Feb 22, 2023
## [1.3.1](v1.3.0...v1.3.1) (2023-02-22)

### Performance Improvements

* **RHIF-167:** get rid of activeApps in redux ([#1754](#1754)) ([11be618](11be618))
@gkarat
Copy link
Contributor

gkarat commented Feb 22, 2023

🎉 This PR is included in version 1.3.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants