]> source.dussan.org Git - sonarqube.git/commitdiff
update projects page layout (#2182)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Mon, 19 Jun 2017 13:31:21 +0000 (06:31 -0700)
committerGitHub <noreply@github.com>
Mon, 19 Jun 2017 13:31:21 +0000 (06:31 -0700)
26 files changed:
it/it-tests/src/test/java/pageobjects/projects/ProjectsPage.java
server/sonar-web/src/main/js/apps/issues/components/App.js
server/sonar-web/src/main/js/apps/issues/conciseIssuesList/ConciseIssuesListHeader.js
server/sonar-web/src/main/js/apps/issues/styles.css
server/sonar-web/src/main/js/apps/organizations/components/OrganizationFavoriteProjects.js
server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.js
server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjectsContainer.js
server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
server/sonar-web/src/main/js/apps/projects/components/App.js
server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.js
server/sonar-web/src/main/js/apps/projects/components/PageHeader.js
server/sonar-web/src/main/js/apps/projects/components/PageHeaderContainer.js
server/sonar-web/src/main/js/apps/projects/components/PerspectiveSelect.js
server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBar.js [deleted file]
server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBarContainer.js [deleted file]
server/sonar-web/src/main/js/apps/projects/components/ProjectsSortingSelect.js
server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.js
server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectOptionBar-test.js [deleted file]
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.js.snap
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectOptionBar-test.js.snap [deleted file]
server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectsSortingSelect-test.js.snap
server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js
server/sonar-web/src/main/js/apps/projects/filters/SearchFilterContainer.js
server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap
server/sonar-web/src/main/js/apps/projects/styles.css
server/sonar-web/src/main/less/components/page.less

index 21bc73da4a09532217a809c6ee79acbdacd97f99..66bc7e5fda4f0504b7f7d455842a550a8733a735 100644 (file)
@@ -90,7 +90,7 @@ public class ProjectsPage {
   }
 
   public ProjectsPage searchProject(String search) {
-    SelenideElement searchInput = $(".projects-facet-search input");
+    SelenideElement searchInput = $(".projects-topbar-item-search input");
     searchInput.setValue("").sendKeys(search);
     return this;
   }
@@ -115,11 +115,6 @@ public class ProjectsPage {
   }
 
   private SelenideElement getOpenTopBar() {
-    SelenideElement topBar = $(".projects-topbar-actions").should(Condition.exist);
-    if (!topBar.has(Condition.hasClass("open"))){
-      $(".js-projects-topbar-open").click();
-    }
-    topBar.should(Condition.hasClass("open"));
-    return topBar;
+    return $(".projects-topbar-items").should(Condition.exist);
   }
 }
index 144f2f2b68276712f8bd821742bb1a1ceca1362e..d827a0d1f1f644a8f3d5e7b5a20a57f97273dcee 100644 (file)
@@ -804,8 +804,8 @@ export default class App extends React.PureComponent {
         {this.renderSide(openIssue)}
 
         <div className="layout-page-main">
-          <div className="issues-header-panel issues-main-header">
-            <div className="issues-header-panel-inner issues-main-header-inner">
+          <div className="layout-page-header-panel layout-page-main-header issues-main-header">
+            <div className="layout-page-header-panel-inner layout-page-main-header-inner">
               <div className="layout-page-main-inner">
                 {this.renderBulkChange(openIssue)}
                 {openIssue != null
index e6a5f1c24b3d4264793673126f8fad11961a3c5c..aed9b836953e8e46e6a72d8d8d53082dc1dbd5dd 100644 (file)
@@ -36,8 +36,8 @@ export default function ConciseIssuesListHeader(props: Props) {
   const { paging, selectedIndex } = props;
 
   return (
-    <header className="issues-header-panel concise-issues-list-header">
-      <div className="issues-header-panel-inner concise-issues-list-header-inner">
+    <header className="layout-page-header-panel concise-issues-list-header">
+      <div className="layout-page-header-panel-inner concise-issues-list-header-inner">
         <BackButton className="pull-left" onClick={props.onBackClick} />
         {props.loading
           ? <i className="spinner pull-right" />
index 95f6f533b227c847a63f919a3c4ccb3883c65c52..b2041786cf76eadd20b6918c2de441fa0ad46267 100644 (file)
@@ -1,55 +1,13 @@
-.issues-header-panel,
-.issues-header-panel-inner {
-  height: 56px;
-  box-sizing: border-box;
-}
-
-.issues-header-panel {
-  margin-top: -20px;
-}
-
-.issues-header-panel-inner {
-  position: fixed;
-  z-index: 30;
-  line-height: 24px;
-  padding-top: 16px;
-  padding-bottom: 16px;
-  border-bottom: 1px solid #e6e6e6;
-  background-color: #f3f3f3;
-}
-
-.issues-main-header {
-  margin-bottom: 20px;
-}
-
 .issues-main-header .component-name {
   line-height: 24px;
 }
 
-.issues-main-header-inner {
-  left: calc(50vw - 360px + 1px);
-  right: 0;
-  padding-left: 20px;
-  padding-right: 20px;
-}
-
-@media (max-width: 1320px) {
-  .issues-main-header-inner {
-    left: 301px;
-  }
+.concise-issues-list-header, .concise-issues-list-header-inner {
 }
 
-.issues-main-header-spinner {
-  margin-left: 1px;
-  margin-right: 9px;
-  margin-top: -1px;
+.concise-issues-list-header {
 }
 
-.concise-issues-list-header,
-.concise-issues-list-header-inner {}
-
-.concise-issues-list-header {}
-
 .concise-issues-list-header-inner {
   width: 260px;
   text-align: center;
   text-align: right;
 }
 
-.issues .search-navigator-facet-header,
-.issues .search-navigator-facet-list {
+.issues .search-navigator-facet-header, .issues .search-navigator-facet-list {
   padding-left: 0;
   padding-right: 0;
 }
   padding-bottom: 8px;
 }
 
-.issues .search-navigator-facet-box:not(.hidden):not(.leak-facet-box) + .search-navigator-facet-box:not(.leak-facet-box) {
+.issues .search-navigator-facet-box:not(.hidden):not(.leak-facet-box)
+  + .search-navigator-facet-box:not(.leak-facet-box) {
   border-top: none;
 }
 
index 39bcb30a75ac1b1bc6ab2e5657affddcbd9625ab..0707e5ae59d69f59ae26273f46e5e267699a969b 100644 (file)
@@ -26,8 +26,6 @@ export default class OrganizationFavoriteProjects extends React.PureComponent {
     children?: React.Element<*>,
     currentUser: { isLoggedIn: boolean },
     location: Object,
-    optionBarOpen: boolean,
-    optionBarToggle: (open: boolean) => void,
     organization: {
       key: string
     }
@@ -53,8 +51,6 @@ export default class OrganizationFavoriteProjects extends React.PureComponent {
         <FavoriteProjectsContainer
           currentUser={this.props.currentUser}
           location={this.props.location}
-          optionBarOpen={this.props.optionBarOpen}
-          optionBarToggle={this.props.optionBarToggle}
           organization={this.props.organization}
         />
       </div>
index 39d5c76ce76b6e5f20341f39f92481d58b758a62..cf16b4fe52f8b636a3f5a8a901ed7532fc7cb4c3 100644 (file)
@@ -26,8 +26,6 @@ export default class OrganizationProjects extends React.PureComponent {
     children?: React.Element<*>,
     currentUser: { isLoggedIn: boolean },
     location: Object,
-    optionBarOpen: boolean,
-    optionBarToggle: (open: boolean) => void,
     organization: {
       key: string
     }
@@ -54,8 +52,6 @@ export default class OrganizationProjects extends React.PureComponent {
           currentUser={this.props.currentUser}
           isFavorite={false}
           location={this.props.location}
-          optionBarOpen={this.props.optionBarOpen}
-          optionBarToggle={this.props.optionBarToggle}
           organization={this.props.organization}
         />
       </div>
index faa2bf8df04bf2d179c42f6259e4d36a83067f57..a08e864d1b9947b8d31d976194e79039dbefadd9 100644 (file)
@@ -23,20 +23,10 @@ import { connect } from 'react-redux';
 import { getCurrentUser, getOrganizationByKey } from '../../../store/rootReducer';
 import { updateOrganization } from '../actions';
 
-type State = {
-  optionBarOpen: boolean
-};
-
 class OrganizationProjectsContainer extends React.PureComponent {
-  state: State = { optionBarOpen: false };
-
-  handleOptionBarToggle = (open: boolean) => this.setState({ optionBarOpen: open });
-
   render() {
     return React.cloneElement(this.props.children, {
       currentUser: this.props.currentUser,
-      optionBarOpen: this.state.optionBarOpen,
-      optionBarToggle: this.handleOptionBarToggle,
       organization: this.props.organization
     });
   }
index 9720d56560bae5f82719f1aebe6f86715d78fd24..93754d095410d04e104df9b67bbb114e72193438 100644 (file)
@@ -21,7 +21,6 @@
 import React from 'react';
 import Helmet from 'react-helmet';
 import PageHeaderContainer from './PageHeaderContainer';
-import ProjectsOptionBarContainer from './ProjectsOptionBarContainer';
 import ProjectsListContainer from './ProjectsListContainer';
 import ProjectsListFooterContainer from './ProjectsListFooterContainer';
 import PageSidebar from './PageSidebar';
@@ -31,16 +30,14 @@ import { translate } from '../../../helpers/l10n';
 import { SORTING_SWITCH, parseSorting } from '../utils';
 import '../styles.css';
 
-type Props = {
+type Props = {|
   isFavorite: boolean,
   location: { pathname: string, query: { [string]: string } },
   fetchProjects: (query: string, isFavorite: boolean, organization?: {}) => Promise<*>,
-  optionBarOpen: boolean,
-  optionBarToggle: (open: boolean) => void,
   organization?: { key: string },
   router: { push: ({ pathname: string, query?: {} }) => void },
   currentUser?: { isLoggedIn: boolean }
-};
+|};
 
 type State = {
   query: { [string]: string }
@@ -67,11 +64,13 @@ export default class AllProjects extends React.PureComponent {
     footer && footer.classList.remove('search-navigator-footer');
   }
 
-  openOptionBar = (evt: Event & { currentTarget: HTMLElement }) => {
-    evt.currentTarget.blur();
-    evt.preventDefault();
-    this.props.optionBarToggle(true);
-  };
+  getView = () => this.state.query.view || 'overall';
+
+  getVisualization = () => this.state.query.visualization || 'risk';
+
+  getSort = () => this.state.query.sort || 'name';
+
+  isFiltered = () => Object.keys(this.state.query).some(key => this.state.query[key] != null);
 
   handlePerspectiveChange = ({ view, visualization }: { view: string, visualization?: string }) => {
     const query: { view: ?string, visualization: ?string, sort?: ?string } = {
@@ -111,78 +110,78 @@ export default class AllProjects extends React.PureComponent {
     });
   };
 
-  render() {
-    const { isFavorite, organization, optionBarOpen } = this.props;
-    const { query } = this.state;
-    const isFiltered = Object.keys(query).some(key => query[key] != null);
-
-    const view = query.view || 'overall';
-    const visualization = query.visualization || 'risk';
-    const selectedSort = query.sort || 'name';
-
-    const sideBarTop = (organization ? 95 : 30) + (optionBarOpen ? 45 : 0);
-    const contentTop = optionBarOpen ? 65 : 20;
+  renderSide = () => (
+    <div className="layout-page-side-outer">
+      <div
+        className="layout-page-side projects-page-side"
+        style={{ top: this.props.organization ? 95 : 30 }}>
+        <div className="layout-page-side-inner">
+          <div className="layout-page-filters">
+            <PageSidebar
+              isFavorite={this.props.isFavorite}
+              organization={this.props.organization}
+              query={this.state.query}
+              view={this.getView()}
+              visualization={this.getVisualization()}
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+
+  renderHeader = () => (
+    <div className="layout-page-header-panel layout-page-main-header">
+      <div className="layout-page-header-panel-inner layout-page-main-header-inner">
+        <div className="layout-page-main-inner">
+          <PageHeaderContainer
+            query={this.state.query}
+            isFavorite={this.props.isFavorite}
+            organization={this.props.organization}
+            onPerspectiveChange={this.handlePerspectiveChange}
+            onSortChange={this.handleSortChange}
+            selectedSort={this.getSort()}
+            currentUser={this.props.currentUser}
+            view={this.getView()}
+            visualization={this.getVisualization()}
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  renderMain = () =>
+    (this.getView() === 'visualizations'
+      ? <div className="layout-page-main-inner">
+          <VisualizationsContainer
+            sort={this.state.query.sort}
+            visualization={this.getVisualization()}
+          />
+        </div>
+      : <div className="layout-page-main-inner">
+          <ProjectsListContainer
+            isFavorite={this.props.isFavorite}
+            isFiltered={this.isFiltered()}
+            organization={this.props.organization}
+            cardType={this.getView()}
+          />
+          <ProjectsListFooterContainer
+            query={this.state.query}
+            isFavorite={this.props.isFavorite}
+            organization={this.props.organization}
+          />
+        </div>);
 
+  render() {
     return (
-      <div>
+      <div className="layout-page projects-page">
         <Helmet title={translate('projects.page')} />
 
-        <ProjectsOptionBarContainer
-          onPerspectiveChange={this.handlePerspectiveChange}
-          onSortChange={this.handleSortChange}
-          onToggleOptionBar={this.props.optionBarToggle}
-          open={optionBarOpen}
-          selectedSort={selectedSort}
-          currentUser={this.props.currentUser}
-          view={view}
-          visualization={visualization}
-        />
-
-        <div className="layout-page projects-page">
-          <div className="layout-page-side-outer">
-            <div className="layout-page-side projects-page-side" style={{ top: sideBarTop }}>
-              <div className="layout-page-side-inner">
-                <div className="layout-page-filters">
-                  <PageSidebar
-                    isFavorite={isFavorite}
-                    organization={organization}
-                    query={query}
-                    view={view}
-                    visualization={visualization}
-                  />
-                </div>
-              </div>
-            </div>
-          </div>
+        {this.renderSide()}
 
-          <div
-            className="layout-page-main projects-page-content"
-            style={{ paddingTop: contentTop }}>
-            <div className="layout-page-main-inner">
-              <PageHeaderContainer
-                query={query}
-                isFavorite={isFavorite}
-                organization={organization}
-                onOpenOptionBar={this.openOptionBar}
-                optionBarOpen={optionBarOpen}
-              />
-              {view !== 'visualizations' &&
-                <ProjectsListContainer
-                  isFavorite={isFavorite}
-                  isFiltered={isFiltered}
-                  organization={organization}
-                  cardType={view}
-                />}
-              {view !== 'visualizations' &&
-                <ProjectsListFooterContainer
-                  query={query}
-                  isFavorite={isFavorite}
-                  organization={organization}
-                />}
-              {view === 'visualizations' &&
-                <VisualizationsContainer sort={query.sort} visualization={visualization} />}
-            </div>
-          </div>
+        <div className="layout-page-main projects-page-content">
+          {this.renderHeader()}
+          {this.renderMain()}
         </div>
       </div>
     );
index f1b4d2f71c2bdaf810c741b6ab62ba1f5446d6fa..83b097ed170de6c87204cc3c1854344f3fc505e4 100644 (file)
 //@flow
 import React from 'react';
 
-type State = {
-  optionBarOpen: boolean
-};
-
 export default class App extends React.PureComponent {
-  state: State = { optionBarOpen: false };
-
   componentDidMount() {
     const elem = document.querySelector('html');
-    elem && elem.classList.add('dashboard-page');
+    if (elem) {
+      elem.classList.add('dashboard-page');
+    }
   }
 
   componentWillUnmount() {
     const elem = document.querySelector('html');
-    elem && elem.classList.remove('dashboard-page');
+    if (elem) {
+      elem.classList.remove('dashboard-page');
+    }
   }
 
-  handleOptionBarToggle = (open: boolean) => this.setState({ optionBarOpen: open });
-
   render() {
     return (
       <div id="projects-page">
-        {React.cloneElement(this.props.children, {
-          optionBarOpen: this.state.optionBarOpen,
-          optionBarToggle: this.handleOptionBarToggle
-        })}
+        {this.props.children}
       </div>
     );
   }
index 988891c41d3b52d921f422bc578a5cf174f7e930..f3e39df8b4d346e8cbc015eb0cae974d75d2f897 100644 (file)
@@ -29,8 +29,6 @@ import { searchProjects } from '../../../api/components';
 type Props = {
   currentUser: { isLoggedIn: boolean },
   location: { query: {} },
-  optionBarOpen: boolean,
-  optionBarToggle: (open: boolean) => void,
   router: {
     replace: (location: { pathname?: string, query?: { [string]: string } }) => void
   }
@@ -107,8 +105,6 @@ class DefaultPageSelector extends React.PureComponent {
         <AllProjectsContainer
           isFavorite={false}
           location={this.props.location}
-          optionBarOpen={this.props.optionBarOpen}
-          optionBarToggle={this.props.optionBarToggle}
           currentUser={this.props.currentUser}
         />
       );
index b4104652feb8dfd4401a97e8260b5e5e0113ad9a..dc1aa2de1233e7532664be7d0270b33703e12129 100644 (file)
  */
 // @flow
 import React from 'react';
+import classNames from 'classnames';
 import SearchFilterContainer from '../filters/SearchFilterContainer';
+import Tooltip from '../../../components/controls/Tooltip';
+import PerspectiveSelect from './PerspectiveSelect';
+import ProjectsSortingSelect from './ProjectsSortingSelect';
 import { translate } from '../../../helpers/l10n';
 
-type Props = {
+type Props = {|
+  currentUser?: { isLoggedIn: boolean },
   isFavorite?: boolean,
-  loading: boolean,
-  onOpenOptionBar: () => void,
-  optionBarOpen?: boolean,
+  onPerspectiveChange: ({ view: string, visualization?: string }) => void,
   organization?: { key: string },
+  projects: Array<*>,
+  projectsAppState: { loading: boolean, total?: number },
   query: { [string]: string },
-  total?: number
-};
+  onSortChange: (sort: string, desc: boolean) => void,
+  selectedSort: string,
+  view: string,
+  visualization?: string
+|};
 
 export default function PageHeader(props: Props) {
+  const renderSortingSelect = () => {
+    const { projectsAppState, projects, currentUser, view } = props;
+    const limitReached =
+      projects != null &&
+      projectsAppState.total != null &&
+      projects.length < projectsAppState.total;
+    const defaultOption = currentUser && currentUser.isLoggedIn ? 'name' : 'analysis_date';
+    if (view === 'visualizations' && !limitReached) {
+      return (
+        <Tooltip overlay={translate('projects.sort.disabled')}>
+          <div className="projects-topbar-item disabled">
+            <ProjectsSortingSelect
+              className="js-projects-sorting-select"
+              defaultOption={defaultOption}
+              onChange={props.onSortChange}
+              selectedSort={props.selectedSort}
+              view={props.view}
+            />
+          </div>
+        </Tooltip>
+      );
+    }
+    return (
+      <ProjectsSortingSelect
+        className="projects-topbar-item js-projects-sorting-select"
+        defaultOption={defaultOption}
+        onChange={props.onSortChange}
+        selectedSort={props.selectedSort}
+        view={props.view}
+      />
+    );
+  };
+
   return (
-    <header className="page-header">
+    <header className="page-header projects-topbar-items">
+      <PerspectiveSelect
+        className="projects-topbar-item js-projects-perspective-select"
+        onChange={props.onPerspectiveChange}
+        view={props.view}
+        visualization={props.visualization}
+      />
+
+      {renderSortingSelect()}
+
       <SearchFilterContainer
+        className="projects-topbar-item projects-topbar-item-search"
         isFavorite={props.isFavorite}
         organization={props.organization}
         query={props.query}
       />
-      <div className="page-actions projects-page-actions text-right">
-        {!props.optionBarOpen &&
-          <a
-            className="button js-projects-topbar-open spacer-right"
-            href="#"
-            onClick={props.onOpenOptionBar}>
-            {translate('projects.view_settings')}
-          </a>}
 
-        {!!props.loading && <i className="spinner spacer-right" />}
+      <div
+        className={classNames('projects-topbar-item', 'is-last', {
+          'is-loading': props.projectsAppState.loading
+        })}>
+        {!!props.projectsAppState.loading && <i className="spinner spacer-right" />}
 
-        {props.total != null &&
+        {props.projectsAppState.total != null &&
           <span>
-            <strong id="projects-total">{props.total}</strong>
+            <strong id="projects-total">{props.projectsAppState.total}</strong>
             {' '}
             {translate('projects._projects')}
           </span>}
index 5d817b926fe93cefdcf3ebc3c30a59f84c4a588e..7780da0a7055236ebd9140e0265ba2333f3ccd1c 100644 (file)
  */
 import { connect } from 'react-redux';
 import PageHeader from './PageHeader';
-import { getProjectsAppState } from '../../../store/rootReducer';
+import { getProjects, getProjectsAppState } from '../../../store/rootReducer';
 
-export default connect(state => getProjectsAppState(state))(PageHeader);
+const mapStateToProps = state => ({
+  projects: getProjects(state),
+  projectsAppState: getProjectsAppState(state)
+});
+
+export default connect(mapStateToProps)(PageHeader);
index 2580a34c4b8579959b688ea1037be474f8ac2dfe..8f6f5f41c0daf9f4d682b3d30236123843b73ca2 100644 (file)
@@ -26,12 +26,12 @@ import { VIEWS, VISUALIZATIONS } from '../utils';
 
 export type Option = { label: string, type: string, value: string };
 
-type Props = {
+type Props = {|
   className?: string,
   onChange: ({ view: string, visualization?: string }) => void,
   view: string,
   visualization?: string
-};
+|};
 
 export default class PerspectiveSelect extends React.PureComponent {
   options: Array<Option>;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBar.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBar.js
deleted file mode 100644 (file)
index 98537d8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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 Tooltip from '../../../components/controls/Tooltip';
-import PerspectiveSelect from './PerspectiveSelect';
-import ProjectsSortingSelect from './ProjectsSortingSelect';
-import { translate } from '../../../helpers/l10n';
-
-type Props = {
-  onPerspectiveChange: ({ view: string, visualization?: string }) => void,
-  onSortChange: (sort: string, desc: boolean) => void,
-  onToggleOptionBar: boolean => void,
-  open: boolean,
-  projects: Array<*>,
-  projectsAppState: { loading: boolean, total?: number },
-  selectedSort: string,
-  currentUser?: { isLoggedIn: boolean },
-  view: string,
-  visualization?: string
-};
-
-export default class ProjectsOptionBar extends React.PureComponent {
-  props: Props;
-
-  closeBar = (evt: Event & { currentTarget: HTMLElement }) => {
-    evt.currentTarget.blur();
-    evt.preventDefault();
-    this.props.onToggleOptionBar(false);
-  };
-
-  renderSortingSelect() {
-    const { projectsAppState, projects, currentUser, view } = this.props;
-    const limitReached =
-      projects != null &&
-      projectsAppState.total != null &&
-      projects.length < projectsAppState.total;
-    const defaultOption = currentUser && currentUser.isLoggedIn ? 'name' : 'analysis_date';
-    if (view === 'visualizations' && !limitReached) {
-      return (
-        <Tooltip overlay={translate('projects.sort.disabled')}>
-          <div>
-            <ProjectsSortingSelect
-              className="projects-topbar-item js-projects-sorting-select disabled"
-              defaultOption={defaultOption}
-              onChange={this.props.onSortChange}
-              selectedSort={this.props.selectedSort}
-              view={this.props.view}
-            />
-          </div>
-        </Tooltip>
-      );
-    }
-    return (
-      <ProjectsSortingSelect
-        className="projects-topbar-item js-projects-sorting-select"
-        defaultOption={defaultOption}
-        onChange={this.props.onSortChange}
-        selectedSort={this.props.selectedSort}
-        view={this.props.view}
-      />
-    );
-  }
-
-  render() {
-    const { open } = this.props;
-    return (
-      <div className="projects-topbar">
-        <div className={classNames('projects-topbar-actions', { open })}>
-          <div className="projects-topbar-actions-inner">
-            <button className="projects-topbar-button" onClick={this.closeBar}>
-              {translate('close')}
-            </button>
-            <div className="projects-topbar-items">
-              <PerspectiveSelect
-                className="projects-topbar-item js-projects-perspective-select"
-                onChange={this.props.onPerspectiveChange}
-                view={this.props.view}
-                visualization={this.props.visualization}
-              />
-              {this.renderSortingSelect()}
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBarContainer.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectsOptionBarContainer.js
deleted file mode 100644 (file)
index a58605b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 ProjectsOptionBar from './ProjectsOptionBar';
-import { getProjects, getProjectsAppState } from '../../../store/rootReducer';
-
-const mapStateToProps = state => ({
-  projects: getProjects(state),
-  projectsAppState: getProjectsAppState(state)
-});
-
-export default connect(mapStateToProps)(ProjectsOptionBar);
index 51d6f1fdd5e8282a9c9e1ae8fae9523239e880c0..2d97d5cad6868741bb0cf4a2fcabb8bf377d4da3 100644 (file)
@@ -65,10 +65,7 @@ export default class ProjectsSortingSelect extends React.PureComponent {
       opt => (opt.value === this.props.defaultOption ? 0 : 1)
     ).map((opt: { value: string, class?: string }) => ({
       value: opt.value,
-      label: translate('projects.sorting', opt.value) +
-        (opt.value === this.props.defaultOption
-          ? ` (${translate('projects.sorting.default')})`
-          : ''),
+      label: translate('projects.sorting', opt.value),
       class: opt.class
     }));
   };
@@ -88,7 +85,7 @@ export default class ProjectsSortingSelect extends React.PureComponent {
       <div className={this.props.className}>
         <label>{translate('projects.sort_by')}:</label>
         <Select
-          className="little-spacer-left input-large"
+          className="little-spacer-left input-medium"
           clearable={false}
           onChange={this.handleSortChange}
           optionComponent={ProjectsSortingSelectOption}
index ef934431b526702b11620bc8032119b86be4b159..0a9b1b2aca0603626cae8a3f8281d42ed8ee4d76 100644 (file)
@@ -22,17 +22,65 @@ import { shallow } from 'enzyme';
 import PageHeader from '../PageHeader';
 
 it('should render correctly', () => {
-  expect(shallow(<PageHeader query={{ search: 'test' }} total="12" />)).toMatchSnapshot();
+  expect(
+    shallow(<PageHeader query={{ search: 'test' }} projectsAppState={{ total: 12 }} />)
+  ).toMatchSnapshot();
 });
 
 it('should render correctly while loading', () => {
   expect(
-    shallow(<PageHeader query={{ search: '' }} loading={true} isFavorite={true} total="2" />)
+    shallow(
+      <PageHeader
+        query={{ search: '' }}
+        isFavorite={true}
+        projectsAppState={{ loading: true, total: 2 }}
+      />
+    )
   ).toMatchSnapshot();
 });
 
 it('should not render projects total', () => {
   expect(
-    shallow(<PageHeader query={{ search: '' }} />).find('#projects-total').exists()
+    shallow(<PageHeader projectsAppState={{}} query={{ search: '' }} />)
+      .find('#projects-total')
+      .exists()
   ).toBeFalsy();
 });
+
+it('should render disabled sorting options for visualizations', () => {
+  expect(
+    shallow(
+      <PageHeader
+        open={true}
+        projectsAppState={{}}
+        view="visualizations"
+        visualization="coverage"
+      />
+    )
+  ).toMatchSnapshot();
+});
+
+it('should render switch the default sorting option for anonymous users', () => {
+  expect(
+    shallow(
+      <PageHeader
+        currentUser={{ isLoggedIn: true }}
+        open={true}
+        projectsAppState={{}}
+        view="overall"
+        visualization="risk"
+      />
+    ).find('ProjectsSortingSelect')
+  ).toMatchSnapshot();
+  expect(
+    shallow(
+      <PageHeader
+        currentUser={{ isLoggedIn: false }}
+        open={true}
+        projectsAppState={{}}
+        view="leak"
+        visualization="risk"
+      />
+    ).find('ProjectsSortingSelect')
+  ).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectOptionBar-test.js b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectOptionBar-test.js
deleted file mode 100644 (file)
index c496b37..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 React from 'react';
-import { shallow } from 'enzyme';
-import ProjectsOptionBar from '../ProjectsOptionBar';
-import { click } from '../../../../helpers/testUtils';
-
-it('should render option bar closed', () => {
-  expect(shallow(<ProjectsOptionBar open={false} view="overall" />)).toMatchSnapshot();
-});
-
-it('should render option bar open', () => {
-  expect(
-    shallow(
-      <ProjectsOptionBar
-        open={true}
-        view="leak"
-        visualization="risk"
-        projects={[1, 2, 3]}
-        projectsAppState={{ total: 3 }}
-        currentUser={{ isLoggedIn: true }}
-      />
-    )
-  ).toMatchSnapshot();
-});
-
-it('should render disabled sorting options for visualizations', () => {
-  expect(
-    shallow(<ProjectsOptionBar open={true} view="visualizations" visualization="coverage" />)
-  ).toMatchSnapshot();
-});
-
-it('should call close method correctly', () => {
-  const toggle = jest.fn();
-  const wrapper = shallow(<ProjectsOptionBar open={true} view="leak" onToggleOptionBar={toggle} />);
-  click(wrapper.find('.projects-topbar-button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-});
-
-it('should render switch the default sorting option for anonymous users', () => {
-  expect(
-    shallow(
-      <ProjectsOptionBar
-        open={true}
-        view="overall"
-        visualization="risk"
-        currentUser={{ isLoggedIn: true }}
-      />
-    ).find('ProjectsSortingSelect')
-  ).toMatchSnapshot();
-  expect(
-    shallow(
-      <ProjectsOptionBar
-        open={true}
-        view="leak"
-        visualization="risk"
-        currentUser={{ isLoggedIn: false }}
-      />
-    ).find('ProjectsSortingSelect')
-  ).toMatchSnapshot();
-});
index c554011553ed7d5867dda097350111cf69a72ade..17c8eddd16c8d6db1e7ea455b8f5bd9e502cc85e 100644 (file)
@@ -2,9 +2,17 @@
 
 exports[`should render correctly 1`] = `
 <header
-  className="page-header"
+  className="page-header projects-topbar-items"
 >
+  <PerspectiveSelect
+    className="projects-topbar-item js-projects-perspective-select"
+  />
+  <ProjectsSortingSelect
+    className="projects-topbar-item js-projects-sorting-select"
+    defaultOption="analysis_date"
+  />
   <withRouter(SearchFilterContainer)
+    className="projects-topbar-item projects-topbar-item-search"
     query={
       Object {
         "search": "test",
@@ -12,14 +20,8 @@ exports[`should render correctly 1`] = `
     }
   />
   <div
-    className="page-actions projects-page-actions text-right"
+    className="projects-topbar-item is-last"
   >
-    <a
-      className="button js-projects-topbar-open spacer-right"
-      href="#"
-    >
-      projects.view_settings
-    </a>
     <span>
       <strong
         id="projects-total"
@@ -35,9 +37,17 @@ exports[`should render correctly 1`] = `
 
 exports[`should render correctly while loading 1`] = `
 <header
-  className="page-header"
+  className="page-header projects-topbar-items"
 >
+  <PerspectiveSelect
+    className="projects-topbar-item js-projects-perspective-select"
+  />
+  <ProjectsSortingSelect
+    className="projects-topbar-item js-projects-sorting-select"
+    defaultOption="analysis_date"
+  />
   <withRouter(SearchFilterContainer)
+    className="projects-topbar-item projects-topbar-item-search"
     isFavorite={true}
     query={
       Object {
@@ -46,14 +56,8 @@ exports[`should render correctly while loading 1`] = `
     }
   />
   <div
-    className="page-actions projects-page-actions text-right"
+    className="projects-topbar-item is-last is-loading"
   >
-    <a
-      className="button js-projects-topbar-open spacer-right"
-      href="#"
-    >
-      projects.view_settings
-    </a>
     <i
       className="spinner spacer-right"
     />
@@ -69,3 +73,51 @@ exports[`should render correctly while loading 1`] = `
   </div>
 </header>
 `;
+
+exports[`should render disabled sorting options for visualizations 1`] = `
+<header
+  className="page-header projects-topbar-items"
+>
+  <PerspectiveSelect
+    className="projects-topbar-item js-projects-perspective-select"
+    view="visualizations"
+    visualization="coverage"
+  />
+  <Tooltip
+    overlay="projects.sort.disabled"
+    placement="bottom"
+  >
+    <div
+      className="projects-topbar-item disabled"
+    >
+      <ProjectsSortingSelect
+        className="js-projects-sorting-select"
+        defaultOption="analysis_date"
+        view="visualizations"
+      />
+    </div>
+  </Tooltip>
+  <withRouter(SearchFilterContainer)
+    className="projects-topbar-item projects-topbar-item-search"
+  />
+  <div
+    className="projects-topbar-item is-last"
+  />
+</header>
+`;
+
+exports[`should render switch the default sorting option for anonymous users 1`] = `
+<ProjectsSortingSelect
+  className="projects-topbar-item js-projects-sorting-select"
+  defaultOption="name"
+  view="overall"
+/>
+`;
+
+exports[`should render switch the default sorting option for anonymous users 2`] = `
+<ProjectsSortingSelect
+  className="projects-topbar-item js-projects-sorting-select"
+  defaultOption="analysis_date"
+  view="leak"
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectOptionBar-test.js.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectOptionBar-test.js.snap
deleted file mode 100644 (file)
index 1505112..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should call close method correctly 1`] = `
-Array [
-  Array [
-    false,
-  ],
-]
-`;
-
-exports[`should render disabled sorting options for visualizations 1`] = `
-<div
-  className="projects-topbar"
->
-  <div
-    className="projects-topbar-actions open"
-  >
-    <div
-      className="projects-topbar-actions-inner"
-    >
-      <button
-        className="projects-topbar-button"
-        onClick={[Function]}
-      >
-        close
-      </button>
-      <div
-        className="projects-topbar-items"
-      >
-        <PerspectiveSelect
-          className="projects-topbar-item js-projects-perspective-select"
-          view="visualizations"
-          visualization="coverage"
-        />
-        <Tooltip
-          overlay="projects.sort.disabled"
-          placement="bottom"
-        >
-          <div>
-            <ProjectsSortingSelect
-              className="projects-topbar-item js-projects-sorting-select disabled"
-              defaultOption="analysis_date"
-              view="visualizations"
-            />
-          </div>
-        </Tooltip>
-      </div>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render option bar closed 1`] = `
-<div
-  className="projects-topbar"
->
-  <div
-    className="projects-topbar-actions"
-  >
-    <div
-      className="projects-topbar-actions-inner"
-    >
-      <button
-        className="projects-topbar-button"
-        onClick={[Function]}
-      >
-        close
-      </button>
-      <div
-        className="projects-topbar-items"
-      >
-        <PerspectiveSelect
-          className="projects-topbar-item js-projects-perspective-select"
-          view="overall"
-        />
-        <ProjectsSortingSelect
-          className="projects-topbar-item js-projects-sorting-select"
-          defaultOption="analysis_date"
-          view="overall"
-        />
-      </div>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render option bar open 1`] = `
-<div
-  className="projects-topbar"
->
-  <div
-    className="projects-topbar-actions open"
-  >
-    <div
-      className="projects-topbar-actions-inner"
-    >
-      <button
-        className="projects-topbar-button"
-        onClick={[Function]}
-      >
-        close
-      </button>
-      <div
-        className="projects-topbar-items"
-      >
-        <PerspectiveSelect
-          className="projects-topbar-item js-projects-perspective-select"
-          view="leak"
-          visualization="risk"
-        />
-        <ProjectsSortingSelect
-          className="projects-topbar-item js-projects-sorting-select"
-          defaultOption="name"
-          view="leak"
-        />
-      </div>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render switch the default sorting option for anonymous users 1`] = `
-<ProjectsSortingSelect
-  className="projects-topbar-item js-projects-sorting-select"
-  defaultOption="name"
-  view="overall"
-/>
-`;
-
-exports[`should render switch the default sorting option for anonymous users 2`] = `
-<ProjectsSortingSelect
-  className="projects-topbar-item js-projects-sorting-select"
-  defaultOption="analysis_date"
-  view="leak"
-/>
-`;
index 7a004599bfb717e45a80995852d0183b0e625510..21c3b3f5d5a57ff292629996560c227cf1609037 100644 (file)
@@ -12,7 +12,7 @@ exports[`should handle the descending sort direction 1`] = `
     autosize={true}
     backspaceRemoves={true}
     backspaceToRemoveMessage="Press backspace to remove {label}"
-    className="little-spacer-left input-large"
+    className="little-spacer-left input-medium"
     clearAllText="Clear all"
     clearValueText="Clear value"
     clearable={false}
@@ -41,7 +41,7 @@ exports[`should handle the descending sort direction 1`] = `
       Array [
         Object {
           "class": undefined,
-          "label": "projects.sorting.name (projects.sorting.default)",
+          "label": "projects.sorting.name",
           "value": "name",
         },
         Object {
@@ -121,7 +121,7 @@ exports[`should render correctly for leak view 1`] = `
     autosize={true}
     backspaceRemoves={true}
     backspaceToRemoveMessage="Press backspace to remove {label}"
-    className="little-spacer-left input-large"
+    className="little-spacer-left input-medium"
     clearAllText="Clear all"
     clearValueText="Clear value"
     clearable={false}
@@ -150,7 +150,7 @@ exports[`should render correctly for leak view 1`] = `
       Array [
         Object {
           "class": undefined,
-          "label": "projects.sorting.analysis_date (projects.sorting.default)",
+          "label": "projects.sorting.analysis_date",
           "value": "analysis_date",
         },
         Object {
@@ -230,7 +230,7 @@ exports[`should render correctly for overall view 1`] = `
     autosize={true}
     backspaceRemoves={true}
     backspaceToRemoveMessage="Press backspace to remove {label}"
-    className="little-spacer-left input-large"
+    className="little-spacer-left input-medium"
     clearAllText="Clear all"
     clearValueText="Clear value"
     clearable={false}
@@ -259,7 +259,7 @@ exports[`should render correctly for overall view 1`] = `
       Array [
         Object {
           "class": undefined,
-          "label": "projects.sorting.name (projects.sorting.default)",
+          "label": "projects.sorting.name",
           "value": "name",
         },
         Object {
index e6bcf8259230f5038a77a3bfd40cc24890a9f1c4..506bec6175f9266c9f5e4b79cdefcbd705a479b6 100644 (file)
@@ -22,6 +22,7 @@ import React from 'react';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 
 type Props = {
+  className?: string,
   handleSearch: (userString?: string) => void,
   query: { search?: string }
 };
@@ -63,11 +64,10 @@ export default class SearchFilter extends React.PureComponent {
     const { userQuery } = this.state;
     const shortQuery = userQuery != null && userQuery.length === 1;
     return (
-      <div className="projects-facet-search" data-key="search">
+      <div className={this.props.className}>
         <input
           type="search"
           value={userQuery || ''}
-          className="input-super-large"
           placeholder={translate('projects.search')}
           onChange={this.handleQueryChange}
           autoComplete="off"
index ec6bad4c55d54dcdf0a7727181cd7c4d101b4212..74b16a51ae30b99b8b6864f356967951a5777491 100644 (file)
@@ -24,12 +24,13 @@ import { debounce } from 'lodash';
 import { getFilterUrl } from './utils';
 import SearchFilter from './SearchFilter';
 
-type Props = {
+type Props = {|
+  className?: string,
   query: { search?: string },
   router: { push: ({ pathname: string }) => void },
   isFavorite?: boolean,
   organization?: {}
-};
+|};
 
 class SearchFilterContainer extends React.PureComponent {
   handleSearch: (userQuery?: string) => void;
@@ -46,7 +47,13 @@ class SearchFilterContainer extends React.PureComponent {
   }
 
   render() {
-    return <SearchFilter query={this.props.query} handleSearch={this.handleSearch} />;
+    return (
+      <SearchFilter
+        className={this.props.className}
+        query={this.props.query}
+        handleSearch={this.handleSearch}
+      />
+    );
   }
 }
 
index a48f32ac99c89d70e3df49eb1fa4c4cab3179199..86e0c761aa1421278a31fddc5bd8bac05e122ef9 100644 (file)
@@ -1,13 +1,9 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should display a help message when there is less than 2 characters 1`] = `
-<div
-  className="projects-facet-search"
-  data-key="search"
->
+<div>
   <input
     autoComplete="off"
-    className="input-super-large"
     onChange={[Function]}
     placeholder="projects.search"
     type="search"
@@ -22,13 +18,9 @@ exports[`should display a help message when there is less than 2 characters 1`]
 `;
 
 exports[`should display a help message when there is less than 2 characters 2`] = `
-<div
-  className="projects-facet-search"
-  data-key="search"
->
+<div>
   <input
     autoComplete="off"
-    className="input-super-large"
     onChange={[Function]}
     placeholder="projects.search"
     type="search"
@@ -38,13 +30,9 @@ exports[`should display a help message when there is less than 2 characters 2`]
 `;
 
 exports[`should render correctly without any search query 1`] = `
-<div
-  className="projects-facet-search"
-  data-key="search"
->
+<div>
   <input
     autoComplete="off"
-    className="input-super-large"
     onChange={[Function]}
     placeholder="projects.search"
     type="search"
@@ -54,13 +42,9 @@ exports[`should render correctly without any search query 1`] = `
 `;
 
 exports[`should render with a search query 1`] = `
-<div
-  className="projects-facet-search"
-  data-key="search"
->
+<div>
   <input
     autoComplete="off"
-    className="input-super-large"
     onChange={[Function]}
     placeholder="projects.search"
     type="search"
index f9b1b627502ca7dc0b8132cdd86feb6ca5c83666..2af711764d095556047d01f72f67a0971b78314d 100644 (file)
@@ -1,7 +1,3 @@
-.projects-page-actions {
-  margin-bottom: 0;
-}
-
 .projects-page-side {
   transition: top 150ms ease-out;
 }
   transition: padding-top 150ms ease-out;
 }
 
-.projects-topbar {
-  position: fixed;
-  width: 100%;
-  z-index: 100;
-}
-
-.projects-topbar-actions {
-  box-sizing: border-box;
-  position: absolute;
-  left: 0;
-  right: 0;
-  top: -50px;
-  z-index: 50;
-  flex-grow: 0.000001;
-  border-bottom: 1px solid #e6e6e6;
-  background-color: #fff;
-  transition: top 150ms ease-out;
+.projects-topbar-items {
+  display: flex;
+  align-items: center;
+  flex-grow: 1;
 }
 
-.projects-topbar-actions.open {
-  top: 0;
+.projects-topbar-item + .projects-topbar-item {
+  padding-left: 24px;
 }
 
-.projects-topbar-actions-inner {
-  position: relative;
-  margin: auto;
-  padding: 0 20px;
-  min-width: 1040px;
-  max-width: 1280px;
+.projects-topbar-item .spinner {
+  top: -1px;
 }
 
-.projects-topbar-items {
-  display: flex;
-  flex-wrap: nowrap;
-  justify-content: center;
-  align-items: center;
-  flex-grow: 1;
-  height: 46px;
+.projects-topbar-item.is-last {
+  margin-left: auto;
+  padding-left: 32px;
 }
 
-.projects-topbar-item {
-  padding: 0 24px;
+.projects-topbar-item.is-loading {
+  padding-left: 0;
 }
 
 .projects-topbar-item.disabled {
   pointer-events: none !important;
 }
 
-.projects-topbar-button {
-  position: absolute;
-  right: 20px;
-  top: 10px;
+.projects-topbar-item-search {
+  position: relative;
+  flex: 1;
 }
 
-.projects-sidebar {
-  width: 260px;
+.projects-topbar-item-search input {
+  width: 100%;
+  max-width: 300px;
+}
+
+.projects-topbar-item-search .note {
+  position: absolute;
+  top: 1px;
+  left: 80px;
+  line-height: 24px;
+  pointer-events: none;
 }
 
 .projects-list .page-actions {
   border-bottom: 1px solid #e6e6e6;
 }
 
-.projects-facet-search {
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 300px;
-}
-
-.projects-facet-search .note {
-  position: absolute;
-  top: 1px;
-  right: 30px;
-  line-height: 24px;
-  pointer-events: none;
-}
-
 .projects-facets-reset {
   float: right;
 }
 
-.projects-facets-reset .button {}
+.projects-facets-reset .button {
+}
 
 .projects-facet-bar {
   display: inline-block;
 }
 
 .search-navigator-facet.active .projects-facet-bar-inner,
-.search-navigator-facet-highlight-under-container .search-navigator-facet.active ~ .search-navigator-facet .projects-facet-bar-inner {
+.search-navigator-facet-highlight-under-container .search-navigator-facet.active
+  ~ .search-navigator-facet .projects-facet-bar-inner {
   background-color: #4b9fd5;
 }
 
index 6ab19d4d724abd81d3587cdc1d75ee23c2263754..fa128f99095af81df2c51164920ca23cbe50cadb 100644 (file)
     background: #f3f3f3;
 
     @media (max-width: 1335px) {
-        & { width: 310px; }
+      & {
+        width: 310px;
       }
+    }
 
     .search-navigator-facets-list {
       width: 260px;
       margin-left: ~"calc(50vw - 640px + 290px - 260px - 37px)";
 
       @media (max-width: 1335px) {
-        & { margin-left: 20px; }
+        & {
+          margin-left: 20px;
+        }
       }
     }
   }
   background-color: #f3f3f3;
 }
 
+.layout-page-header-panel, .layout-page-header-panel-inner {
+  height: 56px;
+  box-sizing: border-box;
+}
+
+.layout-page-header-panel {
+  margin-top: -20px;
+}
+
+.layout-page-header-panel-inner {
+  position: fixed;
+  z-index: 30;
+  line-height: 24px;
+  padding-top: 16px;
+  padding-bottom: 16px;
+  border-bottom: 1px solid #e6e6e6;
+  background-color: #f3f3f3;
+}
+
+.layout-page-main-header {
+  margin-bottom: 20px;
+}
+
+.layout-page-main-header .component-name {
+  line-height: 24px;
+}
+
+.layout-page-main-header-inner {
+  left: ~"calc(50vw - 360px + 1px)";
+  right: 0;
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
 @media (max-width: 1320px) {
   .layout-page-side-outer {
     width: 300px;
   .layout-page-side-inner {
     margin-left: 0;
   }
-}
\ No newline at end of file
+
+  .layout-page-main-header-inner {
+    left: 301px;
+  }
+}