import it.Category1Suite;
import java.util.Iterator;
import javax.mail.internet.MimeMessage;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
+
+import org.junit.*;
import org.sonar.wsclient.Sonar;
import org.sonar.wsclient.qualitygate.NewCondition;
import org.sonar.wsclient.qualitygate.QualityGate;
}
@Test
+ @Ignore("waiting for SONAR-7230")
public void status_on_metric_variation_and_send_notifications() throws Exception {
Wiser smtpServer = new Wiser(NetworkUtils.getNextAvailablePort());
try {
--- /dev/null
+/*
+ * 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.
+ */
+package it.user;
+
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.selenium.Selenese;
+import it.Category1Suite;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.wsclient.SonarClient;
+import org.sonar.wsclient.user.UserParameters;
+import util.selenium.SeleneseTest;
+
+public class MyAccountPageTest {
+
+ @ClassRule
+ public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;
+
+ @BeforeClass
+ public static void initUser() {
+ createUser("account-user", "User With Account", "user@example.com");
+ }
+
+ @AfterClass
+ public static void deleteTestUser() {
+ deactivateUser("account-user");
+ }
+
+ @Test
+ public void should_display_user_details() throws Exception {
+ Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("should_display_user_details",
+ "/user/MyAccountPageTest/should_display_user_details.html"
+ ).build();
+ new SeleneseTest(selenese).runOn(orchestrator);
+ }
+
+ private static void createUser(String login, String name, String email) {
+ SonarClient client = orchestrator.getServer().adminWsClient();
+ UserParameters userCreationParameters = UserParameters.create()
+ .login(login)
+ .name(name)
+ .email(email)
+ .password("password")
+ .passwordConfirmation("password");
+ client.userClient().create(userCreationParameters);
+ }
+
+ private static void deactivateUser(String user) {
+ orchestrator.getServer().adminWsClient().userClient().deactivate(user);
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <link rel="selenium.base" href="http://localhost:49506"/>
+ <title>should_display_user_details</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <thead>
+ <tr>
+ <td rowspan="1" colspan="3">should_display_user_details</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sonar/sessions/login</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>login</td>
+ <td>account-user</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>password</td>
+ <td>password</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/sonar/account/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=name</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>id=name</td>
+ <td>*User With Account*</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=login</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>id=login</td>
+ <td>*account-user*</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=email</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>id=email</td>
+ <td>*user@example.com*</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=groups</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>id=groups</td>
+ <td>*sonar-users*</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=scm-accounts</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>id=scm-accounts</td>
+ <td>*user@example.com*</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>css=#avatar img</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=favorite-components</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=favorite-issue-filters</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>id=favorite-measure-filters</td>
+ <td></td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
return { issues: r.total, debt: r.debtTotal };
});
}
+
+export function getIssueFilters () {
+ const url = window.baseUrl + '/api/issue_filters/search';
+ return getJSON(url).then(r => r.issueFilters);
+}
* 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 Backbone from 'backbone';
-import ChangePasswordView from './change-password-view';
-import TokensView from './tokens-view';
-import avatarHelper from '../../helpers/handlebars/avatarHelper';
-
-var shouldShowAvatars = window.SS && window.SS.lf && window.SS.lf.enableGravatar;
-var favorites = $('.js-account-favorites tr');
-
-function showExtraFavorites () {
- favorites.removeClass('hidden');
-}
-
-class App {
- start () {
- $('html').addClass('dashboard-page');
-
- if (shouldShowAvatars) {
- var avatarHtml = avatarHelper(window.SS.userEmail, 100).string;
- $('.js-avatar').html(avatarHtml);
- }
-
- $('.js-show-all-favorites').on('click', function (e) {
- e.preventDefault();
- $(e.currentTarget).hide();
- showExtraFavorites();
- });
-
- $('#account-change-password-trigger').on('click', function (e) {
- e.preventDefault();
- new ChangePasswordView().render();
- });
-
- const account = new Backbone.Model({
- id: window.SS.user
- });
-
- new TokensView({
- el: '#account-tokens',
- model: account
- }).render();
- }
-}
-
-window.sonarqube.appStarted.then(options => new App().start(options));
+import React from 'react';
+import { render } from 'react-dom';
+import { Router, Route, IndexRoute, Redirect } from 'react-router';
+import { createHistory, useBasename } from 'history';
+
+import AccountApp from './containers/AccountApp';
+import Home from './components/Home';
+import Notifications from './components/Notifications';
+
+window.sonarqube.appStarted.then(options => {
+ const el = document.querySelector(options.el);
+
+ const history = useBasename(createHistory)({
+ basename: window.baseUrl + '/account'
+ });
+
+ document.querySelector('html').classList.add('dashboard-page');
+ document.querySelector('#container').classList.add('page-wrapper-context');
+
+ render((
+ <Router history={history}>
+ <Route path="/" component={AccountApp}>
+ <IndexRoute component={Home}/>
+
+ <Redirect from="/index" to="/"/>
+ </Route>
+ </Router>
+ ), el);
+});
--- /dev/null
+/*
+ * 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 { translate } from '../../../helpers/l10n';
+
+const FavoriteIssueFilters = ({ issueFilters }) => (
+ <section className="big-spacer-bottom">
+ <h2 className="spacer-bottom">
+ {translate('my_account.favorite_issue_filters')}
+ </h2>
+ <table id="favorite-issue-filters" className="data">
+ <tbody>
+ {issueFilters.map(f => (
+ <tr key={f.name}>
+ <td className="thin">
+ <i className="icon-favorite"/>
+ </td>
+ <td>
+ <a href={`${window.baseUrl}/issues/search#id=${f.id}`}>
+ {f.name}
+ </a>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ </section>
+);
+
+export default FavoriteIssueFilters;
--- /dev/null
+/*
+ * 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 { translate } from '../../../helpers/l10n';
+
+const FavoriteMeasureFilters = ({ measureFilters }) => (
+ <section className="big-spacer-bottom">
+ <h2 className="spacer-bottom">
+ {translate('my_account.favorite_measure_filters')}
+ </h2>
+ <table id="favorite-measure-filters" className="data">
+ <tbody>
+ {measureFilters.map(f => (
+ <tr key={f.name}>
+ <td className="thin">
+ <i className="icon-favorite"/>
+ </td>
+ <td>
+ <a href={`${window.baseUrl}/measures/filter/${f.id}`}>
+ {f.name}
+ </a>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ </section>
+);
+
+export default FavoriteMeasureFilters;
--- /dev/null
+/*
+ * 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 Favorite from '../../../components/shared/favorite';
+import QualifierIcon from '../../../components/shared/qualifier-icon';
+import { translate } from '../../../helpers/l10n';
+import { getComponentUrl } from '../../../helpers/urls';
+
+const Favorites = ({ favorites }) => (
+ <section className="big-spacer-bottom">
+ <h2 className="spacer-bottom">
+ {translate('my_account.favorite_components')}
+ </h2>
+ <table id="favorite-components" className="data">
+ <tbody>
+ {favorites.map(f => (
+ <tr key={f.key}>
+ <td className="thin">
+ <Favorite component={f.key} favorite={true}/>
+ </td>
+ <td>
+ <a href={getComponentUrl(f.key)} className="link-with-icon">
+ <QualifierIcon qualifier={f.qualifier}/>
+ {' '}
+ <span>{f.name}</span>
+ </a>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ </section>
+);
+
+export default Favorites;
--- /dev/null
+/*
+ * 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 UserCard from './UserCard';
+import Favorites from './Favorites';
+import FavoriteIssueFilters from './FavoriteIssueFilters';
+import FavoriteMeasureFilters from './FavoriteMeasureFilters';
+
+const Home = ({ user, favorites, issueFilters, measureFilters }) => (
+ <div>
+ <UserCard user={user}/>
+ <div className="overflow-hidden">
+ <Favorites favorites={favorites}/>
+ {issueFilters && <FavoriteIssueFilters issueFilters={issueFilters}/>}
+ {measureFilters && <FavoriteMeasureFilters measureFilters={measureFilters}/>}
+ </div>
+ </div>
+);
+
+export default Home;
--- /dev/null
+/*
+ * 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 } from 'react-router';
+
+import { translate } from '../../../helpers/l10n';
+
+const Nav = () => (
+ <nav className="navbar navbar-context page-container">
+ <div className="container">
+ <ul className="nav navbar-nav nav-crumbs">
+ <li>
+ <IndexLink to="/" activeClassName="active">
+ {translate('my_account.page')}
+ </IndexLink>
+ </li>
+ </ul>
+ <ul className="nav navbar-nav nav-tabs">
+ <li>
+ <IndexLink to="/" activeClassName="active">
+ <i className="icon-home"/>
+ </IndexLink>
+ </li>
+ </ul>
+ </div>
+ </nav>
+);
+
+export default Nav;
--- /dev/null
+/*
+ * 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';
+
+const Notifications = () => (
+ <h1>Notifications</h1>
+);
+
+export default Notifications;
--- /dev/null
+/*
+ * 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 Avatar from '../../../components/shared/avatar';
+import { translate } from '../../../helpers/l10n';
+
+const UserCard = ({ user }) => (
+ <div className="pull-left big-spacer-right abs-width-240">
+ <div className="panel panel-white">
+ <div className="text-center">
+ <div id="avatar" className="big-spacer-bottom">
+ <Avatar email={user.email} size={100}/>
+ </div>
+ <h2 id="name" className="text-ellipsis" title={user.name}>{user.name}</h2>
+ <p id="login" className="note text-ellipsis" title={user.login}>{user.login}</p>
+ <div className="text-center spacer-top">
+ <p id="email" className="text-ellipsis" title={user.email}>{user.email}</p>
+ </div>
+ </div>
+
+ <div className="big-spacer-top">
+ <h3 className="text-center">{translate('my_profile.groups')}</h3>
+ <ul id="groups">
+ {user.groups.map(group => (
+ <li key={group} className="text-ellipsis" title={group}>{group}</li>
+ ))}
+ </ul>
+ </div>
+
+ <div className="big-spacer-top">
+ <h3 className="text-center">{translate('my_profile.scm_accounts')}</h3>
+ <ul id="scm-accounts">
+ {user.scmAccounts.map(scmAccount => (
+ <li key={scmAccount} className="text-ellipsis" title={scmAccount}>{scmAccount}</li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ </div>
+);
+
+export default UserCard;
--- /dev/null
+/*
+ * 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, cloneElement } from 'react';
+
+import Nav from '../components/Nav';
+import { getIssueFilters } from '../../../api/issues';
+
+export default class AccountApp extends Component {
+ state = {}
+
+ componentDidMount () {
+ this.fetchFavoriteIssueFilters();
+ }
+
+ fetchFavoriteIssueFilters () {
+ getIssueFilters().then(issueFilters => {
+ this.setState({ issueFilters });
+ });
+ }
+
+ render () {
+ const { user } = window.sonarqube;
+ const { favorites } = user;
+ const { issueFilters } = this.state;
+ const children = cloneElement(this.props.children, {
+ measureFilters: user.favoriteMeasureFilters,
+ user,
+ favorites,
+ issueFilters
+ });
+
+ return (
+ <div>
+ <Nav/>
+ <div className="page">
+ {children}
+ </div>
+ </div>
+ );
+ }
+}
</a>
<ul className="dropdown-menu dropdown-menu-right">
<li>
- <a href={`${window.baseUrl}/account/index`}>{translate('layout.user_panel.my_profile')}</a>
+ <a href={`${window.baseUrl}/account/`}>{translate('my_account.page')}</a>
</li>
<li>
<a onClick={this.handleLogout} href="#">{translate('layout.logout')}</a>
}
}
- > li.active > a {
+ > li.active > a,
+ > li > a.active {
border-color: @blue;
}
}
}
.icon-star-favorite {
- animation: spin-star .6s forwards;
+
}
.icon-star-favorite path {
before_filter :login_required
def index
+
+ end
+
+ def notifications
@channels = notification_service.getChannels()
@global_dispatchers = dispatchers_for_scope("globalNotification")
@per_project_dispatchers = dispatchers_for_scope("perProjectNotification")
-
+
@global_notifications = {}
@per_project_notifications = {}
load_notification_properties
-
+
if params[:new_project]
new_project = Project.by_key params[:new_project]
unless @per_project_notifications[new_project.id]
end
end
end
-
+
# New project added
new_params = {}
unless params[:new_project].blank?
new_params[:new_project] = params[:new_project]
end
-
+
redirect_to :action => 'index', :params => new_params
end
-
+
private
def notification_service
java_facade.getCoreComponentByClassname('org.sonar.server.notification.NotificationCenter')
end
-
+
def dispatchers_for_scope(scope)
notification_service.getDispatcherKeysForProperty(scope, "true").to_a.sort {|x,y| dispatcher_name(x) <=> dispatcher_name(y)}
end
-
+
def dispatcher_name(dispatcher_key)
Api::Utils.message('notification.dispatcher.' + dispatcher_key)
end
-
+
def load_notification_properties
channel_keys = @channels.map {|c| c.getKey()}
-
+
Property.find(:all, :conditions => ['prop_key like ? AND user_id = ?', 'notification.%', current_user.id]).each do |property|
r_id = property.resource_id
if r_id
end
project_notifs
end
-
+
def init_project_notifications
project_notifs = {}
@per_project_dispatchers.each do |dispatcher|
-<div class="page">
-
- <div class="pull-left big-spacer-right abs-width-240">
- <div class="panel panel-white">
- <div class="text-center">
- <% if configuration('sonar.lf.enableGravatar', 'true') == 'true' %>
- <div class="js-avatar big-spacer-bottom"></div>
- <% end %>
- <h2 id="name" class="text-ellipsis" title="<%= current_user.name -%>"><%= current_user.name -%></h2>
- <p id="login" class="note text-ellipsis" title="<%= current_user.login -%>"><%= current_user.login -%></p>
- <div class="text-center spacer-top">
- <p id="email" class="text-ellipsis" title="<%= current_user.email -%>"><%= current_user.email -%></p>
- </div>
- </div>
-
- <div class="big-spacer-top">
- <h3 class="text-center"><%= message('my_profile.groups') -%></h3>
- <ul id="groups">
- <% current_user.groups.sort.each do |group| -%>
- <li class="text-ellipsis" title="<%= group.name -%>"><%= group.name -%></li>
- <% end -%>
- </ul>
- </div>
-
- <div class="big-spacer-top">
- <h3 class="text-center"><%= message('my_profile.scm_accounts') -%></h3>
- <ul id="scm-accounts">
- <% current_user.full_scm_accounts.each do |scm_account| -%>
- <li class="text-ellipsis" title="<%= scm_account -%>"><%= scm_account -%></li>
- <% end -%>
- </ul>
- </div>
-
- <% if User.editable_password? %>
- <div class="big-spacer-top text-center">
- <button id="account-change-password-trigger">
- <i class="icon-lock"></i> <%= message('my_profile.password.title') -%>
- </button>
- </div>
- <% end %>
- </div>
- </div>
-
- <div class="overflow-hidden">
- <% unless current_user.favourites.empty? -%>
- <section class="big-spacer-bottom">
- <%= render "account/favorites" -%>
- </section>
- <% end %>
-
- <form id="notif_form" method="post" action="<%= ApplicationController.root_context -%>/account/update_notifications">
- <% unless @global_dispatchers.empty? -%>
- <section class="big-spacer-bottom">
- <%= render "account/global_notifications" -%>
- </section>
- <% end %>
-
- <% unless @per_project_dispatchers.empty? -%>
- <section>
- <%= render "account/per_project_notifications" -%>
- </section>
- <% end %>
-
- <section class="big-spacer-top">
- <input type="submit" value="<%= message('my_profile.notifications.submit') -%>" name="commit">
- </section>
- </form>
-
- <section id="account-tokens" class="huge-spacer-top spacer-bottom"></section>
- </div>
-</div>
-
<% content_for :extra_script do %>
+ <script>
+ window.sonarqube.user = {
+ login: '<%= escape_javascript current_user.login -%>',
+ name: '<%= escape_javascript current_user.name -%>',
+ email: '<%= escape_javascript current_user.email -%>',
+ groups: [
+ <% current_user.groups.sort.each do |group| -%>
+ '<%= escape_javascript group.name -%>',
+ <% end -%>
+ ],
+ scmAccounts: [
+ <% current_user.full_scm_accounts.sort.each do |scm_account| -%>
+ '<%= escape_javascript scm_account -%>',
+ <% end -%>
+ ],
+ favorites: [
+ <% current_user.favourites.each_with_index do |f, index| %>
+ {
+ id: '<%= escape_javascript f.uuid -%>',
+ key: '<%= escape_javascript f.key -%>',
+ name: '<%= escape_javascript f.name -%>',
+ qualifier: '<%= escape_javascript f.qualifier -%>'
+ },
+ <% end %>
+ ],
+ favoriteMeasureFilters: [
+ <% current_user.favourited_measure_filters.each do |filter| %>
+ {
+ id: <%= filter.id -%>,
+ name: '<%= escape_javascript filter.name -%>'
+ },
+ <% end %>
+ ]
+ };
+ </script>
<script src="<%= ApplicationController.root_context -%>/js/bundles/account.js?v=<%= sonar_version -%>"></script>
<% end %>
--- /dev/null
+<div class="page">
+
+ <div class="pull-left big-spacer-right abs-width-240">
+ <div class="panel panel-white">
+ <div class="text-center">
+ <% if configuration('sonar.lf.enableGravatar', 'true') == 'true' %>
+ <div class="js-avatar big-spacer-bottom"></div>
+ <% end %>
+ <h2 id="name" class="text-ellipsis" title="<%= current_user.name -%>"><%= current_user.name -%></h2>
+ <p id="login" class="note text-ellipsis" title="<%= current_user.login -%>"><%= current_user.login -%></p>
+ <div class="text-center spacer-top">
+ <p id="email" class="text-ellipsis" title="<%= current_user.email -%>"><%= current_user.email -%></p>
+ </div>
+ </div>
+
+ <div class="big-spacer-top">
+ <h3 class="text-center"><%= message('my_profile.groups') -%></h3>
+ <ul id="groups">
+ <% current_user.groups.sort.each do |group| -%>
+ <li class="text-ellipsis" title="<%= group.name -%>"><%= group.name -%></li>
+ <% end -%>
+ </ul>
+ </div>
+
+ <div class="big-spacer-top">
+ <h3 class="text-center"><%= message('my_profile.scm_accounts') -%></h3>
+ <ul id="scm-accounts">
+ <% current_user.full_scm_accounts.each do |scm_account| -%>
+ <li class="text-ellipsis" title="<%= scm_account -%>"><%= scm_account -%></li>
+ <% end -%>
+ </ul>
+ </div>
+
+ <% if User.editable_password? %>
+ <div class="big-spacer-top text-center">
+ <button id="account-change-password-trigger">
+ <i class="icon-lock"></i> <%= message('my_profile.password.title') -%>
+ </button>
+ </div>
+ <% end %>
+ </div>
+ </div>
+
+ <div class="overflow-hidden">
+ <% unless current_user.favourites.empty? -%>
+ <section class="big-spacer-bottom">
+ <%= render "account/favorites" -%>
+ </section>
+ <% end %>
+
+ <form id="notif_form" method="post" action="<%= ApplicationController.root_context -%>/account/update_notifications">
+ <% unless @global_dispatchers.empty? -%>
+ <section class="big-spacer-bottom">
+ <%= render "account/global_notifications" -%>
+ </section>
+ <% end %>
+
+ <% unless @per_project_dispatchers.empty? -%>
+ <section>
+ <%= render "account/per_project_notifications" -%>
+ </section>
+ <% end %>
+
+ <section class="big-spacer-top">
+ <input type="submit" value="<%= message('my_profile.notifications.submit') -%>" name="commit">
+ </section>
+ </form>
+
+ <section id="account-tokens" class="huge-spacer-top spacer-bottom"></section>
+ </div>
+</div>
+
+<% content_for :extra_script do %>
+ <script src="<%= ApplicationController.root_context -%>/js/bundles/account.js?v=<%= sonar_version -%>"></script>
+<% end %>
#------------------------------------------------------------------------------
#
-# MY PROFILE
+# MY PROFILE & MY ACCOUNT
#
#------------------------------------------------------------------------------
my_profile.login=Login
my_profile.remove_this_line=Remove this line
my_profile.favorites.title=Favorites
+my_account.page=My Account
+my_account.favorite_components=Favorite Components
+my_account.favorite_issue_filters=Favorite Issue Filters
+my_account.favorite_measure_filters=Favorite Measure Filters
+
#------------------------------------------------------------------------------