From 30575d6712fd317a3aa66f0acba72a3eaf691d31 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Tue, 1 Nov 2016 14:58:49 +0100 Subject: [PATCH] SONAR-8300 display favorite projects --- .../src/main/js/app/store/users/reducer.js | 4 +- .../main/js/apps/projects/components/App.js | 9 ++- .../apps/projects/components/AppContainer.js | 5 +- .../projects/components/FavoriteFilter.js | 36 ++++++++++ .../components/FavoriteFilterContainer.js | 30 ++++++++ .../projects/components/FavoriteProjects.js | 70 +++++++++++++++++++ .../components/FavoriteProjectsContainer.js | 32 +++++++++ .../src/main/js/apps/projects/routes.js | 8 ++- .../main/js/apps/projects/store/actions.js | 22 ++++++ .../src/main/js/apps/projects/styles.css | 12 ++++ .../sonar-web/src/main/less/init/forms.less | 2 +- .../app/controllers/projects_controller.rb | 4 ++ 12 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js create mode 100644 server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.js create mode 100644 server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js create mode 100644 server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js diff --git a/server/sonar-web/src/main/js/app/store/users/reducer.js b/server/sonar-web/src/main/js/app/store/users/reducer.js index dec079465f2..d67d04bfdf7 100644 --- a/server/sonar-web/src/main/js/app/store/users/reducer.js +++ b/server/sonar-web/src/main/js/app/store/users/reducer.js @@ -39,7 +39,7 @@ const userLogins = (state = [], action = {}) => { const currentUser = (state = null, action = {}) => { if (action.type === RECEIVE_CURRENT_USER) { - return action.user.login; + return action.user.isLoggedIn ? action.user.login : false; } return state; @@ -48,5 +48,5 @@ const currentUser = (state = null, action = {}) => { export default combineReducers({ usersByLogin, userLogins, currentUser }); export const getCurrentUser = state => ( - state.currentUser ? state.usersByLogin[state.currentUser] : null + state.currentUser ? state.usersByLogin[state.currentUser] : state.currentUser ); diff --git a/server/sonar-web/src/main/js/apps/projects/components/App.js b/server/sonar-web/src/main/js/apps/projects/components/App.js index c86cd6935df..34d280a228e 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/App.js +++ b/server/sonar-web/src/main/js/apps/projects/components/App.js @@ -23,13 +23,15 @@ import PageHeaderContainer from './PageHeaderContainer'; import ProjectsListContainer from './ProjectsListContainer'; import ProjectsListFooterContainer from './ProjectsListFooterContainer'; import PageSidebarContainer from './PageSidebarContainer'; +import FavoriteFilterContainer from './FavoriteFilterContainer'; import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer'; import { parseUrlQuery } from '../store/utils'; -import '../styles.css'; import { translate } from '../../../helpers/l10n'; +import '../styles.css'; export default class App extends React.Component { static propTypes = { + user: React.PropTypes.object, fetchProjects: React.PropTypes.func.isRequired }; @@ -59,6 +61,10 @@ export default class App extends React.Component { } render () { + if (this.props.user == null) { + return null; + } + return (
@@ -73,6 +79,7 @@ export default class App extends React.Component {
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AppContainer.js b/server/sonar-web/src/main/js/apps/projects/components/AppContainer.js index f2956e0b14a..12a9cd32bbb 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AppContainer.js +++ b/server/sonar-web/src/main/js/apps/projects/components/AppContainer.js @@ -20,8 +20,11 @@ import { connect } from 'react-redux'; import App from './App'; import { fetchProjects } from '../store/actions'; +import { getCurrentUser } from '../../../app/store/rootReducer'; export default connect( - () => ({}), + state => ({ + user: getCurrentUser(state) + }), { fetchProjects } )(App); diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js new file mode 100644 index 00000000000..2ef4f12053e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.js @@ -0,0 +1,36 @@ +/* + * 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 { IndexLink, Link } from 'react-router'; + +export default class FavoriteFilter extends React.Component { + render () { + if (!this.props.user) { + return null; + } + + return ( +
+ All + Favorite +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.js b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.js new file mode 100644 index 00000000000..c6437cf58f9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.js @@ -0,0 +1,30 @@ +/* + * 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 { connect } from 'react-redux'; +import FavoriteFilter from './FavoriteFilter'; +import { getCurrentUser } from '../../../app/store/rootReducer'; + +const mapStateToProps = state => ({ + user: getCurrentUser(state) +}); + +export default connect( + mapStateToProps +)(FavoriteFilter); 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 new file mode 100644 index 00000000000..6503b1e083f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjects.js @@ -0,0 +1,70 @@ +/* + * 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 Helmet from 'react-helmet'; +import PageHeaderContainer from './PageHeaderContainer'; +import ProjectsListContainer from './ProjectsListContainer'; +import FavoriteFilterContainer from './FavoriteFilterContainer'; +import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer'; +import { translate } from '../../../helpers/l10n'; +import '../styles.css'; + +export default class FavoriteProjects extends React.Component { + static propTypes = { + user: React.PropTypes.object, + fetchFavoriteProjects: React.PropTypes.func.isRequired + }; + + componentDidMount () { + document.querySelector('html').classList.add('dashboard-page'); + this.props.fetchFavoriteProjects(); + } + + componentWillUnmount () { + document.querySelector('html').classList.remove('dashboard-page'); + } + + render () { + if (!this.props.user) { + return null; + } + + return ( +
+ + + + + + +
+
+ +
+ +
+
+ ); + } +} 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 new file mode 100644 index 00000000000..d78dafbcf42 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteProjectsContainer.js @@ -0,0 +1,32 @@ +/* + * 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 { connect } from 'react-redux'; +import FavoriteProjects from './FavoriteProjects'; +import { fetchFavoriteProjects } from '../store/actions'; +import { getCurrentUser } from '../../../app/store/rootReducer'; + +const mapStateToProps = state => ({ + user: getCurrentUser(state) +}); + +export default connect( + mapStateToProps, + { fetchFavoriteProjects } +)(FavoriteProjects); diff --git a/server/sonar-web/src/main/js/apps/projects/routes.js b/server/sonar-web/src/main/js/apps/projects/routes.js index b96e7d3651b..cc1ecd10506 100644 --- a/server/sonar-web/src/main/js/apps/projects/routes.js +++ b/server/sonar-web/src/main/js/apps/projects/routes.js @@ -18,9 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import React from 'react'; -import { Route } from 'react-router'; +import { Route, IndexRoute } from 'react-router'; import AppContainer from './components/AppContainer'; +import FavoriteProjectsContainer from './components/FavoriteProjectsContainer'; export default ( - + + + + ); 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 93dbc409a4d..e811bd63279 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 @@ -28,6 +28,8 @@ import { getProjectsAppState } from '../../../app/store/rootReducer'; import { getMeasuresForComponents } from '../../../api/measures'; import { receiveComponentsMeasures } from '../../../app/store/measures/actions'; import { convertToFilter } from './utils'; +import { getFavorites } from '../../../api/favorites'; +import { receiveFavorites } from '../../../app/store/favorites/actions'; const PAGE_SIZE = 50; @@ -124,3 +126,23 @@ export const fetchMoreProjects = query => (dispatch, getState) => { } return searchProjects(data).then(onReceiveMoreProjects(dispatch), onFail(dispatch)); }; + +export const fetchFavoriteProjects = () => dispatch => { + dispatch(updateState({ loading: true })); + + return getFavorites().then(favorites => { + dispatch(receiveFavorites(favorites)); + + const projects = favorites.filter(component => component.qualifier === 'TRK'); + + dispatch(receiveComponents(projects)); + dispatch(receiveProjects(projects, [])); + dispatch(fetchProjectMeasures(projects)).then(() => { + dispatch(updateState({ loading: false })); + }); + dispatch(updateState({ + total: projects.length, + pageIndex: 1, + })); + }, onFail(dispatch)); +}; 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 e1a4cc1245b..cc1105ba0aa 100644 --- a/server/sonar-web/src/main/js/apps/projects/styles.css +++ b/server/sonar-web/src/main/js/apps/projects/styles.css @@ -88,3 +88,15 @@ .projects-facets-reset .button { } + +.projects-favorite-filter { + width: 100%; + margin-bottom: 30px; + padding-left: 10px; + padding-right: 10px; + box-sizing: border-box; +} + +.projects-favorite-filter > a { + width: 50%; +} diff --git a/server/sonar-web/src/main/less/init/forms.less b/server/sonar-web/src/main/less/init/forms.less index 5945dd593b9..4de11a1c3e8 100644 --- a/server/sonar-web/src/main/less/init/forms.less +++ b/server/sonar-web/src/main/less/init/forms.less @@ -107,7 +107,7 @@ input[type=button] { outline: none; transition: border-color 0.2s ease; - &:hover, &:focus { + &:hover, &:focus, &.button-active { background: @darkBlue; color: #fff; } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb index 1174555457f..b1d32b5cc03 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb @@ -23,4 +23,8 @@ class ProjectsController < ApplicationController end + def favorite + render :action => 'index' + end + end -- 2.39.5