From bea2847df13b73c7364193419873e3e8b47b5b73 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Thu, 28 Jan 2016 17:10:59 +0100 Subject: [PATCH] SONAR-7228 Create new "My Issues" page --- .../test/java/it/user/MyAccountPageTest.java | 8 ++ .../should_display_issues.html | 50 +++++++++ .../sonar-web/src/main/js/apps/account/app.js | 2 + .../main/js/apps/account/components/Nav.js | 7 ++ .../js/apps/account/containers/AccountApp.js | 2 +- .../account/containers/IssuesContainer.js | 39 +++++++ .../src/main/js/apps/account/issues-app.js | 104 ++++++++++++++++++ .../main/js/apps/account/styles/account.css | 9 ++ .../js/apps/issues/workspace-list-view.js | 15 ++- .../navigator/workspace-list-view.js | 5 + 10 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 it/it-tests/src/test/resources/user/MyAccountPageTest/should_display_issues.html create mode 100644 server/sonar-web/src/main/js/apps/account/containers/IssuesContainer.js create mode 100644 server/sonar-web/src/main/js/apps/account/issues-app.js diff --git a/it/it-tests/src/test/java/it/user/MyAccountPageTest.java b/it/it-tests/src/test/java/it/user/MyAccountPageTest.java index 5188171ec23..fb4704beba4 100644 --- a/it/it-tests/src/test/java/it/user/MyAccountPageTest.java +++ b/it/it-tests/src/test/java/it/user/MyAccountPageTest.java @@ -66,6 +66,14 @@ public class MyAccountPageTest { new SeleneseTest(selenese).runOn(orchestrator); } + @Test + public void should_display_issues() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("should_display_issues", + "/user/MyAccountPageTest/should_display_issues.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + private static void createUser(String login, String name, String email) { adminWsClient.wsConnector().call( new PostRequest("api/users/create") diff --git a/it/it-tests/src/test/resources/user/MyAccountPageTest/should_display_issues.html b/it/it-tests/src/test/resources/user/MyAccountPageTest/should_display_issues.html new file mode 100644 index 00000000000..090cb4fba15 --- /dev/null +++ b/it/it-tests/src/test/resources/user/MyAccountPageTest/should_display_issues.html @@ -0,0 +1,50 @@ + + + + + + + should_display_issues + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_issues
open/sonar/sessions/login
typeloginaccount-user
typepasswordpassword
clickAndWaitcommit
open/sonar/account/issues
waitForElementPresentcss=[data-unresolved]
+ + diff --git a/server/sonar-web/src/main/js/apps/account/app.js b/server/sonar-web/src/main/js/apps/account/app.js index dc52a4fc013..8004bfda586 100644 --- a/server/sonar-web/src/main/js/apps/account/app.js +++ b/server/sonar-web/src/main/js/apps/account/app.js @@ -28,6 +28,7 @@ import AccountApp from './containers/AccountApp'; import Home from './components/Home'; import NotificationsContainer from './containers/NotificationsContainer'; import SecurityContainer from './containers/SecurityContainer'; +import IssuesContainer from './containers/IssuesContainer'; import './styles/account.css'; @@ -45,6 +46,7 @@ window.sonarqube.appStarted.then(options => { + diff --git a/server/sonar-web/src/main/js/apps/account/components/Nav.js b/server/sonar-web/src/main/js/apps/account/components/Nav.js index fe826c18184..a1fe74bfc0d 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Nav.js +++ b/server/sonar-web/src/main/js/apps/account/components/Nav.js @@ -34,6 +34,13 @@ const Nav = ({ user }) => ( +
  • + + {translate('issues.page')} + +
  • {translate('my_account.notifications')} diff --git a/server/sonar-web/src/main/js/apps/account/containers/AccountApp.js b/server/sonar-web/src/main/js/apps/account/containers/AccountApp.js index f9b06e63044..9559d933640 100644 --- a/server/sonar-web/src/main/js/apps/account/containers/AccountApp.js +++ b/server/sonar-web/src/main/js/apps/account/containers/AccountApp.js @@ -48,7 +48,7 @@ export default class AccountApp extends Component { }); return ( -
    +
    diff --git a/server/sonar-web/src/main/js/apps/account/containers/IssuesContainer.js b/server/sonar-web/src/main/js/apps/account/containers/IssuesContainer.js new file mode 100644 index 00000000000..67e927f3a4e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/account/containers/IssuesContainer.js @@ -0,0 +1,39 @@ +/* + * 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, { Component } from 'react'; + +import IssuesApp from '../issues-app'; + +export default class IssuesContainer extends Component { + componentDidMount () { + this.issuesApp = IssuesApp; + this.issuesApp.start({ + el: this.refs.container + }); + } + + componentWillUnmount () { + this.issuesApp.stop(); + } + + render () { + return
    ; + } +} diff --git a/server/sonar-web/src/main/js/apps/account/issues-app.js b/server/sonar-web/src/main/js/apps/account/issues-app.js new file mode 100644 index 00000000000..25c83b1b14e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/account/issues-app.js @@ -0,0 +1,104 @@ +/* + * 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 $ from 'jquery'; +import _ from 'underscore'; +import Backbone from 'backbone'; +import Marionette from 'backbone.marionette'; +import State from '../issues/models/state'; +import Layout from '../issues/layout'; +import Issues from '../issues/models/issues'; +import Facets from '../../components/navigator/models/facets'; +import Filters from '../issues/models/filters'; +import Controller from '../issues/controller'; +import Router from '../issues/router'; +import WorkspaceListView from '../issues/workspace-list-view'; +import WorkspaceHeaderView from '../issues/workspace-header-view'; +import FacetsView from './../issues/facets-view'; + +var App = new Marionette.Application(), + init = function (options) { + this.config = options.config; + this.state = new State({ + isContext: true, + contextQuery: { assignees: '__me__' } + }); + this.updateContextFacets(); + this.list = new Issues(); + this.facets = new Facets(); + this.filters = new Filters(); + + this.layout = new Layout({ app: this }); + this.layout.$el.appendTo(options.el); + this.layout.render(); + $('#footer').addClass('search-navigator-footer'); + + this.controller = new Controller({ app: this }); + + this.issuesView = new WorkspaceListView({ + app: this, + collection: this.list + }); + this.layout.workspaceListRegion.show(this.issuesView); + this.issuesView.bindScrollEvents(); + + this.workspaceHeaderView = new WorkspaceHeaderView({ + app: this, + collection: this.list + }); + this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView); + + this.facetsView = new FacetsView({ + app: this, + collection: this.facets + }); + this.layout.facetsRegion.show(this.facetsView); + + this.controller.fetchFilters().done(function () { + key.setScope('list'); + App.router = new Router({ app: App }); + Backbone.history.start(); + }); + }; + +App.getContextQuery = function () { + return { assignees: '__me__' }; +}; + +App.updateContextFacets = function () { + var facets = this.state.get('facets'), + allFacets = this.state.get('allFacets'), + facetsFromServer = this.state.get('facetsFromServer'); + return this.state.set({ + facets: facets, + allFacets: _.difference(allFacets, ['assignees']), + facetsFromServer: _.difference(facetsFromServer, ['assignees']) + }); +}; + +App.stop = function () { + App.layout.destroy(); + Backbone.history.stop(); +}; + +App.on('start', function (options) { + init.call(App, options); +}); + +export default App; diff --git a/server/sonar-web/src/main/js/apps/account/styles/account.css b/server/sonar-web/src/main/js/apps/account/styles/account.css index e308d9234bc..4105365b0cb 100644 --- a/server/sonar-web/src/main/js/apps/account/styles/account.css +++ b/server/sonar-web/src/main/js/apps/account/styles/account.css @@ -1,4 +1,9 @@ .account-header { + position: fixed; + top: 30px; + left: 0; + right: 0; + z-index: 420; background-color: #f3f3f3; } @@ -18,3 +23,7 @@ float: left; margin-right: 20px; } + +.account-page { + padding-top: 102px; +} diff --git a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js index 5fb6d6aa92c..6e471a45d12 100644 --- a/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js +++ b/server/sonar-web/src/main/js/apps/issues/workspace-list-view.js @@ -73,11 +73,24 @@ export default WorkspaceListView.extend({ key('c', 'list', function () { return doAction('comment'); }); - return key('t', 'list', function () { + key('t', 'list', function () { return doAction('edit-tags'); }); }, + unbindShortcuts: function () { + WorkspaceListView.prototype.unbindShortcuts.apply(this, arguments); + key.unbind('right', 'list'); + key.unbind('space', 'list'); + key.unbind('f', 'list'); + key.unbind('a', 'list'); + key.unbind('m', 'list'); + key.unbind('p', 'list'); + key.unbind('i', 'list'); + key.unbind('c', 'list'); + key.unbind('t', 'list'); + }, + scrollTo: function () { var selectedIssue = this.collection.at(this.options.app.state.get('selectedIndex')); if (selectedIssue == null) { diff --git a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js index 6017b69ff3b..5069792da09 100644 --- a/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js +++ b/server/sonar-web/src/main/js/components/navigator/workspace-list-view.js @@ -86,6 +86,11 @@ export default Marionette.CompositeView.extend({ }); }, + unbindShortcuts: function () { + key.unbind('up', 'list'); + key.unbind('down', 'list'); + }, + loadMore: function () { if (!this.options.app.state.get('maxResultsReached')) { var that = this; -- 2.39.5