From dccf95202c171899a045fd414f256e7ca22dadc2 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Wed, 19 Jul 2017 16:56:38 +0200 Subject: [PATCH] SONAR-9583 Use fixed width layout for navigation --- server/sonar-web/pom.xml | 2 +- .../main/js/app/components/GlobalContainer.js | 2 +- .../main/js/app/components/SimpleContainer.js | 7 +- .../components/nav/component/ComponentNav.css | 11 + .../components/nav/component/ComponentNav.js | 52 +- .../nav/component/ComponentNavBreadcrumbs.js | 10 +- .../nav/component/ComponentNavMenu.js | 13 +- .../ComponentNavBreadcrumbs-test.js.snap | 18 +- .../ComponentNavMenu-test.js.snap | 24 +- .../app/components/nav/global/GlobalNav.css | 67 +++ .../js/app/components/nav/global/GlobalNav.js | 48 +- .../nav/global/GlobalNavBranding.js | 8 +- .../components/nav/global/GlobalNavMenu.js | 4 +- .../components/nav/global/GlobalNavUser.js | 2 +- .../__snapshots__/GlobalNavMenu-test.js.snap | 6 +- .../__snapshots__/GlobalNavUser-test.js.snap | 2 + .../components/nav/settings/SettingsNav.js | 224 ++++--- .../__snapshots__/SettingsNav-test.js.snap | 368 ++++++------ .../main/js/app/components/search/Search.css | 97 +++ .../main/js/app/components/search/Search.js | 1 + .../src/main/js/app/utils/startReactApp.js | 5 +- .../main/js/apps/about/components/AboutApp.js | 102 ++-- .../components/AboutAppForSonarQubeDotCom.js | 4 +- .../AboutRulesForSonarQubeDotCom.js | 2 +- .../apps/about/sonarqube-dot-com-styles.css | 8 +- .../src/main/js/apps/about/styles.css | 10 - .../src/main/js/apps/account/account.css | 10 - .../main/js/apps/account/components/Nav.js | 7 +- .../js/apps/component-measures/styles.css | 25 + .../src/main/js/apps/issues/styles.css | 16 - .../navigation/OrganizationNavigation.js | 143 ++--- .../OrganizationNavigation-test.js.snap | 552 +++++++++--------- .../OrganizationIcon.js | 11 +- .../main/js/components/nav/ContextNavBar.css | 36 ++ .../main/js/components/nav/ContextNavBar.js | 33 ++ .../src/main/js/components/nav/NavBar.css | 24 + .../src/main/js/components/nav/NavBar.js | 41 ++ .../src/main/js/components/nav/NavBarTabs.css | 28 + .../src/main/js/components/nav/NavBarTabs.js | 36 ++ .../js/libs/third-party/bootstrap/dropdown.js | 2 +- .../src/main/less/components/navbar.less | 363 ------------ .../src/main/less/components/page.less | 16 +- .../less/components/search-navigator.less | 10 +- .../src/main/less/components/ui.less | 103 ---- server/sonar-web/src/main/less/print.less | 10 - server/sonar-web/src/main/less/sonar.less | 1 - server/sonar-web/src/main/less/variables.less | 22 +- .../pageobjects/organization/MembersPage.java | 2 +- .../ui/OrganizationUiExtensionsTest.java | 2 +- .../sonarqube/tests/ui/UiExtensionsTest.java | 3 +- 50 files changed, 1204 insertions(+), 1389 deletions(-) create mode 100644 server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css create mode 100644 server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css create mode 100644 server/sonar-web/src/main/js/app/components/search/Search.css rename server/sonar-web/src/main/js/components/{ui => icons-components}/OrganizationIcon.js (85%) create mode 100644 server/sonar-web/src/main/js/components/nav/ContextNavBar.css create mode 100644 server/sonar-web/src/main/js/components/nav/ContextNavBar.js create mode 100644 server/sonar-web/src/main/js/components/nav/NavBar.css create mode 100644 server/sonar-web/src/main/js/components/nav/NavBar.js create mode 100644 server/sonar-web/src/main/js/components/nav/NavBarTabs.css create mode 100644 server/sonar-web/src/main/js/components/nav/NavBarTabs.js delete mode 100644 server/sonar-web/src/main/less/components/navbar.less diff --git a/server/sonar-web/pom.xml b/server/sonar-web/pom.xml index 8ddd3bcd8d4..f3b2803ddfa 100644 --- a/server/sonar-web/pom.xml +++ b/server/sonar-web/pom.xml @@ -230,7 +230,7 @@ com.sonarsource sonarsource-branding - 1.3.0.304 + 1.3.0.307 war runtime diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.js b/server/sonar-web/src/main/js/app/components/GlobalContainer.js index 284cba8d436..68c4c0f7374 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.js +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.js @@ -28,7 +28,7 @@ export default function GlobalContainer(props: Object) { return (
-
+
diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.js b/server/sonar-web/src/main/js/app/components/SimpleContainer.js index 7d9396e7bf0..a2d22afea2d 100644 --- a/server/sonar-web/src/main/js/app/components/SimpleContainer.js +++ b/server/sonar-web/src/main/js/app/components/SimpleContainer.js @@ -20,6 +20,7 @@ // @flow import React from 'react'; import GlobalFooterContainer from './GlobalFooterContainer'; +import NavBar from '../../components/nav/NavBar'; type Props = { children?: React.Element<*> | Array>, @@ -46,10 +47,8 @@ export default class SimpleContainer extends React.PureComponent { render() { return (
-
- +
+
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css new file mode 100644 index 00000000000..22ec0d36ea1 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css @@ -0,0 +1,11 @@ +.navbar-context-favorite { + float: left; + padding: 7px 10px 0 0; +} + +.navbar-context-title-qualifier { + display: inline-block; + line-height: 16px; + padding-top: 5px; + box-sizing: border-box; +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js index 23b08126fa7..d9963b913ac 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js @@ -23,9 +23,11 @@ import ComponentNavBreadcrumbs from './ComponentNavBreadcrumbs'; import ComponentNavMeta from './ComponentNavMeta'; import ComponentNavMenu from './ComponentNavMenu'; import RecentHistory from '../../RecentHistory'; +import ContextNavBar from '../../../../components/nav/ContextNavBar'; import { TooltipsContainer } from '../../../../components/mixins/tooltips-mixin'; import { getTasksForComponent } from '../../../../api/ce'; import { STATUSES } from '../../../../apps/background-tasks/constants'; +import './ComponentNav.css'; export default class ComponentNav extends React.PureComponent { componentDidMount() { @@ -66,36 +68,32 @@ export default class ComponentNav extends React.PureComponent { render() { return ( - + + ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js index c719a568c70..c7f17f3a9cd 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js @@ -59,7 +59,7 @@ class ComponentNavBreadcrumbs extends React.PureComponent { + className="link-base-color link-no-underline"> {index === breadcrumbs.length - 1 ? {itemName} @@ -74,7 +74,7 @@ class ComponentNavBreadcrumbs extends React.PureComponent { }); return ( -

+

- + {organization.name} } {items} {component.visibility === 'private' && } -

+ ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js index 0903d35eaa9..c484fa2b50c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js @@ -19,6 +19,8 @@ */ import React from 'react'; import { Link } from 'react-router'; +import classNames from 'classnames'; +import NavBarTabs from '../../../../components/nav/NavBarTabs'; import { translate } from '../../../../helpers/l10n'; const SETTINGS_URLS = [ @@ -59,7 +61,7 @@ export default class ComponentNavMenu extends React.PureComponent { return (
  • - + {translate('overview.page')}
  • ); @@ -131,11 +133,10 @@ export default class ComponentNavMenu extends React.PureComponent { } const isSettingsActive = SETTINGS_URLS.some(url => window.location.href.indexOf(url) !== -1); - const className = 'dropdown' + (isSettingsActive ? ' active' : ''); return ( -
  • +
  • @@ -348,7 +349,7 @@ export default class ComponentNavMenu extends React.PureComponent { render() { return ( -
      + {this.renderDashboardLink()} {this.renderIssuesLink()} {this.renderComponentMeasuresLink()} @@ -356,7 +357,7 @@ export default class ComponentNavMenu extends React.PureComponent { {this.renderActivityLink()} {this.renderAdministration()} {this.renderExtensions()} -
    + ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap index 385012e7de0..1588ae83e8a 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should not render breadcrumbs with one element 1`] = ` -

    -

    + `; exports[`should render organization 1`] = ` -

    -

    + `; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.js.snap index 9b9a24ab6fe..1772a834780 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.js.snap @@ -1,9 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should work with extensions 1`] = ` -
  • - + `; exports[`should work with multiple extensions 1`] = ` - - + `; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css new file mode 100644 index 00000000000..bdb8e019611 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.css @@ -0,0 +1,67 @@ +.navbar-global, +.navbar-global .navbar-inner { + background-color: #262626; + z-index: 421; +} + +.navbar-brand { + display: block; + margin-left: -10px; + padding-left: 10px; + padding-right: 10px; + border: none; +} + +.navbar-brand:hover, +.navbar-brand:focus { + background-color: #000; +} + +.navbar-login { + margin-right: -10px; +} + +.navbar-avatar { + margin-right: -3px !important; + padding: 3px !important; +} + +.navbar-help { + line-height: 16px !important; + padding: 7px !important; +} + +.global-navbar-menu { + display: flex; + align-items: center; +} + +.global-navbar-menu > li > a { + display: block; + padding: 8px 10px; + line-height: 14px; + border: none; + color: #ccc; + font-size: 12px; + letter-spacing: 0.05em; + transition: none; +} + +.global-navbar-menu > li > a.active, +.global-navbar-menu > li > a:hover, +.global-navbar-menu > li > a:focus { + background-color: #4b9fd5; + color: #fff; +} + +.global-navbar-menu > li > a.is-admin.active, +.global-navbar-menu > li > a.is-admin:hover, +.global-navbar-menu > li > a.is-admin:focus { + background-color: #ed7d20; +} + +@media print { + .navbar-global { + display: none !important; + } +} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js index 5f6de29a8f7..5ad2c836f37 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js @@ -25,11 +25,13 @@ import GlobalNavMenu from './GlobalNavMenu'; import GlobalNavUserContainer from './GlobalNavUserContainer'; import Search from '../../search/Search'; import GlobalHelp from '../../help/GlobalHelp'; +import NavBar from '../../../../components/nav/NavBar'; import Tooltip from '../../../../components/controls/Tooltip'; import HelpIcon from '../../../../components/icons-components/HelpIcon'; import OnboardingModal from '../../../../apps/tutorials/onboarding/OnboardingModal'; import { getCurrentUser, getAppState, getSettingValue } from '../../../../store/rootReducer'; import { translate } from '../../../../helpers/l10n'; +import './GlobalNav.css'; type Props = { appState: { organizationsEnabled: boolean }, @@ -96,29 +98,27 @@ class GlobalNav extends React.PureComponent { render() { return ( - + ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js index d0bac2720ea..968a9d109eb 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js @@ -31,7 +31,7 @@ class GlobalNavBranding extends React.PureComponent { renderLogo() { const url = this.props.customLogoUrl || `${window.baseUrl}/images/logo.svg`; - const width = this.props.customLogoWidth || 100; + const width = this.props.customLogoUrl ? this.props.customLogoWidth || 100 : 83; const height = 30; const title = translate('layout.sonar.slogan'); return {title}; @@ -39,11 +39,9 @@ class GlobalNavBranding extends React.PureComponent { render() { const homeController = this.props.currentUser.isLoggedIn ? '/projects' : '/about'; - const homeLinkClassName = - 'navbar-brand' + (this.props.customLogoUrl ? ' navbar-brand-custom' : ''); return ( -
    - +
    + {this.renderLogo()}
    diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js index 5b99dd06c92..6535201176f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js @@ -111,7 +111,7 @@ export default class GlobalNavMenu extends React.PureComponent { } return (
  • - + {translate('layout.settings')}
  • @@ -152,7 +152,7 @@ export default class GlobalNavMenu extends React.PureComponent { const { organizationsEnabled } = this.props.appState; return ( -
      +
        {this.renderProjects()} {governanceInstalled && this.renderPortfolios()} {this.renderIssuesLink()} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js index d5d25ec79a6..830a351b05e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js @@ -168,7 +168,7 @@ export default class GlobalNavUser extends React.PureComponent { renderAnonymous() { return (
      • - + {translate('layout.login')}
      • diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap index bb21d44b23e..3315afa83e2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.js.snap @@ -2,7 +2,7 @@ exports[`should show administration menu if the user has the rights 1`] = `
        • @@ -322,6 +323,7 @@ exports[`should update the component correctly when the user changes to anonymou exports[`should update the component correctly when the user changes to anonymous 2`] = `
        • diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js index 88750547c4a..21540b25a99 100644 --- a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js @@ -21,6 +21,8 @@ import React from 'react'; import classNames from 'classnames'; import { IndexLink, Link } from 'react-router'; import { connect } from 'react-redux'; +import ContextNavBar from '../../../../components/nav/ContextNavBar'; +import NavBarTabs from '../../../../components/nav/NavBarTabs'; import { translate } from '../../../../helpers/l10n'; import { areThereCustomOrganizations } from '../../../../store/rootReducer'; @@ -64,135 +66,129 @@ class SettingsNav extends React.PureComponent { const isProjects = this.isProjectsActive(); const isSystem = this.isSystemActive(); - const securityClassName = classNames('dropdown', { active: isSecurity }); - const projectsClassName = classNames('dropdown', { active: isProjects }); - const systemClassName = classNames('dropdown', { active: isSystem }); - const configurationClassNames = classNames('dropdown', { + const securityClassName = classNames('dropdown-toggle', { active: isSecurity }); + const projectsClassName = classNames('dropdown-toggle', { active: isProjects }); + const systemClassName = classNames('dropdown-toggle', { active: isSystem }); + const configurationClassNames = classNames('dropdown-toggle', { active: !isSecurity && !isProjects && !isSystem }); return ( - +
        • + + ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.js.snap index 1efd658114f..7f285d4906c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsNav-test.js.snap @@ -1,223 +1,209 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should work with extensions 1`] = ` -
          + + + `; diff --git a/server/sonar-web/src/main/js/app/components/search/Search.css b/server/sonar-web/src/main/js/app/components/search/Search.css new file mode 100644 index 00000000000..f9297eabb83 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/search/Search.css @@ -0,0 +1,97 @@ +.navbar-search { + position: relative; + padding-right: 3px; +} + +.navbar-search-input { + vertical-align: middle; + width: 310px; + margin-top: 3px; + margin-bottom: 3px; + padding-left: 26px !important; +} + +.navbar-search-input-hint { + position: absolute; + top: 4px; + right: 30px; + line-height: 24px; + font-size: 12px; + color: #777; +} +.navbar-search-input-hint.is-shifted { + z-index: 7501; + top: 32px; +} + +.navbar-search-icon { + position: relative; + vertical-align: middle; + width: 16px; + margin-right: -20px; + color: #777; +} + +.navbar-search-icon:before { + font-size: 14px; +} + +.navbar-search-item-link { + display: flex !important; +} + +.navbar-search-item-match { + flex-grow: 5; + overflow: hidden; + text-overflow: ellipsis; +} + +.navbar-search-item-right { + flex-grow: 1; + padding-left: 10px; + text-align: right; +} + +.navbar-search-item-icons { + position: relative; + flex-shrink: 0; + width: 16px; + height: 16px; +} +.navbar-search-item-icons > * { + position: absolute; + z-index: 5; + top: 0; + left: 0; +} + +.navbar-search-item-icons > .icon-star, +.navbar-search-item-icons > .icon-clock { + z-index: 6; + top: -4px; + left: -5px; +} + +.navbar-search-shortcut-hint { + line-height: 16px; + margin-top: 5px; + padding: 5px 10px; + border-top: 1px solid #e6e6e6; + background-color: #f3f3f3; + color: #777; + font-size: 11px; +} + +.navbar-search-no-results { + margin-top: 4px; + padding: 5px 10px; +} + +.global-navbar-search-dropdown { + max-height: 80vh; + width: 440px; + padding: 0; + overflow-y: auto; + overflow-x: hidden; + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} diff --git a/server/sonar-web/src/main/js/app/components/search/Search.js b/server/sonar-web/src/main/js/app/components/search/Search.js index 04098668141..808614922d1 100644 --- a/server/sonar-web/src/main/js/app/components/search/Search.js +++ b/server/sonar-web/src/main/js/app/components/search/Search.js @@ -33,6 +33,7 @@ import { getSuggestions } from '../../../api/components'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { scrollToElement } from '../../../helpers/scrolling'; import { getProjectUrl } from '../../../helpers/urls'; +import './Search.css'; type Props = {| appState: { organizationsEnabled: boolean }, diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.js b/server/sonar-web/src/main/js/app/utils/startReactApp.js index 18f4ba69ed7..41779d0b4ab 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.js +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.js @@ -29,7 +29,6 @@ import GlobalContainer from '../components/GlobalContainer'; import SimpleContainer from '../components/SimpleContainer'; import SimpleSessionsContainer from '../../apps/sessions/components/SimpleSessionsContainer'; import Landing from '../components/Landing'; -import ProjectContainer from '../components/ProjectContainer'; import ProjectAdminContainer from '../components/ProjectAdminContainer'; import ProjectPageExtension from '../components/extensions/ProjectPageExtension'; import ProjectAdminPageExtension from '../components/extensions/ProjectAdminPageExtension'; @@ -165,7 +164,9 @@ const startReactApp = () => { - + + import('../components/ProjectContainer').then(i => i.default)}> diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js index f22509ca1d5..715543e99a4 100644 --- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js +++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js @@ -132,67 +132,65 @@ class AboutApp extends React.PureComponent { } return ( -
          -
          -
          -
          -

          - {translate('layout.sonar.slogan')} -

          - {!this.props.currentUser.isLoggedIn && - - {translate('layout.login')} - } - - {translate('about_page.read_documentation')} - -
          - -
          - - -
          +
          +
          +
          +

          + {translate('layout.sonar.slogan')} +

          + {!this.props.currentUser.isLoggedIn && + + {translate('layout.login')} + } + + {translate('about_page.read_documentation')} +
          - {customText != null && - customText.value && -
          } +
          + + +
          +
          - + {customText != null && + customText.value && +
          } - + -
          -
          - -
          -
          - -
          -
          + -
          -
          - -
          -
          - -
          +
          +
          + +
          +
          +
          +
          - +
          +
          + +
          +
          + +
          + +
          ); } diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js b/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js index 2e9eee74ed4..80041d540bb 100644 --- a/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js +++ b/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js @@ -51,7 +51,7 @@ export default function AboutAppForSonarQubeDotCom(props: Props) { return (
          -
          +

          Continuous Code Quality
          as a Service @@ -73,7 +73,7 @@ export default function AboutAppForSonarQubeDotCom(props: Props) { -
          +
          {customText != null && customText.value &&
          -
          +
          +3,000 rules diff --git a/server/sonar-web/src/main/js/apps/about/sonarqube-dot-com-styles.css b/server/sonar-web/src/main/js/apps/about/sonarqube-dot-com-styles.css index dc5a19e0559..88db615075e 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarqube-dot-com-styles.css +++ b/server/sonar-web/src/main/js/apps/about/sonarqube-dot-com-styles.css @@ -16,10 +16,12 @@ color: #4b9fd5; } -.sqcom-about-page-entry .about-page-container { +.sqcom-about-page-entry .page-limited { display: flex; justify-content: space-between; align-items: center; + padding-top: 0; + padding-bottom: 0; } .sqcom-about-page-intro { @@ -89,10 +91,12 @@ background-color: #4193c8; } -.sqcom-about-rules .about-page-container { +.sqcom-about-rules .page-limited { display: flex; justify-content: space-between; align-items: center; + padding-top: 0; + padding-bottom: 0; } .sqcom-about-rules .button { diff --git a/server/sonar-web/src/main/js/apps/about/styles.css b/server/sonar-web/src/main/js/apps/about/styles.css index 46a0e9added..a81e5434c6f 100644 --- a/server/sonar-web/src/main/js/apps/about/styles.css +++ b/server/sonar-web/src/main/js/apps/about/styles.css @@ -22,16 +22,6 @@ padding-bottom: 25px; } -.about-page-container { - position: relative; - width: 1080px; - margin-left: auto; - margin-right: auto; - padding-left: 20px; - padding-right: 20px; - box-sizing: border-box; -} - .about-page-entry { display: flex; justify-content: space-between; diff --git a/server/sonar-web/src/main/js/apps/account/account.css b/server/sonar-web/src/main/js/apps/account/account.css index 10410996517..6050ad05929 100644 --- a/server/sonar-web/src/main/js/apps/account/account.css +++ b/server/sonar-web/src/main/js/apps/account/account.css @@ -16,16 +16,6 @@ padding-top: 11px; } -.account-nav .nav-tabs { - width: 100%; - border-bottom: none; -} - -.account-nav .navbar-nav > li > a { - padding-top: 8px; - padding-bottom: 8px; -} - .account-user { float: left; } diff --git a/server/sonar-web/src/main/js/apps/account/components/Nav.js b/server/sonar-web/src/main/js/apps/account/components/Nav.js index 65c06efeb12..d8d39380cd5 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Nav.js +++ b/server/sonar-web/src/main/js/apps/account/components/Nav.js @@ -20,6 +20,7 @@ // @flow import React from 'react'; import { Link, IndexLink } from 'react-router'; +import NavBarTabs from '../../../components/nav/NavBarTabs'; import { translate } from '../../../helpers/l10n'; type Props = { @@ -28,8 +29,8 @@ type Props = { export default function Nav({ customOrganizations }: Props) { return ( - ); } diff --git a/server/sonar-web/src/main/js/apps/component-measures/styles.css b/server/sonar-web/src/main/js/apps/component-measures/styles.css index 1c6f8c433ba..b72fcf31384 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/styles.css +++ b/server/sonar-web/src/main/js/apps/component-measures/styles.css @@ -377,3 +377,28 @@ border: 1px solid #e6e6e6; background-color: #fff; } + +.nav-pills > ul { + display: flex; + flex-wrap: wrap; +} + +.nav-pills > ul > li > a { + display: inline-block; + vertical-align: middle; + padding: 3px 10px; + border: 1px solid transparent; + border-radius: 24px; + color: #236a97; + transition: none; +} + +.nav-pills > ul > li > a:hover { + border-color: #236a97; +} + +.nav-pills > ul > li.active > a, +.nav-pills > ul > li > a.active { + background-color: #236a97; + color: #fff; +} diff --git a/server/sonar-web/src/main/js/apps/issues/styles.css b/server/sonar-web/src/main/js/apps/issues/styles.css index 3d1a53be793..bb0f41ec65b 100644 --- a/server/sonar-web/src/main/js/apps/issues/styles.css +++ b/server/sonar-web/src/main/js/apps/issues/styles.css @@ -115,22 +115,6 @@ text-align: right; } -.issues .search-navigator-facet-header, -.issues .search-navigator-facet-list { - padding-left: 0; - padding-right: 0; -} - -.issues .search-navigator-facet-header { - padding-top: 8px; - padding-bottom: 8px; -} - -.issues .search-navigator-facet-box:not(.hidden):not(.leak-facet-box) - + .search-navigator-facet-box:not(.leak-facet-box) { - border-top: none; -} - .issues .search-navigator-facet-footer { padding: 0 0 10px 0; } diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js index 370b2bc4dfb..e872e6e2ac1 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js @@ -20,8 +20,11 @@ // @flow import React from 'react'; import { Link } from 'react-router'; +import classNames from 'classnames'; import { translate } from '../../../helpers/l10n'; -import OrganizationIcon from '../../../components/ui/OrganizationIcon'; +import ContextNavBar from '../../../components/nav/ContextNavBar'; +import NavBarTabs from '../../../components/nav/NavBarTabs'; +import OrganizationIcon from '../../../components/icons-components/OrganizationIcon'; import type { Organization } from '../../../store/organizations/duck'; const ADMIN_PATHS = [ @@ -43,8 +46,11 @@ export default class OrganizationNavigation extends React.PureComponent { const { organization } = this.props; return ( -
        • - +
        • + {translate('layout.settings')} 
            @@ -145,75 +151,72 @@ export default class OrganizationNavigation extends React.PureComponent { const moreActive = !adminActive && location.pathname.includes('/extension/'); return ( - + + +
          • + + {translate('projects.page')} + +
          • +
          • + + {translate('organization.members.page')} + +
          • +
          • + + {translate('quality_profiles.page')} + +
          • +
          • + + {translate('coding_rules.page')} + +
          • + {this.renderExtensions(moreActive)} + {organization.canAdmin && this.renderAdministration(adminActive)} +
            + ); } } diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap index 06ffb28889b..05104c2e4d8 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap @@ -1,59 +1,100 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`admin 1`] = ` -
        • +
          +
          + +
        • + + projects.page + +
        • +
        • + + organization.members.page + +
        • +
        • + + quality_profiles.page + +
        • +
        • + + coding_rules.page + +
        • +
        • + + layout.settings +   + +
            -
          • - - projects.page - -
          • - organization.members.page + user_groups.page
          • @@ -61,9 +102,9 @@ exports[`admin 1`] = ` activeClassName="active" onlyActiveOnIndex={false} style={Object {}} - to="/organizations/foo/quality_profiles" + to="/organizations/foo/permissions" > - quality_profiles.page + permissions.page
          • @@ -71,140 +112,9 @@ exports[`admin 1`] = ` activeClassName="active" onlyActiveOnIndex={false} style={Object {}} - to="/organizations/foo/rules" + to="/organizations/foo/permission_templates" > - coding_rules.page - -
          • -
          • - - layout.settings -   - - -
              -
            • - - user_groups.page - -
            • -
            • - - permissions.page - -
            • -
            • - - permission_templates - -
            • -
            • - - projects_management - -
            • -
            • - - edit - -
            • -
            • - - delete - -
            • -
            -
          • -
          -
        • -
          - -`; - -exports[`regular user 1`] = ` - +
          + +
        • + + projects.page + +
        • +
        • + + organization.members.page + +
        • +
        • + + quality_profiles.page + +
        • +
        • + + coding_rules.page + +
        • +
          + `; exports[`undeletable org 1`] = ` - + + + `; diff --git a/server/sonar-web/src/main/js/components/ui/OrganizationIcon.js b/server/sonar-web/src/main/js/components/icons-components/OrganizationIcon.js similarity index 85% rename from server/sonar-web/src/main/js/components/ui/OrganizationIcon.js rename to server/sonar-web/src/main/js/components/icons-components/OrganizationIcon.js index 4b0de907c2c..225b3f92b5c 100644 --- a/server/sonar-web/src/main/js/components/ui/OrganizationIcon.js +++ b/server/sonar-web/src/main/js/components/icons-components/OrganizationIcon.js @@ -20,10 +20,17 @@ // @flow import React from 'react'; -export default function OrganizationIcon() { +type Props = { className?: string, size?: number }; + +export default function OrganizationIcon({ className, size = 16 }: Props) { /* eslint-disable max-len */ return ( - + ; +} diff --git a/server/sonar-web/src/main/js/components/nav/NavBar.css b/server/sonar-web/src/main/js/components/nav/NavBar.css new file mode 100644 index 00000000000..c74c0929f39 --- /dev/null +++ b/server/sonar-web/src/main/js/components/nav/NavBar.css @@ -0,0 +1,24 @@ +.navbar, +[class^="navbar-"], +[class*=" navbar-"] { + box-sizing: border-box; +} + +.navbar { +} + +.navbar-inner { + position: fixed; + left: 0; + right: 0; +} + +.navbar-limited { + position: relative; + min-width: 1100px; + max-width: 1320px; + margin-left: auto; + margin-right: auto; + padding-left: 20px; + padding-right: 20px; +} diff --git a/server/sonar-web/src/main/js/components/nav/NavBar.js b/server/sonar-web/src/main/js/components/nav/NavBar.js new file mode 100644 index 00000000000..beb4466edbc --- /dev/null +++ b/server/sonar-web/src/main/js/components/nav/NavBar.js @@ -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. + */ +// @flow +import React from 'react'; +import classNames from 'classnames'; +import './NavBar.css'; + +type Props = { + children?: React.Element<*>, + className?: string, + height: number +}; + +export default function NavBar({ children, className, height, ...other }: Props) { + return ( +
          +
          + {children} +
          +
          + + ); +} diff --git a/server/sonar-web/src/main/js/components/nav/NavBarTabs.css b/server/sonar-web/src/main/js/components/nav/NavBarTabs.css new file mode 100644 index 00000000000..b716dad62a3 --- /dev/null +++ b/server/sonar-web/src/main/js/components/nav/NavBarTabs.css @@ -0,0 +1,28 @@ +.navbar-tabs { + display: flex; + align-items: center; +} + +.navbar-tabs > li + li { + margin-left: 20px; +} + +.navbar-tabs > li > a { + display: block; + padding: 7px 0 4px; + border-bottom: 3px solid transparent; + color: #444; + transition: none; +} + +.navbar-tabs > li > a.active, +.navbar-tabs > li > a:hover, +.navbar-tabs > li > a:focus { + border-bottom-color: #4b9fd5; +} + +.navbar-tabs > li > a.is-admin.active, +.navbar-tabs > li > a.is-admin:hover, +.navbar-tabs > li > a.is-admin:focus { + border-bottom-color: #ed7d20; +} diff --git a/server/sonar-web/src/main/js/components/nav/NavBarTabs.js b/server/sonar-web/src/main/js/components/nav/NavBarTabs.js new file mode 100644 index 00000000000..f1d8e296278 --- /dev/null +++ b/server/sonar-web/src/main/js/components/nav/NavBarTabs.js @@ -0,0 +1,36 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import classNames from 'classnames'; +import './NavBarTabs.css'; + +type Props = { + children?: React.Element<*>, + className?: string +}; + +export default function NavBarTabs({ children, className, ...other }: Props) { + return ( +
            + {children} +
          + ); +} diff --git a/server/sonar-web/src/main/js/libs/third-party/bootstrap/dropdown.js b/server/sonar-web/src/main/js/libs/third-party/bootstrap/dropdown.js index 9dd4a8b75f4..05606b9ea88 100644 --- a/server/sonar-web/src/main/js/libs/third-party/bootstrap/dropdown.js +++ b/server/sonar-web/src/main/js/libs/third-party/bootstrap/dropdown.js @@ -42,7 +42,7 @@ clearMenus() if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + if ('ontouchstart' in document.documentElement) { // if mobile we use a backdrop because click events don't delegate $('