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

Move $().setupVerticalNavigation(...) logic to React #6463

Merged
merged 21 commits into from Dec 5, 2019

Conversation

fhlavac
Copy link
Contributor

@fhlavac fhlavac commented Nov 28, 2019

Untitled 100

  • deleted $().setupVerticalNavigation(...) method from miq_application.js
  • moved vertical-navbar logic for levels expanding to React components
  • replaced left-section (collapsed state toggle + miq logo) with NavbarHeader React component
  • moved vertical-navbar collapsing logic to React
  • updated tests for vertical-nav collapsing using Redux
  • removed pinning from vertical-navbar and related styling

@epwinchell Do you see anything about removing the pinning what should be changed or fixed?

@martinpovolny @himdel @Hyperkid123

@Hyperkid123
Copy link
Contributor

@miq-bot assign @martinpovolny
@miq-bot add_label react
@miq-bot add_reviewer @Hyperkid123

Copy link
Contributor

@Hyperkid123 Hyperkid123 left a comment

Choose a reason for hiding this comment

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

I think the code works. Have some minor remarks for the styling. As always I am probably not aware of all the features the has. Somebody that is should probably double check if anything is missing. @skateman @himdel

'menu-list-group-item',
{
'tertiary-nav-item-pf': hasSubitems,
'is-hover': useContext(HoverContext).secondLevelId === id,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is usage of hooks is dangerous. 1st rule of rule of react hooks is that they have to defined at the top of the function to avoid potential state inconsistencies.

const Foo = () => {
  const { bar }  = useSomething() // same as const bar = useSomething().bar but it is preferred syntax.
  return (
  <div> ...
  )
}

Granted this is not the case for useContext but still, we should follow the rules not to confuse anyone who might use this as a inspiration in the future.

Choose a reason for hiding this comment

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

@fhlavac : can you move the useContext into a separate statement after/before line 20?

@Hyperkid123 : that is what you are asking for, 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.

moved :)

@@ -10,7 +11,10 @@ const ThirdLevel = ({
visible,
type,
}) => (!visible ? null : (
<li className={`menu-list-group-item ${active ? 'active' : ''}`} id={`menu_item_${id}`}>
<li
className={`menu-list-group-item ${active ? 'active' : ''}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

imported clsx but its not used for composite className

'menu-list-group-item',
'secondary-nav-item-pf',
{
'is-hover': useContext(HoverContext).topLevelId === id,
Copy link
Contributor

Choose a reason for hiding this comment

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

again hooks rules

dispatch(toggleVerticalMenuCollapsed());
const content = window.document.getElementsByClassName('container-pf-nav-pf-vertical-with-sub-menus')[0];
if (isVerticalMenuCollapsed) {
content.classList.remove('collapsed-nav');
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be nice to check if the content exists. I don't know if its possible for the content no to be present in the DOM but its a good practice to first check if the element really exists before trying to call any functions on it.


const MainMenu = ({ menu }) => {
const [activeIds, setActiveIds] = useState({});
const isVerticalMenuCollapsed = useSelector(store => store.menuReducer.isVerticalMenuCollapsed);
Copy link
Contributor

Choose a reason for hiding this comment

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

I would refer if you use object destructing for the property:

const isVerticalMenuCollapsed = useSelector(({ menuReducer: { isVerticalMenuCollapsed }})  => isVerticalMenuCollapsed);

package.json Outdated
@@ -43,6 +43,7 @@
"bootstrap-filestyle": "~1.2.1",
"bootstrap-switch": "3.3.4",
"classnames": "~2.2.6",
"clsx": "^1.0.4",
Copy link
Member

Choose a reason for hiding this comment

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

Just one line above, we pull in the classnames package which does the same thing as clsx.

Copy link
Contributor

@himdel himdel Dec 2, 2019

Choose a reason for hiding this comment

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

in ui-classic, we only have one use of classnames, which should be trivial to change.

app/javascript/forms/miq-button.jsx
3:import ClassNames from 'classnames';
14:  const klass = ClassNames({

But, in v2v, there's 28 more uses of classnames.

So, I'd suggest just going with classnames, unless you want to update https://github.com/ManageIQ/manageiq-v2v too.

Copy link
Contributor

Choose a reason for hiding this comment

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

@fhlavac ok classnames it is. Can you please change it? The package has almost the same syntax as clsx. You can find it in the docs.

@Hyperkid123
Copy link
Contributor

@skateman oh did not noticed that. I don't even know if classnames were ever used. @fhlavac can you check if we use classnames? If we already use classnames just use that instead and remove clsx. If not i would just remove classnames. I do prefer clsx because its a bit more lightweight.

@skateman
Copy link
Member

skateman commented Dec 1, 2019

My point is to use one, doesn't matter which 😆

@epwinchell
Copy link
Contributor

@epwinchell Do you see anything about removing the pinning what should be changed or fixed?

@fhlavac Nope, it looks fine.

Copy link
Contributor

@epwinchell epwinchell left a comment

Choose a reason for hiding this comment

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

Tested. Looks fine. I do see a couple of issues with the menu in the mobile layout that are unrelated to this PR. We can address seperately.

@martinpovolny
Copy link

@fhlavac : there's just a few minor comments. We are almost there.

Thanks for the great work everyone!

@fhlavac fhlavac changed the title Move $().setupVerticalNavigation(...) logic to React [WIP] Move $().setupVerticalNavigation(...) logic to React Dec 4, 2019
@miq-bot miq-bot added the wip label Dec 4, 2019
@fhlavac fhlavac changed the title [WIP] Move $().setupVerticalNavigation(...) logic to React Move $().setupVerticalNavigation(...) logic to React Dec 4, 2019
@miq-bot miq-bot removed the wip label Dec 4, 2019
@@ -65,6 +66,7 @@ ManageIQ.component.addReact('ImportDatastoreViaGit', ImportDatastoreViaGit);
ManageIQ.component.addReact('MainMenu', MainMenu);
ManageIQ.component.addReact('MiqAboutModal', MiqAboutModal);
ManageIQ.component.addReact('MiqToolbar', MiqToolbar);
ManageIQ.component.addReact('NavbarHeader', NavbarHeader);
Copy link
Contributor

Choose a reason for hiding this comment

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

@fhlavac Can you use the navbar. convention here too? :)

@@ -0,0 +1 @@
= react('NavbarHeader', { :customBrand => ::Settings.server.custom_brand, :imagePath => image_path("layout/brand.svg") })
Copy link
Contributor

Choose a reason for hiding this comment

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

(and here)

@himdel
Copy link
Contributor

himdel commented Dec 4, 2019

The menu currently doesn't remember the collapsed state...

  1. click the kebab to make the menu small
  2. click the menu to go to some other screen
  3. the menu will load full-sized

It should remember and load in the collapsed state.

The original implementation is using localStorage['patternfly-navigation-primary'] = "collapsed" | "expanded", maybe you can reuse the same variable?

@Hyperkid123
Copy link
Contributor

The menu currently doesn't remember the collapsed state...

  1. click the kebab to make the menu small
  2. click the menu to go to some other screen
  3. the menu will load full-sized

It should remember and load in the collapsed state.

The original implementation is using localStorage['patternfly-navigation-primary'] = "collapsed" | "expanded", maybe you can reuse the same variable?

Yeah redux state is not persisted on full page refresh. So we will have to use local storage. We might want to think about persisting redux state to local storage further(somewhere else). But i don't know how i feel about that.

@himdel
Copy link
Contributor

himdel commented Dec 4, 2019

But i don't know how i feel about that.

I don't think it makes sense to persist the whole redux state, that sounds like it would always be caching more than it should.

IMO we should have explicit interfaces for specific things that should remain set after reload, this may be one of them.

@Hyperkid123
Copy link
Contributor

IMO we should have explicit interfaces for specific things that should remain set after reload, this may be one of them.

agreed

@miq-bot
Copy link
Member

miq-bot commented Dec 5, 2019

Checked commits fhlavac/manageiq-ui-classic@d794a15~...11c062d with ruby 2.5.5, rubocop 0.69.0, haml-lint 0.20.0, and yamllint 1.10.0
0 files checked, 0 offenses detected
Everything looks fine. ⭐

const content = window.document.getElementsByClassName('container-pf-nav-pf-vertical-with-sub-menus')[0];
if (content) {
if (isVerticalMenuCollapsed) {
content.classList.add('collapsed-nav');
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 a bit unfortunate we have to manipulate these classes manually, since this is a react component and the data is in state. Any way to use react here? :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, never mind, that particular element is in app/views/layouts/_content.html.haml and app/views/layouts/_center_div_*.html.haml, and is still outside of the react navbar.

So, this makes sense for now, no issues :)

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah you would have to have the whole layout as a react component. No way around it for now i am afraid

@himdel himdel added this to the Sprint 126 Ending Dec 9, 2019 milestone Dec 5, 2019
@himdel himdel merged commit 082a476 into ManageIQ:master Dec 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
React rewrite
  
Awaiting triage
Development

Successfully merging this pull request may close these issues.

None yet

7 participants