aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-05-29 16:51:25 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-06-09 08:26:48 +0200
commit0c575091622e0992de4c856d02e34b3e037f8f9f (patch)
tree609c1a8aa43d0e6fa3adbd1c62594ac7a6b085de /server
parent8a173aa3175c846291b8b56f2cfd84ab0e782627 (diff)
downloadsonarqube-0c575091622e0992de4c856d02e34b3e037f8f9f.tar.gz
sonarqube-0c575091622e0992de4c856d02e34b3e037f8f9f.zip
SONAR-9254 Move the projects search box on top of the projects cards
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjects.js22
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/PageHeader.js9
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.js38
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.js.snap79
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.js.snap16
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js15
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap17
-rw-r--r--server/sonar-web/src/main/js/apps/projects/styles.css19
9 files changed, 155 insertions, 62 deletions
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
index 8b172222b75..46d752be2db 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.js
@@ -120,6 +120,7 @@ export default class AllProjects extends React.PureComponent {
};
render() {
+ const { isFavorite, organization } = this.props;
const { query, optionBarOpen } = this.state;
const isFiltered = Object.keys(query).some(key => query[key] != null);
@@ -127,7 +128,7 @@ export default class AllProjects extends React.PureComponent {
const visualization = query.visualization || 'risk';
const selectedSort = query.sort || 'name';
- const top = (this.props.organization ? 95 : 30) + (optionBarOpen ? 45 : 0);
+ const top = (organization ? 95 : 30) + (optionBarOpen ? 45 : 0);
return (
<div>
@@ -149,8 +150,8 @@ export default class AllProjects extends React.PureComponent {
<div className="layout-page-side-inner">
<div className="layout-page-filters">
<PageSidebar
- isFavorite={this.props.isFavorite}
- organization={this.props.organization}
+ isFavorite={isFavorite}
+ organization={organization}
query={query}
view={view}
visualization={visualization}
@@ -162,19 +163,24 @@ export default class AllProjects extends React.PureComponent {
<div className="layout-page-main">
<div className="layout-page-main-inner">
- <PageHeaderContainer onOpenOptionBar={this.openOptionBar} />
+ <PageHeaderContainer
+ query={query}
+ isFavorite={isFavorite}
+ organization={organization}
+ onOpenOptionBar={this.openOptionBar}
+ />
{view !== 'visualizations' &&
<ProjectsListContainer
- isFavorite={this.props.isFavorite}
+ isFavorite={isFavorite}
isFiltered={isFiltered}
- organization={this.props.organization}
+ organization={organization}
cardType={view}
/>}
{view !== 'visualizations' &&
<ProjectsListFooterContainer
query={query}
- isFavorite={this.props.isFavorite}
- organization={this.props.organization}
+ isFavorite={isFavorite}
+ organization={organization}
/>}
{view === 'visualizations' &&
<VisualizationsContainer sort={query.sort} visualization={visualization} />}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.js b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.js
index f3866ee3935..00022b19545 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.js
@@ -19,17 +19,26 @@
*/
// @flow
import React from 'react';
+import SearchFilterContainer from '../filters/SearchFilterContainer';
import { translate } from '../../../helpers/l10n';
type Props = {
+ isFavorite?: boolean,
loading: boolean,
onOpenOptionBar: () => void,
+ organization?: { key: string },
+ query: { [string]: string },
total?: number
};
export default function PageHeader(props: Props) {
return (
<header className="page-header">
+ <SearchFilterContainer
+ isFavorite={props.isFavorite}
+ organization={props.organization}
+ query={props.query}
+ />
<div className="page-actions projects-page-actions text-right">
<div className="spacer-bottom">
<a className="button js-projects-topbar-open" href="#" onClick={props.onOpenOptionBar}>
diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js
index 3e7ca9e4591..302ee1941ff 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js
@@ -34,7 +34,6 @@ import NewLinesFilter from '../filters/NewLinesFilter';
import QualityGateFilter from '../filters/QualityGateFilter';
import ReliabilityFilter from '../filters/ReliabilityFilter';
import SecurityFilter from '../filters/SecurityFilter';
-import SearchFilterContainer from '../filters/SearchFilterContainer';
import SizeFilter from '../filters/SizeFilter';
import TagsFilterContainer from '../filters/TagsFilterContainer';
import { translate } from '../../../helpers/l10n';
@@ -84,7 +83,6 @@ export default function PageSidebar({
</div>}
<h3>{translate('filters')}</h3>
- <SearchFilterContainer {...facetProps} />
</div>
<QualityGateFilter {...facetProps} />
{!isLeakView && [
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.js b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.js
new file mode 100644
index 00000000000..ef934431b52
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.js
@@ -0,0 +1,38 @@
+/*
+ * 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 PageHeader from '../PageHeader';
+
+it('should render correctly', () => {
+ expect(shallow(<PageHeader query={{ search: 'test' }} total="12" />)).toMatchSnapshot();
+});
+
+it('should render correctly while loading', () => {
+ expect(
+ shallow(<PageHeader query={{ search: '' }} loading={true} isFavorite={true} total="2" />)
+ ).toMatchSnapshot();
+});
+
+it('should not render projects total', () => {
+ expect(
+ shallow(<PageHeader query={{ search: '' }} />).find('#projects-total').exists()
+ ).toBeFalsy();
+});
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.js.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.js.snap
new file mode 100644
index 00000000000..9783b6a6c35
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.js.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<header
+ className="page-header"
+>
+ <withRouter(SearchFilterContainer)
+ query={
+ Object {
+ "search": "test",
+ }
+ }
+ />
+ <div
+ className="page-actions projects-page-actions text-right"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ <a
+ className="button js-projects-topbar-open"
+ href="#"
+ >
+ projects.view_settings
+ </a>
+ </div>
+ <span>
+ <strong
+ id="projects-total"
+ >
+ 12
+ </strong>
+
+ projects._projects
+ </span>
+ </div>
+</header>
+`;
+
+exports[`should render correctly while loading 1`] = `
+<header
+ className="page-header"
+>
+ <withRouter(SearchFilterContainer)
+ isFavorite={true}
+ query={
+ Object {
+ "search": "",
+ }
+ }
+ />
+ <div
+ className="page-actions projects-page-actions text-right"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ <a
+ className="button js-projects-topbar-open"
+ href="#"
+ >
+ projects.view_settings
+ </a>
+ </div>
+ <i
+ className="spinner spacer-right"
+ />
+ <span>
+ <strong
+ id="projects-total"
+ >
+ 2
+ </strong>
+
+ projects._projects
+ </span>
+ </div>
+</header>
+`;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.js.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.js.snap
index 5460d9a0e3d..d48dbb01e6d 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.js.snap
@@ -40,14 +40,6 @@ exports[`should render \`leak\` view correctly 1`] = `
<h3>
filters
</h3>
- <withRouter(SearchFilterContainer)
- isFavorite={false}
- query={
- Object {
- "view": "leak",
- }
- }
- />
</div>
<QualityGateFilter
isFavorite={false}
@@ -151,14 +143,6 @@ exports[`should render correctly 1`] = `
<h3>
filters
</h3>
- <withRouter(SearchFilterContainer)
- isFavorite={true}
- query={
- Object {
- "size": "3",
- }
- }
- />
</div>
<QualityGateFilter
isFavorite={true}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js
index 1ce1141fa11..e6bcf825923 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/SearchFilter.js
@@ -19,7 +19,6 @@
*/
// @flow
import React from 'react';
-import classNames from 'classnames';
import { translate, translateWithParameters } from '../../../helpers/l10n';
type Props = {
@@ -62,23 +61,21 @@ export default class SearchFilter extends React.PureComponent {
render() {
const { userQuery } = this.state;
- const inputClassName = classNames('input-super-large', {
- touched: userQuery != null && userQuery.length === 1
- });
-
+ const shortQuery = userQuery != null && userQuery.length === 1;
return (
<div className="projects-facet-search" data-key="search">
<input
type="search"
value={userQuery || ''}
- className={inputClassName}
+ className="input-super-large"
placeholder={translate('projects.search')}
onChange={this.handleQueryChange}
autoComplete="off"
/>
- <span className="note spacer-left">
- {translateWithParameters('select2.tooShort', 2)}
- </span>
+ {shortQuery &&
+ <span className="note spacer-left">
+ {translateWithParameters('select2.tooShort', 2)}
+ </span>}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap
index 0fd5b0f6cb4..a48f32ac99c 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projects/filters/__tests__/__snapshots__/SearchFilter-test.js.snap
@@ -7,7 +7,7 @@ exports[`should display a help message when there is less than 2 characters 1`]
>
<input
autoComplete="off"
- className="input-super-large touched"
+ className="input-super-large"
onChange={[Function]}
placeholder="projects.search"
type="search"
@@ -34,11 +34,6 @@ exports[`should display a help message when there is less than 2 characters 2`]
type="search"
value="foo"
/>
- <span
- className="note spacer-left"
- >
- select2.tooShort.2
- </span>
</div>
`;
@@ -55,11 +50,6 @@ exports[`should render correctly without any search query 1`] = `
type="search"
value=""
/>
- <span
- className="note spacer-left"
- >
- select2.tooShort.2
- </span>
</div>
`;
@@ -76,10 +66,5 @@ exports[`should render with a search query 1`] = `
type="search"
value="foo"
/>
- <span
- className="note spacer-left"
- >
- select2.tooShort.2
- </span>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/styles.css b/server/sonar-web/src/main/js/apps/projects/styles.css
index a6c471bef8c..afe6b79b614 100644
--- a/server/sonar-web/src/main/js/apps/projects/styles.css
+++ b/server/sonar-web/src/main/js/apps/projects/styles.css
@@ -223,21 +223,18 @@
}
.projects-facet-search {
- position: relative;
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
-.projects-facet-search .note {
position: absolute;
- opacity: 0;
+ bottom: 0;
left: 0;
- bottom: -7px;
- transition: opacity 0.3s ease;
+ width: 300px;
}
-.projects-facet-search input.touched ~ .note {
- opacity: 1;
+.projects-facet-search .note {
+ position: absolute;
+ top: 1px;
+ right: 30px;
+ line-height: 24px;
+ pointer-events: none;
}
.projects-facets-reset {