diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2016-11-09 10:04:13 +0100 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2016-11-09 15:51:40 +0100 |
commit | a2892186843864f467b97a6d3f1a21c3576002bb (patch) | |
tree | 8b0ff8452b504057075c6d7c687c0d2f34bee15d /server | |
parent | f662a342d352376b9cc6854e20c58b205f184e45 (diff) | |
download | sonarqube-a2892186843864f467b97a6d3f1a21c3576002bb.tar.gz sonarqube-a2892186843864f467b97a6d3f1a21c3576002bb.zip |
SONAR-8360 Add favorite projects filter
Diffstat (limited to 'server')
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']); } |