diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-12-11 17:59:17 +0100 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-01-02 10:38:10 +0100 |
commit | 0d3c531f4a6ef72a1f0982808543273760ea05ba (patch) | |
tree | d7a1ce57ace32f1613b639b4392c2849886eae8e | |
parent | d04588cdf547d0e8f9290ad1cf1fa3fb0ecf6371 (diff) | |
download | sonarqube-0d3c531f4a6ef72a1f0982808543273760ea05ba.tar.gz sonarqube-0d3c531f4a6ef72a1f0982808543273760ea05ba.zip |
SONAR-10186 Switch between organizations from the header
19 files changed, 1172 insertions, 759 deletions
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.css b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.css new file mode 100644 index 00000000000..f61bbd33bd2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.css @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +.organization-switch { + display: inline-block; +} + +.organization-switch .dropdown-toggle { + display: block; + height: calc(4 * var(--gridSize)); + line-height: calc(4 * var(--gridSize) - 2px); + padding: 0 var(--gridSize); + border: 1px solid transparent; + border-radius: 2px; + box-sizing: border-box; + color: var(--baseFontColor) !important; + transition: all 0.3s ease; +} + +.organization-switch .dropdown-toggle:hover, +.organization-switch.open .dropdown-toggle { + border-color: var(--barBorderColor); + background-color: #fff; + box-shadow: var(--defaultShadow); +} + +.organization-switch.open .dropdown-toggle { + border-bottom-color: transparent; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.organization-switch .dropdown-menu { + min-width: 100%; + margin-left: -1px; +} + +.organization-switch .dropdown-menu > li > a { + padding-left: var(--gridSize); + padding-right: var(--gridSize); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx index 4cffcc47d80..b57d9840517 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx @@ -18,222 +18,25 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as classNames from 'classnames'; -import { Link } from 'react-router'; +import OrganizationNavigationHeaderContainer from './OrganizationNavigationHeaderContainer'; +import OrganizationNavigationMeta from './OrganizationNavigationMeta'; +import OrganizationNavigationMenu from './OrganizationNavigationMenu'; import * as theme from '../../../app/theme'; -import { translate } from '../../../helpers/l10n'; import ContextNavBar from '../../../components/nav/ContextNavBar'; -import NavBarTabs from '../../../components/nav/NavBarTabs'; -import OrganizationAvatar from '../../../components/common/OrganizationAvatar'; -import { getQualityGatesUrl } from '../../../helpers/urls'; -import { Extension, Organization } from '../../../app/types'; - -const ADMIN_PATHS = [ - 'edit', - 'groups', - 'delete', - 'permissions', - 'permission_templates', - 'projects_management' -]; +import { Organization } from '../../../app/types'; +import './OrganizationNavigation.css'; interface Props { location: { pathname: string }; organization: Organization; } -export default class OrganizationNavigation extends React.PureComponent<Props> { - renderAdministration(adminActive: boolean) { - const { organization } = this.props; - - return ( - <li className="dropdown"> - <a - className={classNames('dropdown-toggle', { active: adminActive })} - data-toggle="dropdown" - id="organization-navigation-admin" - href="#"> - {translate('layout.settings')} <i className="icon-dropdown" /> - </a> - <ul className="dropdown-menu"> - {this.renderAdminExtensions()} - <li> - <Link to={`/organizations/${organization.key}/groups`} activeClassName="active"> - {translate('user_groups.page')} - </Link> - </li> - <li> - <Link to={`/organizations/${organization.key}/permissions`} activeClassName="active"> - {translate('permissions.page')} - </Link> - </li> - <li> - <Link - to={`/organizations/${organization.key}/permission_templates`} - activeClassName="active"> - {translate('permission_templates')} - </Link> - </li> - <li> - <Link - to={`/organizations/${organization.key}/projects_management`} - activeClassName="active"> - {translate('projects_management')} - </Link> - </li> - <li> - <Link to={`/organizations/${organization.key}/edit`} activeClassName="active"> - {translate('edit')} - </Link> - </li> - {organization.canDelete && ( - <li> - <Link to={`/organizations/${organization.key}/delete`} activeClassName="active"> - {translate('delete')} - </Link> - </li> - )} - </ul> - </li> - ); - } - - renderAdminExtensions() { - const extensions = this.props.organization.adminPages || []; - return extensions.map(this.renderExtension); - } - - renderExtension = (extension: Extension) => { - const { organization } = this.props; - const pathname = `/organizations/${organization.key}/extension/${extension.key}`; - return ( - <li key={extension.key}> - <Link to={pathname} activeClassName="active"> - {extension.name} - </Link> - </li> - ); - }; - - renderExtensions(moreActive: boolean) { - const extensions = this.props.organization.pages || []; - if (extensions.length > 0) { - return ( - <li className={moreActive ? 'active' : ''}> - <a - className="dropdown-toggle" - id="organization-navigation-more" - data-toggle="dropdown" - href="#"> - {translate('more')} <i className="icon-dropdown" /> - </a> - <ul className="dropdown-menu">{extensions.map(this.renderExtension)}</ul> - </li> - ); - } else { - return null; - } - } - - render() { - const { organization, location } = this.props; - - const isHomeActive = - location.pathname === `organizations/${organization.key}/projects` || - location.pathname === `organizations/${organization.key}/projects/favorite`; - - const adminPathsWithExtensions = (organization.adminPages || []) - .map(e => `extension/${e.key}`) - .concat(ADMIN_PATHS); - - const adminActive = adminPathsWithExtensions.some(path => - location.pathname.endsWith(`organizations/${organization.key}/${path}`) - ); - const moreActive = !adminActive && location.pathname.includes('/extension/'); - - return ( - <ContextNavBar id="context-navigation" height={theme.contextNavHeightRaw}> - <div className="navbar-context-header"> - <h1 className="display-inline-block"> - <OrganizationAvatar organization={organization} /> - <Link - to={`/organizations/${organization.key}`} - className="link-base-color link-no-underline spacer-left"> - {organization.name} - </Link> - </h1> - {organization.description != null && ( - <div className="navbar-context-description"> - <p className="text-limited text-top" title={organization.description}> - {organization.description} - </p> - </div> - )} - </div> - - <div className="navbar-context-meta"> - <div className="text-muted"> - <strong>{translate('organization.key')}:</strong> {organization.key} - </div> - {organization.url != null && ( - <div> - <p className="text-limited text-top"> - <a - className="link-underline" - href={organization.url} - title={organization.url} - rel="nofollow"> - {organization.url} - </a> - </p> - </div> - )} - </div> - - <NavBarTabs className="navbar-context-tabs"> - <li> - <Link - to={`/organizations/${organization.key}/projects`} - className={isHomeActive ? 'active' : ''}> - {translate('projects.page')} - </Link> - </li> - <li> - <Link - to={{ - pathname: `/organizations/${organization.key}/issues`, - query: { resolved: 'false' } - }} - activeClassName="active"> - {translate('issues.page')} - </Link> - </li> - <li> - <Link - to={`/organizations/${organization.key}/quality_profiles`} - activeClassName="active"> - {translate('quality_profiles.page')} - </Link> - </li> - <li> - <Link to={`/organizations/${organization.key}/rules`} activeClassName="active"> - {translate('coding_rules.page')} - </Link> - </li> - <li> - <Link to={getQualityGatesUrl(organization.key)} activeClassName="active"> - {translate('quality_gates.page')} - </Link> - </li> - <li> - <Link to={`/organizations/${organization.key}/members`} activeClassName="active"> - {translate('organization.members.page')} - </Link> - </li> - {this.renderExtensions(moreActive)} - {organization.canAdmin && this.renderAdministration(adminActive)} - </NavBarTabs> - </ContextNavBar> - ); - } +export default function OrganizationNavigation({ organization, location }: Props) { + return ( + <ContextNavBar id="context-navigation" height={theme.contextNavHeightRaw}> + <OrganizationNavigationHeaderContainer organization={organization} /> + <OrganizationNavigationMeta organization={organization} /> + <OrganizationNavigationMenu location={location} organization={organization} /> + </ContextNavBar> + ); } diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx new file mode 100644 index 00000000000..98d50b19d61 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx @@ -0,0 +1,112 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { Link } from 'react-router'; +import * as classNames from 'classnames'; +import { Organization } from '../../../app/types'; +import { translate } from '../../../helpers/l10n'; +import Dropdown from '../../../components/controls/Dropdown'; +import DropdownIcon from '../../../components/icons-components/DropdownIcon'; + +interface Props { + location: { pathname: string }; + organization: Organization; +} + +const ADMIN_PATHS = [ + 'edit', + 'groups', + 'delete', + 'permissions', + 'permission_templates', + 'projects_management' +]; + +export default function OrganizationNavigationAdministration({ location, organization }: Props) { + const extensions = organization.adminPages || []; + const adminPathsWithExtensions = extensions.map(e => `extension/${e.key}`).concat(ADMIN_PATHS); + const adminActive = adminPathsWithExtensions.some(path => + location.pathname.endsWith(`organizations/${organization.key}/${path}`) + ); + + return ( + <Dropdown> + {({ onToggleClick, open }) => ( + <li className={classNames('dropdown', { open })}> + <a + className={classNames('dropdown-toggle', { active: adminActive })} + id="organization-navigation-admin" + href="#" + onClick={onToggleClick}> + {translate('layout.settings')} + <DropdownIcon /> + </a> + <ul className="dropdown-menu"> + {extensions.map(extension => ( + <li key={extension.key}> + <Link + to={`/organizations/${organization.key}/extension/${extension.key}`} + activeClassName="active"> + {extension.name} + </Link> + </li> + ))} + <li> + <Link to={`/organizations/${organization.key}/groups`} activeClassName="active"> + {translate('user_groups.page')} + </Link> + </li> + <li> + <Link to={`/organizations/${organization.key}/permissions`} activeClassName="active"> + {translate('permissions.page')} + </Link> + </li> + <li> + <Link + to={`/organizations/${organization.key}/permission_templates`} + activeClassName="active"> + {translate('permission_templates')} + </Link> + </li> + <li> + <Link + to={`/organizations/${organization.key}/projects_management`} + activeClassName="active"> + {translate('projects_management')} + </Link> + </li> + <li> + <Link to={`/organizations/${organization.key}/edit`} activeClassName="active"> + {translate('edit')} + </Link> + </li> + {organization.canDelete && ( + <li> + <Link to={`/organizations/${organization.key}/delete`} activeClassName="active"> + {translate('delete')} + </Link> + </li> + )} + </ul> + </li> + )} + </Dropdown> + ); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx new file mode 100644 index 00000000000..097fcba9bc0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { Link } from 'react-router'; +import * as classNames from 'classnames'; +import { Organization } from '../../../app/types'; +import { translate } from '../../../helpers/l10n'; +import Dropdown from '../../../components/controls/Dropdown'; + +interface Props { + location: { pathname: string }; + organization: Organization; +} + +export default function OrganizationNavigationExtensions({ location, organization }: Props) { + const extensions = organization.pages || []; + if (extensions.length === 0) { + return null; + } + const active = extensions.some( + extension => + location.pathname === `/organizations/${organization.key}/extension/${extension.key}` + ); + + return ( + <Dropdown> + {({ onToggleClick, open }) => ( + <li className={classNames('dropdown', { open })}> + <a + className={classNames('dropdown-toggle', { active })} + id="organization-navigation-more" + href="#" + onClick={onToggleClick}> + {translate('more')} + <i className="icon-dropdown little-spacer-left" /> + </a> + + <ul className="dropdown-menu"> + {extensions.map(extension => ( + <li key={extension.key}> + <Link + to={`/organizations/${organization.key}/extension/${extension.key}`} + activeClassName="active"> + {extension.name} + </Link> + </li> + ))} + </ul> + </li> + )} + </Dropdown> + ); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx new file mode 100644 index 00000000000..afa4332544c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import * as classNames from 'classnames'; +import { sortBy } from 'lodash'; +import { Organization } from '../../../app/types'; +import OrganizationAvatar from '../../../components/common/OrganizationAvatar'; +import Dropdown from '../../../components/controls/Dropdown'; +import DropdownIcon from '../../../components/icons-components/DropdownIcon'; +import OrganizationLink from '../../../components/ui/OrganizationLink'; +import { translate } from '../../../helpers/l10n'; + +interface Props { + organization: Organization; + organizations: Organization[]; +} + +export default function OrganizationNavigationHeader({ organization, organizations }: Props) { + const other = organizations.filter(o => o.key !== organization.key); + + return ( + <div className="navbar-context-header"> + <h1 className="display-inline-block"> + <OrganizationAvatar organization={organization} /> + {other.length ? ( + <Dropdown> + {({ onToggleClick, open }) => ( + <div className={classNames('organization-switch', 'dropdown', { open })}> + <a className="dropdown-toggle" href="#" onClick={onToggleClick}> + {organization.name} + <DropdownIcon className="little-spacer-left" /> + </a> + <ul className="dropdown-menu"> + {sortBy(other, org => org.name.toLowerCase()).map(organization => ( + <li key={organization.key}> + <OrganizationLink className="dropdown-item-flex" organization={organization}> + <div> + <OrganizationAvatar organization={organization} small={true} /> + <span className="spacer-left">{organization.name}</span> + </div> + {organization.isAdmin && ( + <span className="outline-badge spacer-left">{translate('admin')}</span> + )} + </OrganizationLink> + </li> + ))} + </ul> + </div> + )} + </Dropdown> + ) : ( + <span className="spacer-left">{organization.name}</span> + )} + </h1> + {organization.description != null && ( + <div className="navbar-context-description"> + <p className="text-limited text-top" title={organization.description}> + {organization.description} + </p> + </div> + )} + </div> + ); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx new file mode 100644 index 00000000000..c94996e6a76 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeaderContainer.tsx @@ -0,0 +1,33 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { connect } from 'react-redux'; +import OrganizationNavigationHeader from './OrganizationNavigationHeader'; +import { Organization } from '../../../app/types'; +import { getMyOrganizations } from '../../../store/rootReducer'; + +interface StateProps { + organizations: Organization[]; +} + +const mapStateToProps = (state: any): StateProps => ({ + organizations: getMyOrganizations(state) +}); + +export default connect(mapStateToProps)(OrganizationNavigationHeader); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx new file mode 100644 index 00000000000..048c9f3b750 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx @@ -0,0 +1,78 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { Link } from 'react-router'; +import { Organization } from '../../../app/types'; +import NavBarTabs from '../../../components/nav/NavBarTabs'; +import { translate } from '../../../helpers/l10n'; +import { getQualityGatesUrl } from '../../../helpers/urls'; +import OrganizationNavigationExtensions from './OrganizationNavigationExtensions'; +import OrganizationNavigationAdministration from './OrganizationNavigationAdministration'; + +interface Props { + location: { pathname: string }; + organization: Organization; +} + +export default function OrganizationNavigationMenu({ location, organization }: Props) { + return ( + <NavBarTabs className="navbar-context-tabs"> + <li> + <Link to={`/organizations/${organization.key}/projects`} activeClassName="active"> + {translate('projects.page')} + </Link> + </li> + <li> + <Link + to={{ + pathname: `/organizations/${organization.key}/issues`, + query: { resolved: 'false' } + }} + activeClassName="active"> + {translate('issues.page')} + </Link> + </li> + <li> + <Link to={`/organizations/${organization.key}/quality_profiles`} activeClassName="active"> + {translate('quality_profiles.page')} + </Link> + </li> + <li> + <Link to={`/organizations/${organization.key}/rules`} activeClassName="active"> + {translate('coding_rules.page')} + </Link> + </li> + <li> + <Link to={getQualityGatesUrl(organization.key)} activeClassName="active"> + {translate('quality_gates.page')} + </Link> + </li> + <li> + <Link to={`/organizations/${organization.key}/members`} activeClassName="active"> + {translate('organization.members.page')} + </Link> + </li> + <OrganizationNavigationExtensions location={location} organization={organization} /> + {organization.canAdmin && ( + <OrganizationNavigationAdministration location={location} organization={organization} /> + )} + </NavBarTabs> + ); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx new file mode 100644 index 00000000000..b720223abe1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { Organization } from '../../../app/types'; +import { translate } from '../../../helpers/l10n'; + +interface Props { + organization: Organization; +} + +export default function OrganizationNavigationMeta({ organization }: Props) { + return ( + <div className="navbar-context-meta"> + <div className="text-muted"> + <strong>{translate('organization.key')}:</strong> {organization.key} + </div> + {organization.url != null && ( + <div> + <p className="text-limited text-top"> + <a + className="link-underline" + href={organization.url} + title={organization.url} + rel="nofollow"> + {organization.url} + </a> + </p> + </div> + )} + </div> + ); +} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx index e4884f83545..41fea385334 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx @@ -22,40 +22,17 @@ import { shallow } from 'enzyme'; import OrganizationNavigation from '../OrganizationNavigation'; import { Visibility } from '../../../../app/types'; -jest.mock('../../../issues/utils', () => ({ - isMySet: () => false -})); - -const organization = { - key: 'foo', - name: 'Foo', - canAdmin: false, - canDelete: false, - projectVisibility: Visibility.Public -}; - -it('regular user', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -it('admin', () => { +it('render', () => { expect( - getWrapper({ organization: { ...organization, canAdmin: true, canDelete: true } }) + shallow( + <OrganizationNavigation + location={{ pathname: '/organizations/foo' }} + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + /> + ) ).toMatchSnapshot(); }); - -it('undeletable org', () => { - expect( - getWrapper({ organization: { ...organization, canAdmin: true, canDelete: false } }) - ).toMatchSnapshot(); -}); - -function getWrapper(props = {}) { - return shallow( - <OrganizationNavigation - location={{ pathname: '/organizations/foo' }} - organization={organization} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx new file mode 100644 index 00000000000..4bebf6b977e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import OrganizationNavigationAdministration from '../OrganizationNavigationAdministration'; +import { Visibility } from '../../../../app/types'; + +it('renders', () => { + const wrapper = shallow( + <OrganizationNavigationAdministration + location={{ pathname: '' }} + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + /> + ); + expect(wrapper.find('Dropdown').dive()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx new file mode 100644 index 00000000000..bb9bd18b521 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import OrganizationNavigationHeader from '../OrganizationNavigationHeader'; +import { Visibility } from '../../../../app/types'; + +it('renders', () => { + expect( + shallow( + <OrganizationNavigationHeader + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + organizations={[]} + /> + ) + ).toMatchSnapshot(); +}); + +it('renders dropdown', () => { + const organizations = [ + { isAdmin: true, key: 'org1', name: 'org1', projectVisibility: Visibility.Public }, + { isAdmin: false, key: 'org2', name: 'org2', projectVisibility: Visibility.Public } + ]; + const wrapper = shallow( + <OrganizationNavigationHeader + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + organizations={organizations} + /> + ); + expect(wrapper.find('Dropdown').dive()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx new file mode 100644 index 00000000000..a5b266bcc2a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import OrganizationNavigationMenu from '../OrganizationNavigationMenu'; +import { Visibility } from '../../../../app/types'; + +it('renders', () => { + expect( + shallow( + <OrganizationNavigationMenu + location={{ pathname: '' }} + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + /> + ) + ).toMatchSnapshot(); +}); + +it('renders for admin', () => { + expect( + shallow( + <OrganizationNavigationMenu + location={{ pathname: '' }} + organization={{ + canAdmin: true, + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + /> + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx new file mode 100644 index 00000000000..5b69f2c4853 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import OrganizationNavigationMeta from '../OrganizationNavigationMeta'; +import { Visibility } from '../../../../app/types'; + +it('renders', () => { + expect( + shallow( + <OrganizationNavigationMeta + organization={{ + key: 'foo', + name: 'Foo', + projectVisibility: Visibility.Public + }} + /> + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap index b9efc8fe2e3..eb04cc431fe 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap @@ -1,523 +1,41 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`admin 1`] = ` +exports[`render 1`] = ` <ContextNavBar height={72} id="context-navigation" > - <div - className="navbar-context-header" - > - <h1 - className="display-inline-block" - > - <OrganizationAvatar - organization={ - Object { - "canAdmin": true, - "canDelete": true, - "key": "foo", - "name": "Foo", - "projectVisibility": "public", - } - } - /> - <Link - className="link-base-color link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo" - > - Foo - </Link> - </h1> - </div> - <div - className="navbar-context-meta" - > - <div - className="text-muted" - > - <strong> - organization.key - : - </strong> - - foo - </div> - </div> - <NavBarTabs - className="navbar-context-tabs" - > - <li> - <Link - className="" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/projects" - > - projects.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/issues", - "query": Object { - "resolved": "false", - }, - } - } - > - issues.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/quality_profiles" - > - quality_profiles.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/rules" - > - coding_rules.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/quality_gates", - } - } - > - quality_gates.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/members" - > - organization.members.page - </Link> - </li> - <li - className="dropdown" - > - <a - className="dropdown-toggle" - data-toggle="dropdown" - href="#" - id="organization-navigation-admin" - > - layout.settings - - <i - className="icon-dropdown" - /> - </a> - <ul - className="dropdown-menu" - > - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/groups" - > - user_groups.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/permissions" - > - permissions.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/permission_templates" - > - permission_templates - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/projects_management" - > - projects_management - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/edit" - > - edit - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/delete" - > - delete - </Link> - </li> - </ul> - </li> - </NavBarTabs> -</ContextNavBar> -`; - -exports[`regular user 1`] = ` -<ContextNavBar - height={72} - id="context-navigation" -> - <div - className="navbar-context-header" - > - <h1 - className="display-inline-block" - > - <OrganizationAvatar - organization={ - Object { - "canAdmin": false, - "canDelete": false, - "key": "foo", - "name": "Foo", - "projectVisibility": "public", - } - } - /> - <Link - className="link-base-color link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo" - > - Foo - </Link> - </h1> - </div> - <div - className="navbar-context-meta" - > - <div - className="text-muted" - > - <strong> - organization.key - : - </strong> - - foo - </div> - </div> - <NavBarTabs - className="navbar-context-tabs" - > - <li> - <Link - className="" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/projects" - > - projects.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/issues", - "query": Object { - "resolved": "false", - }, - } - } - > - issues.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/quality_profiles" - > - quality_profiles.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/rules" - > - coding_rules.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/quality_gates", - } - } - > - quality_gates.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/members" - > - organization.members.page - </Link> - </li> - </NavBarTabs> -</ContextNavBar> -`; - -exports[`undeletable org 1`] = ` -<ContextNavBar - height={72} - id="context-navigation" -> - <div - className="navbar-context-header" - > - <h1 - className="display-inline-block" - > - <OrganizationAvatar - organization={ - Object { - "canAdmin": true, - "canDelete": false, - "key": "foo", - "name": "Foo", - "projectVisibility": "public", - } - } - /> - <Link - className="link-base-color link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo" - > - Foo - </Link> - </h1> - </div> - <div - className="navbar-context-meta" - > - <div - className="text-muted" - > - <strong> - organization.key - : - </strong> - - foo - </div> - </div> - <NavBarTabs - className="navbar-context-tabs" - > - <li> - <Link - className="" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/projects" - > - projects.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/issues", - "query": Object { - "resolved": "false", - }, - } - } - > - issues.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/quality_profiles" - > - quality_profiles.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/rules" - > - coding_rules.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/organizations/foo/quality_gates", - } - } - > - quality_gates.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/members" - > - organization.members.page - </Link> - </li> - <li - className="dropdown" - > - <a - className="dropdown-toggle" - data-toggle="dropdown" - href="#" - id="organization-navigation-admin" - > - layout.settings - - <i - className="icon-dropdown" - /> - </a> - <ul - className="dropdown-menu" - > - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/groups" - > - user_groups.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/permissions" - > - permissions.page - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/permission_templates" - > - permission_templates - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/projects_management" - > - projects_management - </Link> - </li> - <li> - <Link - activeClassName="active" - onlyActiveOnIndex={false} - style={Object {}} - to="/organizations/foo/edit" - > - edit - </Link> - </li> - </ul> - </li> - </NavBarTabs> + <Connect(OrganizationNavigationHeader) + organization={ + Object { + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> + <OrganizationNavigationMeta + organization={ + Object { + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> + <OrganizationNavigationMenu + location={ + Object { + "pathname": "/organizations/foo", + } + } + organization={ + Object { + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> </ContextNavBar> `; diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap new file mode 100644 index 00000000000..61f766d7cf7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap @@ -0,0 +1,71 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<li + className="dropdown" +> + <a + className="dropdown-toggle" + href="#" + id="organization-navigation-admin" + onClick={[Function]} + > + layout.settings + <DropdownIcon /> + </a> + <ul + className="dropdown-menu" + > + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/groups" + > + user_groups.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/permissions" + > + permissions.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/permission_templates" + > + permission_templates + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/projects_management" + > + projects_management + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/edit" + > + edit + </Link> + </li> + </ul> +</li> +`; diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap new file mode 100644 index 00000000000..32683a0f5be --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap @@ -0,0 +1,120 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<div + className="navbar-context-header" +> + <h1 + className="display-inline-block" + > + <OrganizationAvatar + organization={ + Object { + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> + <span + className="spacer-left" + > + Foo + </span> + </h1> +</div> +`; + +exports[`renders dropdown 1`] = ` +<div + className="organization-switch dropdown" +> + <a + className="dropdown-toggle" + href="#" + onClick={[Function]} + > + Foo + <DropdownIcon + className="little-spacer-left" + /> + </a> + <ul + className="dropdown-menu" + > + <li + key="org1" + > + <OrganizationLink + className="dropdown-item-flex" + organization={ + Object { + "isAdmin": true, + "key": "org1", + "name": "org1", + "projectVisibility": "public", + } + } + > + <div> + <OrganizationAvatar + organization={ + Object { + "isAdmin": true, + "key": "org1", + "name": "org1", + "projectVisibility": "public", + } + } + small={true} + /> + <span + className="spacer-left" + > + org1 + </span> + </div> + <span + className="outline-badge spacer-left" + > + admin + </span> + </OrganizationLink> + </li> + <li + key="org2" + > + <OrganizationLink + className="dropdown-item-flex" + organization={ + Object { + "isAdmin": false, + "key": "org2", + "name": "org2", + "projectVisibility": "public", + } + } + > + <div> + <OrganizationAvatar + organization={ + Object { + "isAdmin": false, + "key": "org2", + "name": "org2", + "projectVisibility": "public", + } + } + small={true} + /> + <span + className="spacer-left" + > + org2 + </span> + </div> + </OrganizationLink> + </li> + </ul> +</div> +`; diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap new file mode 100644 index 00000000000..1177b7604b7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap @@ -0,0 +1,201 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<NavBarTabs + className="navbar-context-tabs" +> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/projects" + > + projects.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/organizations/foo/issues", + "query": Object { + "resolved": "false", + }, + } + } + > + issues.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/quality_profiles" + > + quality_profiles.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/rules" + > + coding_rules.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/organizations/foo/quality_gates", + } + } + > + quality_gates.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/members" + > + organization.members.page + </Link> + </li> + <OrganizationNavigationExtensions + location={ + Object { + "pathname": "", + } + } + organization={ + Object { + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> +</NavBarTabs> +`; + +exports[`renders for admin 1`] = ` +<NavBarTabs + className="navbar-context-tabs" +> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/projects" + > + projects.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/organizations/foo/issues", + "query": Object { + "resolved": "false", + }, + } + } + > + issues.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/quality_profiles" + > + quality_profiles.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/rules" + > + coding_rules.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/organizations/foo/quality_gates", + } + } + > + quality_gates.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to="/organizations/foo/members" + > + organization.members.page + </Link> + </li> + <OrganizationNavigationExtensions + location={ + Object { + "pathname": "", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> + <OrganizationNavigationAdministration + location={ + Object { + "pathname": "", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", + "projectVisibility": "public", + } + } + /> +</NavBarTabs> +`; diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap new file mode 100644 index 00000000000..3da71c25930 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +<div + className="navbar-context-meta" +> + <div + className="text-muted" + > + <strong> + organization.key + : + </strong> + + foo + </div> +</div> +`; diff --git a/server/sonar-web/src/main/js/components/icons-components/DropdownIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/DropdownIcon.tsx new file mode 100644 index 00000000000..20bc9629f31 --- /dev/null +++ b/server/sonar-web/src/main/js/components/icons-components/DropdownIcon.tsx @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { IconProps } from './types'; + +export default function DropdownIcon({ className, fill = 'currentColor', size = 16 }: IconProps) { + return ( + <svg + className={className} + width={size} + height={size} + viewBox="0 0 16 16" + version="1.1" + xmlnsXlink="http://www.w3.org/1999/xlink" + xmlSpace="preserve"> + <g transform="matrix(0.0273438,0,0,0.0273438,4.5,2.65625)"> + <path + style={{ fill }} + d="M256,176C256,180.333 254.417,184.083 251.25,187.25L139.25,299.25C136.083,302.417 132.333,304 128,304C123.667,304 119.917,302.417 116.75,299.25L4.75,187.25C1.583,184.083 0,180.333 0,176C0,171.667 1.583,167.917 4.75,164.75C7.917,161.583 11.667,160 16,160L240,160C244.333,160 248.083,161.583 251.25,164.75C254.417,167.917 256,171.667 256,176Z" + /> + </g> + </svg> + ); +} |