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

React header #6197

Merged
merged 34 commits into from
Dec 4, 2019
Merged

React header #6197

merged 34 commits into from
Dec 4, 2019

Conversation

fhlavac
Copy link
Contributor

@fhlavac fhlavac commented Sep 17, 2019

@Hyperkid123 @martinpovolny @epwinchell

  • Added parameter for element specification to ReactjsHelper
  • Rewritten help and user menu structure generating (similar as for vertical navbar - should be merged)
  • Rewritten top-navbar component and divided it into components: user-options, configuration, help, notifications, custom-logo
  • Created right-section component containing all above mentioned small components
  • Created top-navbar tests

This PR is dependent on #5854

top-navbar

In notifications part I currently call setUnreadCount (function returning number of unread notifications) by Redux. Previously, it was solved in Angular.
Currently: When number of unread notifications in drawer is updated, Rx message is sent to React header and Redux dispatch updates value stored in Redux store.

@fhlavac fhlavac changed the title React header [WIP] React header Sep 17, 2019
@miq-bot miq-bot added the wip label Sep 17, 2019
@epwinchell
Copy link
Contributor

@miq-bot add_reviewer @martinpovolny

@epwinchell
Copy link
Contributor

@miq-bot add_reviewer @epwinchell

@epwinchell
Copy link
Contributor

@miq-bot add_reviewer @Hyperkid123

@miq-bot miq-bot requested a review from Hyperkid123 September 17, 2019 18:13
@martinpovolny
Copy link
Member

Touches notifications, pinging @skateman .

Also the notifications should be converted to React as a priority.

This is a piece of Angular that is loaded on every page. Let's avoid that soon. Toolbars will be gone in a moment, then GTL will be replaced and trees. There should be no angular on most pages in the next release.

@skateman
Copy link
Member

@martinpovolny the pf-react implementation of the drawer is very far from our needs. We did some customizations with @himdel on top of the angular-based implementation and we would have to do that and a little more with the react one before we're able to actually consume it.

I was looking into this last year and it seemed like a painful task. But I'm in the area already because of the popup throttling, so I'll re-evaluate this as well.

Gonna take a look at this piece of code of course ... gimme some 🕐

Copy link
Member

@skateman skateman left a comment

Choose a reason for hiding this comment

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

Great job, a few problems and some stuff open for debate...

@@ -66,5 +66,4 @@ $login-container-details-border-color-rgba: rgba(0, 0, 0, 0.5);
body.login.whitelabel {
background: url($img-bg-login-whitelabel);
background-size: 100% auto;
}

}
Copy link
Member

Choose a reason for hiding this comment

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

Missing newline here...

:items => item.items.to_a.map(&method(:item_to_hash)),
:visible => item.visible?,
:link_params => item.link_params
}
Copy link
Member

Choose a reason for hiding this comment

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

You could implement this a little prettier:

%i[
  id
  name
  icon
  placement
  before
  type
  href
  parent_id
  feature
  rbac_feature
  defaults
  link_params
].each_with_object(:visible => item.visible?, :items => item.items.to_a.map(&method(:item_to_hash))) do |obj, key|
  obj[key] = item.try(key)
end

Except of visible and items all the fields map nicely to the keys...

Copy link
Member

Choose a reason for hiding this comment

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

10 points to Griffindor for the &method btw 🥇 😆

<Help helpMenu={helpMenu} />
{ currentUser && (
<React.Fragment>
<Configuration opsExplorerAllowed={opsExplorerAllowed} />
Copy link
Member

Choose a reason for hiding this comment

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

TBH I don't see a reason why to have this as a separate component in a separate file, this is way too small for that and you're creating much bigger ones here. I'd just extract it into a function, but don't take this seriously and ask someone who actually knows React 😉

Copy link
Contributor

Choose a reason for hiding this comment

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

This was actually by my command! ☠️

But it is better to make these component as small and independent as possible. It is much easier to find them, test them and fix them if need be.

Copy link
Member

Choose a reason for hiding this comment

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

Then IMO the other one(s) should be small(er) as well... It's just feels weird that you have one small, and the rest is HUGE.

customLogo, currentUser, helpMenu, opsExplorerAllowed, applianceName, miqGroups, currentGroup, userMenu,
}) => (
<React.Fragment>
<CustomLogo customLogo={customLogo} />
Copy link
Member

Choose a reason for hiding this comment

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

Same as below...

@@ -47,6 +53,7 @@ angular.module('ManageIQ').controller('headerController', ['$scope', 'eventNotif

vm.notificationsIndicatorTooltip = miqFormatNotification(__('%{count} unread notifications'),
{count: notificationCount});
ManageIQ.redux.store.dispatch({ type: '@@notifications/setUnreadCount', payload: notificationCount.text });
Copy link
Member

Choose a reason for hiding this comment

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

Could you please write a few words into the PR's description about this idea. I know how it works because I made it up 😆 but others might not...

@@ -91,6 +91,11 @@ angular.module('ManageIQ').service('eventNotifications', ['$timeout', '$window',
});

updateUnreadCount(events);
var x = 0;
_.forEach(state.groups, function(group) {
Copy link
Member

Choose a reason for hiding this comment

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

I think you don't need the _ here, you can directly call forEach on the array. Anyway, this code is a great example for using reduce on the array instead of having the helper variable.

@@ -1,5 +1,33 @@
module ApplicationHelper
module Navbar
def menu_to_json(position)
Copy link
Member

Choose a reason for hiding this comment

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

For now, it's okay to have this method here, but after this is done, we should extract it into the Menu::Manager. I have an idea about that, just let's not forget it so we need to talk when this is done and we're both in the office.

@@ -0,0 +1 @@
= react('RightSection', { :customLogo => ::Settings.server.custom_logo, :currentUser => current_user, :helpMenu => menu_to_json(:help),:opsExplorerAllowed => ApplicationHelper.role_allows?(:feature => 'ops_explorer', :any => true), :applianceName => appliance_name, :miqGroups => current_user.miq_groups, :currentGroup => current_group, :userMenu => menu_to_json(:top_right) }, {:class => "nav navbar-nav navbar-right navbar-iconic"}, 'ul')
Copy link
Member

Choose a reason for hiding this comment

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

Missing newline

Copy link
Member

Choose a reason for hiding this comment

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

Maybe it's completely wrong and maybe out of the context of this PR, but could we preseed these data into the Redux store upon login? Then we would have them cached and the list of props would be simpler/shorter/nicer...

unreadCount: 0,
};

const nPrefix = '@@notifications/';
Copy link
Member

Choose a reason for hiding this comment

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

It's just a semantic nitpick and others might disagree with me, but I'd prefer singular here. Just to be a little more future-prooof. Also the setUnreadCount is a little too specific and there's a 100% chance it will be dropped in the future in favor of something like new. So I'd just go with @@notification/new instead, but this is also something where others might and should stop me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Honestly i don't really care about this :D As long as its same everywhere I am ok with both.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, in this case let's go with singular please.

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 good.

@@ -91,6 +91,8 @@ angular.module('ManageIQ').service('eventNotifications', ['$timeout', '$window',
});

updateUnreadCount(events);
const totalUnreadCount = state.groups.reduce((sum, group) => (sum + group.unreadCount), 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think that we can use Array.prototype.reduce in old JS. This is not ES6 and its not being compiled by webpack.

Copy link
Contributor

Choose a reason for hiding this comment

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

es6-shim. We can use any ES6 libary feature just fine, only the syntax ones have to go through babel.

Copy link
Contributor

Choose a reason for hiding this comment

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

@fhlavac this is the one ^.. reduce is fine, but arrow functions are new syntax

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, and also const! :)

@@ -0,0 +1,19 @@
import React from 'react';

const Configuration = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see any prop types validation here.

import React from 'react';
import { Dropdown, Icon, MenuItem } from 'patternfly-react';

const Help = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing prop types again.

import React from 'react';
import { Dropdown, Icon, MenuItem } from 'patternfly-react';

const UserOptions = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

PropTypes

@@ -70,6 +76,12 @@ ManageIQ.component.addReact('TagGroup', props => <TagGroup {...props} />);
ManageIQ.component.addReact('TagView', TagView);
ManageIQ.component.addReact('TaggingWrapperConnected', TaggingWrapperConnected);
ManageIQ.component.addReact('TextualSummaryWrapper', TextualSummaryWrapper);
ManageIQ.component.addReact('RightSection', RightSection);
Copy link
Contributor

Choose a reason for hiding this comment

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

These should be sorted alphabetically by the component name. It helps us to avoid constant PR conflicts when registering new react components.

@fhlavac fhlavac changed the title [WIP] React header React header Oct 2, 2019
@himdel himdel mentioned this pull request Oct 3, 2019
@martinpovolny
Copy link
Member

Looks good!

Please, do not forget to move menu_to_json.
I think it's ok to have small and big components either in one or in multiple files. It really does not bother me for small React components.

Thx, @fhlavac, @Hyperkid123, @skateman !

id={group.description}
key={group.id}
title={__('Change to this Group')}
onClick={(e) => { e.preventDefault(); miqSparkleOn(); miqToggleUserOptions(group.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 will need a change once #6325 gets merged.

e.preventDefault(); miqChangeGroup(group.id); should do it, just make sure the id is a string please ;)

<MenuItem
id="logout-btn"
href="/dashboard/logout"
onClick={event => !miqCheckForChanges() && event.preventDefault()}
Copy link
Contributor

@himdel himdel Oct 22, 2019

Choose a reason for hiding this comment

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

And this also needs updating - this time for #6065 (merged in August)

I suggest

(e) => miqCheckForChanges() ? (ManageIQ.logoutInProgress = true) : e.preventDefault()

(Maybe you should go through the git log of all the files removed here and check for recent changes just to make sure ;).)

@miq-bot
Copy link
Member

miq-bot commented Dec 4, 2019

Checked commits fhlavac/manageiq-ui-classic@40c71fa~...0ca1e44 with ruby 2.5.5, rubocop 0.69.0, haml-lint 0.20.0, and yamllint 1.10.0
5 files checked, 0 offenses detected
Everything looks fine. 🍰

@martinpovolny
Copy link
Member

Restarted travis to recover from unrelated failures.

@himdel
Copy link
Contributor

himdel commented Dec 4, 2019

LGTM, tested vertical menu still working, group switcher, the usual buttons .. everything looks fine 👍

@himdel himdel merged commit 49c2416 into ManageIQ:master Dec 4, 2019
@himdel himdel added this to the Sprint 126 Ending Dec 9, 2019 milestone Dec 4, 2019
@skateman
Copy link
Member

skateman commented Dec 4, 2019

🎉

@Hyperkid123
Copy link
Contributor

Hyperkid123 commented Dec 4, 2019

@fhlavac good job. Now to the next bit 😄

@martinpovolny
Copy link
Member

❤️ 😍 💟 👍

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

Successfully merging this pull request may close these issues.

7 participants