aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-11-09 10:04:13 +0100
committerStas Vilchik <vilchiks@gmail.com>2016-11-09 15:51:40 +0100
commita2892186843864f467b97a6d3f1a21c3576002bb (patch)
tree8b0ff8452b504057075c6d7c687c0d2f34bee15d /server
parentf662a342d352376b9cc6854e20c58b205f184e45 (diff)
downloadsonarqube-a2892186843864f467b97a6d3f1a21c3576002bb.tar.gz
sonarqube-a2892186843864f467b97a6d3f1a21c3576002bb.zip
SONAR-8360 Add favorite projects filter
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjects.js13
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js50
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js11
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/PageSidebar.js21
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectsList.js14
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectsListFooterContainer.js2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/FilterContainer.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/store/actions.js8
-rw-r--r--server/sonar-web/src/main/js/apps/projects/store/utils.js6
15 files changed, 62 insertions, 84 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 fbbfb11fd56..cc303887e71 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
@@ -21,12 +21,12 @@ import React from 'react';
import ProjectsListContainer from './ProjectsListContainer';
import ProjectsListFooterContainer from './ProjectsListFooterContainer';
import PageSidebar from './PageSidebar';
-import NoProjects from './NoProjects';
import { parseUrlQuery } from '../store/utils';
export default class AllProjects extends React.Component {
static propTypes = {
user: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.bool]),
+ isFavorite: React.PropTypes.bool.isRequired,
fetchProjects: React.PropTypes.func.isRequired
};
@@ -47,7 +47,7 @@ export default class AllProjects extends React.Component {
handleQueryChange () {
const query = parseUrlQuery(this.props.location.query);
this.setState({ query });
- this.props.fetchProjects(query);
+ this.props.fetchProjects(query, this.props.isFavorite);
}
render () {
@@ -55,14 +55,17 @@ export default class AllProjects extends React.Component {
return null;
}
+ const favoriteAndNoFilters = this.props.isFavorite &&
+ !Object.keys(this.state.query).some(key => this.state.query[key] != null);
+
return (
<div className="page-with-sidebar projects-page">
<div className="page-main">
- <ProjectsListContainer noProjectsComponent={<NoProjects/>}/>
- <ProjectsListFooterContainer query={this.state.query}/>
+ <ProjectsListContainer favoriteAndNoFilters={favoriteAndNoFilters}/>
+ <ProjectsListFooterContainer query={this.state.query} isFavorite={this.props.isFavorite}/>
</div>
<aside className="page-sidebar-fixed projects-sidebar">
- <PageSidebar query={this.state.query}/>
+ <PageSidebar query={this.state.query} isFavorite={this.props.isFavorite}/>
</aside>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js
index 5201152e943..d003248d72c 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.js
@@ -23,7 +23,8 @@ import { fetchProjects } from '../store/actions';
import { getCurrentUser } from '../../../app/store/rootReducer';
const mapStateToProps = state => ({
- user: getCurrentUser(state)
+ user: getCurrentUser(state),
+ isFavorite: false
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js b/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js
deleted file mode 100644
index 4c45ed601f8..00000000000
--- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import ProjectsListContainer from './ProjectsListContainer';
-import NoFavoriteProjects from './NoFavoriteProjects';
-
-export default class FavoriteProjects extends React.Component {
- static propTypes = {
- user: React.PropTypes.object,
- fetchFavoriteProjects: React.PropTypes.func.isRequired
- };
-
- componentDidMount () {
- this.props.fetchFavoriteProjects();
- }
-
- render () {
- if (!this.props.user) {
- return null;
- }
-
- return (
- <div className="page-with-sidebar">
- <div className="page-main">
- <div className="projects-list-container">
- <ProjectsListContainer noProjectsComponent={<NoFavoriteProjects/>}/>
- </div>
- </div>
- <aside className="page-sidebar-fixed projects-sidebar"/>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js b/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js
index d78dafbcf42..3e383549f3e 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js
@@ -18,15 +18,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-import FavoriteProjects from './FavoriteProjects';
-import { fetchFavoriteProjects } from '../store/actions';
+import AllProjects from './AllProjects';
+import { fetchProjects } from '../store/actions';
import { getCurrentUser } from '../../../app/store/rootReducer';
const mapStateToProps = state => ({
- user: getCurrentUser(state)
+ user: getCurrentUser(state),
+ isFavorite: true
});
export default connect(
mapStateToProps,
- { fetchFavoriteProjects }
-)(FavoriteProjects);
+ { fetchProjects }
+)(AllProjects);
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 2f44ca9798e..811330c3a55 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
@@ -30,18 +30,21 @@ import { translate } from '../../../helpers/l10n';
export default class PageSidebar extends React.Component {
static propTypes = {
- query: React.PropTypes.object.isRequired
+ query: React.PropTypes.object.isRequired,
+ isFavorite: React.PropTypes.bool.isRequired
};
render () {
const isFiltered = Object.keys(this.props.query).some(key => this.props.query[key] != null);
+ const pathname = this.props.isFavorite ? '/projects/favorite' : '/projects';
+
return (
<div className="search-navigator-facets-list">
<div className="projects-facets-header clearfix">
{isFiltered && (
<div className="projects-facets-reset">
- <Link to="/projects" className="button button-red">
+ <Link to={pathname} className="button button-red">
{translate('projects.clear_all_filters')}
</Link>
</div>
@@ -50,13 +53,13 @@ export default class PageSidebar extends React.Component {
<h3>{translate('filters')}</h3>
</div>
- <QualityGateFilter query={this.props.query}/>
- <ReliabilityFilter query={this.props.query}/>
- <SecurityFilter query={this.props.query}/>
- <MaintainabilityFilter query={this.props.query}/>
- <CoverageFilter query={this.props.query}/>
- <DuplicationsFilter query={this.props.query}/>
- <SizeFilter query={this.props.query}/>
+ <QualityGateFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <ReliabilityFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <SecurityFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <MaintainabilityFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <CoverageFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <DuplicationsFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
+ <SizeFilter query={this.props.query} isFavorite={this.props.isFavorite}/>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.js
index 53e20cbd615..76274465b25 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.js
@@ -19,13 +19,23 @@
*/
import React from 'react';
import ProjectCardContainer from './ProjectCardContainer';
+import NoProjects from './NoProjects';
+import NoFavoriteProjects from './NoFavoriteProjects';
export default class ProjectsList extends React.Component {
static propTypes = {
projects: React.PropTypes.arrayOf(React.PropTypes.string),
- noProjectsComponent: React.PropTypes.element.isRequired
+ favoriteAndNoFilters: React.PropTypes.bool.isRequired
};
+ renderNoProjects () {
+ return this.props.favoriteAndNoFilters ? (
+ <NoFavoriteProjects/>
+ ) : (
+ <NoProjects/>
+ );
+ }
+
render () {
const { projects } = this.props;
@@ -40,7 +50,7 @@ export default class ProjectsList extends React.Component {
<ProjectCardContainer key={projectKey} projectKey={projectKey}/>
))
) : (
- this.props.noProjectsComponent
+ this.renderNoProjects()
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsListFooterContainer.js b/server/sonar-web/src/main/js/apps/projects/components/ProjectsListFooterContainer.js
index d30f699c723..210b4312b9c 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsListFooterContainer.js
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsListFooterContainer.js
@@ -33,7 +33,7 @@ const mapStateToProps = state => {
};
const mapDispatchToProps = (dispatch, ownProps) => ({
- loadMore: () => dispatch(fetchMoreProjects(ownProps.query))
+ loadMore: () => dispatch(fetchMoreProjects(ownProps.query, ownProps.isFavorite))
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
index ae0a6ac54d5..04cdd0e6f28 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/CoverageFilter.js
@@ -47,7 +47,8 @@ export default class CoverageFilter extends React.Component {
renderName={() => 'Coverage'}
renderOption={this.renderOption}
getFacetValueForOption={this.getFacetValueForOption}
- query={this.props.query}/>
+ query={this.props.query}
+ isFavorite={this.props.isFavorite}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
index 18be81714ed..2c3788bb0b3 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/DuplicationsFilter.js
@@ -47,7 +47,8 @@ export default class DuplicationsFilter extends React.Component {
renderName={() => 'Duplications'}
renderOption={this.renderOption}
getFacetValueForOption={this.getFacetValueForOption}
- query={this.props.query}/>
+ query={this.props.query}
+ isFavorite={this.props.isFavorite}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/FilterContainer.js b/server/sonar-web/src/main/js/apps/projects/filters/FilterContainer.js
index 7f030717c34..e943a6b2847 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/FilterContainer.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/FilterContainer.js
@@ -29,8 +29,9 @@ const mapStateToProps = (state, ownProps) => ({
facet: getProjectsAppFacetByProperty(state, ownProps.property),
maxFacetValue: getProjectsAppMaxFacetValue(state),
getFilterUrl: part => {
+ const pathname = ownProps.isFavorite ? '/projects/favorite': '/projects';
const query = omitBy({ ...ownProps.query, ...part }, isNil);
- return { pathname: '/projects', query };
+ return { pathname, query };
}
});
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.js
index f3d76b6c6ae..e66902fc776 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/IssuesFilter.js
@@ -45,7 +45,8 @@ export default class IssuesFilter extends React.Component {
renderName={() => this.props.name}
renderOption={this.renderOption}
getFacetValueForOption={this.getFacetValueForOption}
- query={this.props.query}/>
+ query={this.props.query}
+ isFavorite={this.props.isFavorite}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
index e18f964a472..cd9139af45c 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/QualityGateFilter.js
@@ -40,7 +40,8 @@ export default class QualityGateFilter extends React.Component {
renderName={() => 'Quality Gate'}
renderOption={this.renderOption}
getFacetValueForOption={this.getFacetValueForOption}
- query={this.props.query}/>
+ query={this.props.query}
+ isFavorite={this.props.isFavorite}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.js b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.js
index 6ad997e09d5..48670902644 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.js
+++ b/server/sonar-web/src/main/js/apps/projects/filters/SizeFilter.js
@@ -47,7 +47,8 @@ export default class SizeFilter extends React.Component {
renderName={() => 'Size'}
renderOption={this.renderOption}
getFacetValueForOption={this.getFacetValueForOption}
- query={this.props.query}/>
+ query={this.props.query}
+ isFavorite={this.props.isFavorite}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/store/actions.js b/server/sonar-web/src/main/js/apps/projects/store/actions.js
index 922400ead59..76c3cf13210 100644
--- a/server/sonar-web/src/main/js/apps/projects/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/projects/store/actions.js
@@ -113,22 +113,22 @@ const onReceiveMoreProjects = dispatch => response => {
dispatch(updateState({ pageIndex: response.paging.pageIndex }));
};
-export const fetchProjects = query => dispatch => {
+export const fetchProjects = (query, isFavorite) => dispatch => {
dispatch(updateState({ loading: true }));
const data = { ps: PAGE_SIZE, facets: FACETS.join() };
- const filter = convertToFilter(query);
+ const filter = convertToFilter(query, isFavorite);
if (filter) {
data.filter = filter;
}
return searchProjects(data).then(onReceiveProjects(dispatch), onFail(dispatch));
};
-export const fetchMoreProjects = query => (dispatch, getState) => {
+export const fetchMoreProjects = (query, isFavorite) => (dispatch, getState) => {
dispatch(updateState({ loading: true }));
const state = getState();
const { pageIndex } = getProjectsAppState(state);
const data = { ps: PAGE_SIZE, p: pageIndex + 1 };
- const filter = convertToFilter(query);
+ const filter = convertToFilter(query, isFavorite);
if (filter) {
data.filter = filter;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/store/utils.js b/server/sonar-web/src/main/js/apps/projects/store/utils.js
index 9ed9dd74ef4..37c42077d5d 100644
--- a/server/sonar-web/src/main/js/apps/projects/store/utils.js
+++ b/server/sonar-web/src/main/js/apps/projects/store/utils.js
@@ -101,9 +101,13 @@ const convertSize = size => {
}
};
-export const convertToFilter = query => {
+export const convertToFilter = (query, isFavorite) => {
const conditions = [];
+ if (isFavorite) {
+ conditions.push('isFavorite');
+ }
+
if (query['gate'] != null) {
conditions.push('alert_status = ' + query['gate']);
}