diff --git a/superset-frontend/spec/javascripts/components/Menu_spec.jsx b/superset-frontend/spec/javascripts/components/Menu_spec.jsx index 4b152cec299cd..0ae1884958008 100644 --- a/superset-frontend/spec/javascripts/components/Menu_spec.jsx +++ b/superset-frontend/spec/javascripts/components/Menu_spec.jsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { shallow, mount } from 'enzyme'; -import { Nav } from 'react-bootstrap'; +import { Nav, NavDropdown, MenuItem } from 'react-bootstrap'; import { supersetTheme, ThemeProvider } from '@superset-ui/style'; import Menu from 'src/components/Menu/Menu'; @@ -26,19 +26,6 @@ import Menu from 'src/components/Menu/Menu'; const defaultProps = { data: { menu: [ - { - name: 'Security', - icon: 'fa-cogs', - label: 'Security', - childs: [ - { - name: 'List Users', - icon: 'fa-user', - label: 'List Users', - url: '/users/list/', - }, - ], - }, { name: 'Sources', icon: 'fa-table', @@ -100,6 +87,21 @@ const defaultProps = { user_login_url: '/login/', locale: 'en', }, + settings: [ + { + name: 'Security', + icon: 'fa-cogs', + label: 'Security', + childs: [ + { + name: 'List Users', + icon: 'fa-user', + label: 'List Users', + url: '/users/list/', + }, + ], + }, + ], }, }; @@ -164,4 +166,12 @@ describe('Menu', () => { expect(versionedWrapper.find('.version-info div')).toHaveLength(2); }); + + it('renders a NavDropdown (settings)', () => { + expect(wrapper.find(NavDropdown)).toHaveLength(1); + }); + + it('renders MenuItems in NavDropdown (settings)', () => { + expect(wrapper.find(NavDropdown).find(MenuItem)).toHaveLength(2); + }); }); diff --git a/superset-frontend/src/components/Menu/Menu.tsx b/superset-frontend/src/components/Menu/Menu.tsx index d22b64dd02f80..87f846f5e13b6 100644 --- a/superset-frontend/src/components/Menu/Menu.tsx +++ b/superset-frontend/src/components/Menu/Menu.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { t } from '@superset-ui/translation'; -import { Nav, Navbar, NavItem } from 'react-bootstrap'; +import { Nav, Navbar, NavDropdown, NavItem, MenuItem } from 'react-bootstrap'; import styled from '@superset-ui/style'; import MenuObject, { MenuObjectProps } from './MenuObject'; import NewMenu from './NewMenu'; @@ -51,6 +51,7 @@ export interface MenuProps { menu: MenuObjectProps[]; brand: BrandProps; navbar_right: NavBarProps; + settings: MenuObjectProps[]; }; } @@ -115,11 +116,44 @@ const StyledHeader = styled.header` margin: 0; } } + + .settings-divider { + margin-bottom: 8px; + border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; + } `; export default function Menu({ - data: { menu, brand, navbar_right: navbarRight }, + data: { menu, brand, navbar_right: navbarRight, settings }, }: MenuProps) { + // Flatten settings + const flatSettings: any[] = []; + + if (settings) { + settings.forEach((section: object, index: number) => { + const newSection: MenuObjectProps = { + ...section, + index, + isHeader: true, + }; + + flatSettings.push(newSection); + + // Filter out '-' + if (newSection.childs) { + newSection.childs.forEach((child: any) => { + if (child !== '-') { + flatSettings.push(child); + } + }); + } + + if (index !== settings.length - 1) { + flatSettings.push('-'); + } + }); + } + return ( @@ -138,6 +172,38 @@ export default function Menu({