diff --git a/app/helpers/application_helper/navbar.rb b/app/helpers/application_helper/navbar.rb index 08892192732..b99e9daf4fb 100644 --- a/app/helpers/application_helper/navbar.rb +++ b/app/helpers/application_helper/navbar.rb @@ -11,7 +11,7 @@ def item_to_hash(item) :id => item.id.to_s, :title => item.name, :icon => item.icon, - :href => item.link_params[:href], + :href => item.href, :type => item.type, :visible => item.visible?, :active => item_active?(item), diff --git a/app/javascript/components/main-menu/helpers.js b/app/javascript/components/main-menu/helpers.js deleted file mode 100644 index 8aae44f65ef..00000000000 --- a/app/javascript/components/main-menu/helpers.js +++ /dev/null @@ -1,38 +0,0 @@ -export const getHrefByType = (type, href, id) => { - switch (type) { - case 'big_iframe': - return `/dashboard/iframe?id=${id}`; - case 'modal': - return undefined; - default: - return href; - } -}; - -export const getItemId = id => `menu_item_${id}`; - -export const getSectionId = id => `menu_section_${id}`; - -export const getIdByCategory = (isSection, id) => (isSection ? getSectionId(id) : getItemId(id)); - -export const handleUnsavedChanges = (type) => { - if (type === 'modal') { - return sendDataWithRx({ type: 'showAboutModal' }); - } - return window.miqCheckForChanges(); -}; - -export const saveVerticalMenuState = (isVerticalMenuCollapsed) => { - window.localStorage.setItem('patternfly-navigation-primary', isVerticalMenuCollapsed ? 'collapsed' : 'expanded'); -}; - -export const adaptContentWidth = (isVerticalMenuCollapsed) => { - const content = window.document.getElementsByClassName('container-pf-nav-pf-vertical-with-sub-menus')[0]; - if (content) { - if (isVerticalMenuCollapsed) { - content.classList.add('collapsed-nav'); - } else { - content.classList.remove('collapsed-nav'); - } - } -}; diff --git a/app/javascript/components/main-menu/main-menu.jsx b/app/javascript/components/main-menu/main-menu.jsx index 7d1afd3430a..c765e592bc4 100644 --- a/app/javascript/components/main-menu/main-menu.jsx +++ b/app/javascript/components/main-menu/main-menu.jsx @@ -8,7 +8,6 @@ import TopLevel from './top-level'; import SecondLevel from './second-level'; import ThirdLevel from './third-level'; import { menuProps, RecursiveMenuProps } from './recursive-props'; -import { adaptContentWidth } from './helpers'; const Fallback = props => ; @@ -26,7 +25,16 @@ const MainMenu = ({ menu }) => { const isVerticalMenuCollapsed = useSelector(({ menuReducer: { isVerticalMenuCollapsed } }) => isVerticalMenuCollapsed); useEffect(() => { - adaptContentWidth(isVerticalMenuCollapsed); + const content = document.querySelector('.container-pf-nav-pf-vertical-with-sub-menus'); + if (! content) { + return; + } + + if (isVerticalMenuCollapsed) { + content.classList.add('collapsed-nav'); + } else { + content.classList.remove('collapsed-nav'); + } }, [isVerticalMenuCollapsed]); const handleSetActiveIds = (value) => { diff --git a/app/javascript/components/main-menu/second-level.jsx b/app/javascript/components/main-menu/second-level.jsx index d2c51759231..fa49533dfe7 100644 --- a/app/javascript/components/main-menu/second-level.jsx +++ b/app/javascript/components/main-menu/second-level.jsx @@ -3,10 +3,7 @@ import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { MenuItem, HoverContext } from './main-menu'; import { menuProps } from './recursive-props'; -import { - getHrefByType, getIdByCategory, handleUnsavedChanges, -} from './helpers'; -import getTargetByType from '../../helpers/get-target-by-type'; +import { itemId, linkProps } from '../../menu/item-type'; const SecondLevel = ({ id, @@ -31,20 +28,11 @@ const SecondLevel = ({ active, }, )} - id={getIdByCategory(hasSubitems, id)} + id={itemId(id, hasSubitems)} onMouseEnter={() => (handleSetActiveIds(hasSubitems ? { secondLevelId: id } : undefined))} onMouseLeave={() => handleSetActiveIds({ secondLevelId: undefined })} > - { - if (handleUnsavedChanges(type) === false) { - event.preventDefault(); - } - return false; - }} - target={getTargetByType(type)} - > + {title}
diff --git a/app/javascript/components/main-menu/third-level.jsx b/app/javascript/components/main-menu/third-level.jsx index a35fba1f5b9..a8c4f339d97 100644 --- a/app/javascript/components/main-menu/third-level.jsx +++ b/app/javascript/components/main-menu/third-level.jsx @@ -1,8 +1,7 @@ import React from 'react'; import ClassNames from 'classnames'; import { menuProps } from './recursive-props'; -import { getHrefByType, handleUnsavedChanges } from './helpers'; -import getTargetByType from '../../helpers/get-target-by-type'; +import { itemId, linkProps } from '../../menu/item-type'; const ThirdLevel = ({ id, @@ -13,7 +12,7 @@ const ThirdLevel = ({ type, }) => (!visible ? null : (
  • - { - if (handleUnsavedChanges(type) === false) { - event.preventDefault(); - } - return false; - }} - target={getTargetByType(type)} - > + {title}
  • diff --git a/app/javascript/components/main-menu/top-level.jsx b/app/javascript/components/main-menu/top-level.jsx index 4401db7d9ac..4f0e1127796 100644 --- a/app/javascript/components/main-menu/top-level.jsx +++ b/app/javascript/components/main-menu/top-level.jsx @@ -3,10 +3,7 @@ import PropTypes from 'prop-types'; import ClassNames from 'classnames'; import { MenuItem, HoverContext } from './main-menu'; import { menuProps, RecursiveMenuProps } from './recursive-props'; -import { - getHrefByType, getSectionId, handleUnsavedChanges, getItemId, -} from './helpers'; -import getTargetByType from '../../helpers/get-target-by-type'; +import { itemId, linkProps } from '../../menu/item-type'; const TopLevel = ({ level, @@ -32,20 +29,13 @@ const TopLevel = ({ 'is-hover': hoveredTopLevelId === id, }, )} - id={getSectionId(id)} + id={itemId(id, isSection)} onMouseEnter={() => handleSetActiveIds({ topLevelId: id })} onBlur={() => undefined} > { - if (handleUnsavedChanges(type) === false) { - event.preventDefault(); - } - return false; - }} - target={getTargetByType(type)} + {...linkProps({ type, href, id })} > {title} @@ -68,7 +58,7 @@ const TopLevel = ({ return (
  • { - if (handleUnsavedChanges(type) === false) { - event.preventDefault(); - } - return false; - }} - target={getTargetByType(type)} + {...linkProps({ type, href, id })} > {title} diff --git a/app/javascript/components/top-navbar/help.jsx b/app/javascript/components/top-navbar/help.jsx index 00b8577eb98..b45bab78865 100644 --- a/app/javascript/components/top-navbar/help.jsx +++ b/app/javascript/components/top-navbar/help.jsx @@ -1,9 +1,8 @@ import React from 'react'; import { Dropdown, Icon, MenuItem } from 'patternfly-react'; import PropTypes from 'prop-types'; -import { showAboutModal } from './helpers'; import { helpMenuProps, recursiveHelpMenuProps } from './recursive-props'; -import getTargetByType from '../../helpers/get-target-by-type'; +import { linkProps } from '../../menu/item-type'; const Help = ({ helpMenu, @@ -47,9 +46,7 @@ const Help = ({ (item.type === 'modal' ? showAboutModal(e) : !miqCheckForChanges() && e.preventDefault())} - target={getTargetByType(item.type)} + {...linkProps(item)} > {item.title} diff --git a/app/javascript/components/top-navbar/helpers.js b/app/javascript/components/top-navbar/helpers.js deleted file mode 100644 index b28f9ec8ebd..00000000000 --- a/app/javascript/components/top-navbar/helpers.js +++ /dev/null @@ -1,4 +0,0 @@ -export const showAboutModal = (e) => { - e.preventDefault(); - return sendDataWithRx({ type: 'showAboutModal' }); -}; diff --git a/app/javascript/components/top-navbar/navbar-header.jsx b/app/javascript/components/top-navbar/navbar-header.jsx index 42ba02fdb56..9818e08e7dc 100644 --- a/app/javascript/components/top-navbar/navbar-header.jsx +++ b/app/javascript/components/top-navbar/navbar-header.jsx @@ -1,7 +1,6 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; -import { saveVerticalMenuState } from '../main-menu/helpers'; import { toggleVerticalMenuCollapsed } from '../../miq-redux/menu-reducer'; const NavbarHeader = ({ @@ -11,7 +10,7 @@ const NavbarHeader = ({ const dispatch = useDispatch(); const isVerticalMenuCollapsed = useSelector(({ menuReducer: { isVerticalMenuCollapsed } }) => isVerticalMenuCollapsed); useEffect(() => { - saveVerticalMenuState(isVerticalMenuCollapsed); + window.localStorage.setItem('patternfly-navigation-primary', isVerticalMenuCollapsed ? 'collapsed' : 'expanded'); }, [isVerticalMenuCollapsed]); return ( diff --git a/app/javascript/helpers/get-target-by-type.js b/app/javascript/helpers/get-target-by-type.js deleted file mode 100644 index ebe6fbc02b7..00000000000 --- a/app/javascript/helpers/get-target-by-type.js +++ /dev/null @@ -1,3 +0,0 @@ -const getTargetByType = type => (type === 'new_window' ? '_blank' : '_self'); - -export default getTargetByType; diff --git a/app/javascript/menu/item-type.js b/app/javascript/menu/item-type.js new file mode 100644 index 00000000000..25d0b8ee557 --- /dev/null +++ b/app/javascript/menu/item-type.js @@ -0,0 +1,35 @@ +// there are 4 menu item types (used both in navbar and menu) +// * default (href) - opens href +// * big_iframe (id) - no menu, only navbar and ..a big iframe (external with our header) +// * modal () - open the About Modal (extend for any modals) +// * new_window (href) - opens href in new window (for external links) + +export const linkProps = ({type, href, id}) => ({ + href: { + big_iframe: `/dashboard/iframe?id=${id}`, + default: href, + modal: undefined, + new_window: href, + }[type || 'default'], + + target: (type === 'new_window' ? '_blank' : '_self'), + + onClick: (event) => { + if (type === 'modal') { + sendDataWithRx({ type: 'showAboutModal' }); + event.preventDefault(); + return; + } + + if (['default', 'big_iframe'].includes(type) && miqCheckForChanges() === false) { + event.preventDefault(); + return; + } + + if (href === '/dashboard/logout') { + ManageIQ.logoutInProgress = true; + } + }, +}); + +export const itemId = (id, section) => (section ? `menu_section_${id}` : `menu_item_${id}`); diff --git a/app/javascript/spec/top-navbar/__snapshots__/top-navbar.spec.js.snap b/app/javascript/spec/top-navbar/__snapshots__/top-navbar.spec.js.snap index 5afb3ec1ee3..0aed93c86c3 100644 --- a/app/javascript/spec/top-navbar/__snapshots__/top-navbar.spec.js.snap +++ b/app/javascript/spec/top-navbar/__snapshots__/top-navbar.spec.js.snap @@ -325,7 +325,6 @@ exports[`Top navbar tests should render correctly 1`] = ` disabled={false} divider={false} header={false} - href="" id="help-menu-about" key=".$about" onClick={[Function]} @@ -339,7 +338,6 @@ exports[`Top navbar tests should render correctly 1`] = ` > "/dashboard/iframe?id=#{id}"} - when :new_window then {:href => href, :target => '_new'} - when :modal then {:onclick => "sendDataWithRx({type: 'showAboutModal'});", :href => 'javascript:void(0);'} - else {:href => href} - end - params[:onclick] = 'return miqCheckForChanges();' unless type.try(:to_sym) == :modal - params - end - def leaf? true end diff --git a/app/presenters/menu/section.rb b/app/presenters/menu/section.rb index a6788faf02a..3aa219979e3 100644 --- a/app/presenters/menu/section.rb +++ b/app/presenters/menu/section.rb @@ -44,12 +44,13 @@ def subsection? @subsection ||= Array(items).detect { |el| el.kind_of?(Section) } end - def link_params - params = case type - when :big_iframe then {:href => "/dashboard/iframe?sid=#{id}"} - else {:href => "/dashboard/maintab/?tab=#{id}"} - end - params.merge(:onclick => 'return miqCheckForChanges();') + def href + case type + when :big_iframe + "/dashboard/iframe?sid=#{id}" + else + "/dashboard/maintab/?tab=#{id}" + end end def leaf? @@ -75,7 +76,7 @@ def default_redirect_url items.each do |item| next unless item.visible? if item.kind_of?(Item) - return item.link_params[:href] + return item.href else section_result = item.default_redirect_url return section_result if section_result