login: string;
password: string;
previousPassword?: string;
-}): Promise<void> {
- return post('/api/users/change_password', data);
+}) {
+ return post('/api/users/change_password', data).catch(throwGlobalError);
}
export interface UserGroup {
}));
const LOGGED_IN_USER: LoggedInUser = {
+ groups: [],
isLoggedIn: true,
login: 'luke',
name: 'Skywalker',
+ scmAccounts: [],
showOnboardingTutorial: false
};
email?: string;
externalIdentity?: string;
externalProvider?: string;
+ groups: string[];
homepage?: HomePage;
isLoggedIn: true;
+ local?: boolean;
login: string;
name: string;
+ scmAccounts: string[];
}
export interface LongLivingBranch extends Branch {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 { connect } from 'react-redux';
-import Helmet from 'react-helmet';
-import Nav from './Nav';
-import UserCard from './UserCard';
-import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';
-import { translate } from '../../../helpers/l10n';
-import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import '../account.css';
-
-class Account extends React.PureComponent {
- componentDidMount() {
- if (!this.props.currentUser.isLoggedIn) {
- handleRequiredAuthentication();
- }
- }
-
- render() {
- const { currentUser, children } = this.props;
-
- if (!currentUser.isLoggedIn) {
- return null;
- }
-
- const title = translate('my_account.page');
- return (
- <div id="account-page">
- <Suggestions suggestions="account" />
- <Helmet defaultTitle={title} titleTemplate={'%s - ' + title} />
- <header className="account-header">
- <div className="account-container clearfix">
- <UserCard user={currentUser} />
- <Nav customOrganizations={this.props.customOrganizations} user={currentUser} />
- </div>
- </header>
-
- {children}
- </div>
- );
- }
-}
-
-const mapStateToProps = state => ({
- currentUser: getCurrentUser(state),
- customOrganizations: areThereCustomOrganizations(state)
-});
-
-export default connect(mapStateToProps)(Account);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { connect } from 'react-redux';
+import Helmet from 'react-helmet';
+import Nav from './Nav';
+import UserCard from './UserCard';
+import { CurrentUser, LoggedInUser } from '../../../app/types';
+import { getCurrentUser, areThereCustomOrganizations, Store } from '../../../store/rootReducer';
+import { translate } from '../../../helpers/l10n';
+import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
+import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
+import '../account.css';
+
+interface Props {
+ currentUser: CurrentUser;
+ customOrganizations?: boolean;
+}
+
+class Account extends React.PureComponent<Props> {
+ componentDidMount() {
+ if (!this.props.currentUser.isLoggedIn) {
+ handleRequiredAuthentication();
+ }
+ }
+
+ render() {
+ const { currentUser, children } = this.props;
+
+ if (!currentUser.isLoggedIn) {
+ return null;
+ }
+
+ const title = translate('my_account.page');
+ return (
+ <div id="account-page">
+ <Suggestions suggestions="account" />
+ <Helmet defaultTitle={title} titleTemplate={'%s - ' + title} />
+ <header className="account-header">
+ <div className="account-container clearfix">
+ <UserCard user={currentUser as LoggedInUser} />
+ <Nav customOrganizations={this.props.customOrganizations} />
+ </div>
+ </header>
+
+ {children}
+ </div>
+ );
+ }
+}
+
+const mapStateToProps = (state: Store) => ({
+ currentUser: getCurrentUser(state),
+ customOrganizations: areThereCustomOrganizations(state)
+});
+
+export default connect(mapStateToProps)(Account);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.
- */
-// @flow
-import React from 'react';
-import { Link, IndexLink } from 'react-router';
-import NavBarTabs from '../../../components/nav/NavBarTabs';
-import { translate } from '../../../helpers/l10n';
-
-/*::
-type Props = {
- customOrganizations: boolean
-};
-*/
-
-export default function Nav({ customOrganizations } /*: Props */) {
- return (
- <nav className="account-nav">
- <NavBarTabs>
- <li>
- <IndexLink activeClassName="active" to="/account/">
- {translate('my_account.profile')}
- </IndexLink>
- </li>
- <li>
- <Link activeClassName="active" to="/account/security/">
- {translate('my_account.security')}
- </Link>
- </li>
- <li>
- <Link activeClassName="active" to="/account/notifications">
- {translate('my_account.notifications')}
- </Link>
- </li>
- {!customOrganizations && (
- <li>
- <Link activeClassName="active" to="/account/projects/">
- {translate('my_account.projects')}
- </Link>
- </li>
- )}
- {customOrganizations && (
- <li>
- <Link activeClassName="active" to="/account/organizations">
- {translate('my_account.organizations')}
- </Link>
- </li>
- )}
- </NavBarTabs>
- </nav>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { Link, IndexLink } from 'react-router';
+import NavBarTabs from '../../../components/nav/NavBarTabs';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ customOrganizations?: boolean;
+}
+
+export default function Nav({ customOrganizations }: Props) {
+ return (
+ <nav className="account-nav">
+ <NavBarTabs>
+ <li>
+ <IndexLink activeClassName="active" to="/account/">
+ {translate('my_account.profile')}
+ </IndexLink>
+ </li>
+ <li>
+ <Link activeClassName="active" to="/account/security/">
+ {translate('my_account.security')}
+ </Link>
+ </li>
+ <li>
+ <Link activeClassName="active" to="/account/notifications">
+ {translate('my_account.notifications')}
+ </Link>
+ </li>
+ {!customOrganizations && (
+ <li>
+ <Link activeClassName="active" to="/account/projects/">
+ {translate('my_account.projects')}
+ </Link>
+ </li>
+ )}
+ {customOrganizations && (
+ <li>
+ <Link activeClassName="active" to="/account/organizations">
+ {translate('my_account.organizations')}
+ </Link>
+ </li>
+ )}
+ </NavBarTabs>
+ </nav>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 { changePassword } from '../../../api/users';
-import { SubmitButton } from '../../../components/ui/buttons';
-import { translate } from '../../../helpers/l10n';
-
-export default class Password extends Component {
- state = {
- success: false,
- errors: null
- };
-
- handleSuccessfulChange = () => {
- this.oldPassword.value = '';
- this.password.value = '';
- this.passwordConfirmation.value = '';
- this.setState({ success: true, errors: null });
- };
-
- handleFailedChange = e => {
- e.response.json().then(r => {
- this.oldPassword.focus();
- this.setErrors(r.errors.map(e => e.msg));
- });
- };
-
- setErrors = errors => {
- this.setState({
- success: false,
- errors
- });
- };
-
- handleChangePassword = e => {
- e.preventDefault();
-
- const { user } = this.props;
- const previousPassword = this.oldPassword.value;
- const password = this.password.value;
- const passwordConfirmation = this.passwordConfirmation.value;
-
- if (password !== passwordConfirmation) {
- this.password.focus();
- this.setErrors([translate('user.password_doesnt_match_confirmation')]);
- } else {
- changePassword({ login: user.login, password, previousPassword })
- .then(this.handleSuccessfulChange)
- .catch(this.handleFailedChange);
- }
- };
-
- render() {
- const { success, errors } = this.state;
-
- return (
- <section className="boxed-group">
- <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
-
- <form className="boxed-group-inner" onSubmit={this.handleChangePassword}>
- {success && (
- <div className="alert alert-success">{translate('my_profile.password.changed')}</div>
- )}
-
- {errors &&
- errors.map((e, i) => (
- <div className="alert alert-danger" key={i}>
- {e}
- </div>
- ))}
-
- <div className="modal-field">
- <label htmlFor="old_password">
- {translate('my_profile.password.old')}
- <em className="mandatory">*</em>
- </label>
- <input
- autoComplete="off"
- id="old_password"
- name="old_password"
- ref={elem => (this.oldPassword = elem)}
- required={true}
- type="password"
- />
- </div>
- <div className="modal-field">
- <label htmlFor="password">
- {translate('my_profile.password.new')}
- <em className="mandatory">*</em>
- </label>
- <input
- autoComplete="off"
- id="password"
- name="password"
- ref={elem => (this.password = elem)}
- required={true}
- type="password"
- />
- </div>
- <div className="modal-field">
- <label htmlFor="password_confirmation">
- {translate('my_profile.password.confirm')}
- <em className="mandatory">*</em>
- </label>
- <input
- autoComplete="off"
- id="password_confirmation"
- name="password_confirmation"
- ref={elem => (this.passwordConfirmation = elem)}
- required={true}
- type="password"
- />
- </div>
- <div className="modal-field">
- <SubmitButton id="change-password">
- {translate('my_profile.password.submit')}
- </SubmitButton>
- </div>
- </form>
- </section>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { changePassword } from '../../../api/users';
+import { SubmitButton } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+import { LoggedInUser } from '../../../app/types';
+
+interface Props {
+ user: LoggedInUser;
+}
+
+interface State {
+ errors?: string[];
+ success: boolean;
+}
+
+export default class Password extends React.Component<Props, State> {
+ oldPassword!: HTMLInputElement;
+ password!: HTMLInputElement;
+ passwordConfirmation!: HTMLInputElement;
+ state: State = {
+ success: false
+ };
+
+ handleSuccessfulChange = () => {
+ this.oldPassword.value = '';
+ this.password.value = '';
+ this.passwordConfirmation.value = '';
+ this.setState({ success: true, errors: undefined });
+ };
+
+ setErrors = (errors: string[]) => {
+ this.setState({ success: false, errors });
+ };
+
+ handleChangePassword = (event: React.FormEvent) => {
+ event.preventDefault();
+
+ const { user } = this.props;
+ const previousPassword = this.oldPassword.value;
+ const password = this.password.value;
+ const passwordConfirmation = this.passwordConfirmation.value;
+
+ if (password !== passwordConfirmation) {
+ this.password.focus();
+ this.setErrors([translate('user.password_doesnt_match_confirmation')]);
+ } else {
+ changePassword({ login: user.login, password, previousPassword }).then(
+ this.handleSuccessfulChange,
+ () => {}
+ );
+ }
+ };
+
+ render() {
+ const { success, errors } = this.state;
+
+ return (
+ <section className="boxed-group">
+ <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
+
+ <form className="boxed-group-inner" onSubmit={this.handleChangePassword}>
+ {success && (
+ <div className="alert alert-success">{translate('my_profile.password.changed')}</div>
+ )}
+
+ {errors &&
+ errors.map((e, i) => (
+ <div className="alert alert-danger" key={i}>
+ {e}
+ </div>
+ ))}
+
+ <div className="modal-field">
+ <label htmlFor="old_password">
+ {translate('my_profile.password.old')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoComplete="off"
+ id="old_password"
+ name="old_password"
+ ref={elem => (this.oldPassword = elem!)}
+ required={true}
+ type="password"
+ />
+ </div>
+ <div className="modal-field">
+ <label htmlFor="password">
+ {translate('my_profile.password.new')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoComplete="off"
+ id="password"
+ name="password"
+ ref={elem => (this.password = elem!)}
+ required={true}
+ type="password"
+ />
+ </div>
+ <div className="modal-field">
+ <label htmlFor="password_confirmation">
+ {translate('my_profile.password.confirm')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoComplete="off"
+ id="password_confirmation"
+ name="password_confirmation"
+ ref={elem => (this.passwordConfirmation = elem!)}
+ required={true}
+ type="password"
+ />
+ </div>
+ <div className="modal-field">
+ <SubmitButton id="change-password">
+ {translate('my_profile.password.submit')}
+ </SubmitButton>
+ </div>
+ </form>
+ </section>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 { connect } from 'react-redux';
-import Password from './Password';
-import Tokens from './Tokens';
-import { translate } from '../../../helpers/l10n';
-import { getCurrentUser } from '../../../store/rootReducer';
-
-function Security(props) {
- const { user } = props;
-
- return (
- <div className="account-body account-container">
- <Helmet title={translate('my_account.security')} />
- <Tokens login={user.login} />
- {user.local && <Password user={user} />}
- </div>
- );
-}
-
-export default connect(state => ({ user: getCurrentUser(state) }))(Security);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import Helmet from 'react-helmet';
+import { connect } from 'react-redux';
+import Password from './Password';
+import Tokens from './Tokens';
+import { translate } from '../../../helpers/l10n';
+import { getCurrentUser, Store } from '../../../store/rootReducer';
+import { LoggedInUser } from '../../../app/types';
+
+interface Props {
+ user: LoggedInUser;
+}
+
+function Security({ user }: Props) {
+ return (
+ <div className="account-body account-container">
+ <Helmet title={translate('my_account.security')} />
+ <Tokens login={user.login} />
+ {user.local && <Password user={user} />}
+ </div>
+ );
+}
+
+const mapStateToProps = (state: Store) => ({
+ user: getCurrentUser(state) as LoggedInUser
+});
+
+export default connect(mapStateToProps)(Security);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 PropTypes from 'prop-types';
-import Avatar from '../../../components/ui/Avatar';
-
-export default class UserCard extends React.PureComponent {
- static propTypes = {
- user: PropTypes.object.isRequired
- };
-
- render() {
- const { user } = this.props;
-
- return (
- <div className="account-user">
- <div className="pull-left account-user-avatar" id="avatar">
- <Avatar hash={user.avatar} name={user.name} size={60} />
- </div>
- <h1 className="pull-left" id="name">
- {user.name}
- </h1>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import Avatar from '../../../components/ui/Avatar';
+import { LoggedInUser } from '../../../app/types';
+
+interface Props {
+ user: LoggedInUser;
+}
+
+export default function UserCard({ user }: Props) {
+ return (
+ <div className="account-user">
+ <div className="pull-left account-user-avatar" id="avatar">
+ <Avatar hash={user.avatar} name={user.name} size={60} />
+ </div>
+ <h1 className="pull-left" id="name">
+ {user.name}
+ </h1>
+ </div>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.
- */
-// @flow
-import React from 'react';
-import { connect } from 'react-redux';
-import UserExternalIdentity from './UserExternalIdentity';
-import UserGroups from './UserGroups';
-import UserScmAccounts from './UserScmAccounts';
-import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';
-import { translate } from '../../../helpers/l10n';
-
-/*::
-type Props = {
- customOrganizations: boolean,
- user: {
- email?: string,
- externalProvider?: string,
- groups: Array<*>,
- local: boolean,
- login: string,
- scmAccounts: Array<*>
- }
-};
-*/
-
-function Profile(props /*: Props */) {
- const { customOrganizations, user } = props;
-
- return (
- <div className="account-body account-container">
- <div className="boxed-group boxed-group-inner">
- <div className="spacer-bottom">
- {translate('login')}: <strong id="login">{user.login}</strong>
- </div>
-
- {!user.local &&
- user.externalProvider !== 'sonarqube' && (
- <div className="spacer-bottom" id="identity-provider">
- <UserExternalIdentity user={user} />
- </div>
- )}
-
- {!!user.email && (
- <div className="spacer-bottom">
- {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
- </div>
- )}
-
- {!customOrganizations && <hr className="account-separator" />}
- {!customOrganizations && <UserGroups groups={user.groups} />}
-
- <hr />
-
- <UserScmAccounts scmAccounts={user.scmAccounts} user={user} />
- </div>
- </div>
- );
-}
-
-const mapStateToProps = state => ({
- customOrganizations: areThereCustomOrganizations(state),
- user: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(Profile);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { connect } from 'react-redux';
+import UserExternalIdentity from './UserExternalIdentity';
+import UserGroups from './UserGroups';
+import UserScmAccounts from './UserScmAccounts';
+import { getCurrentUser, areThereCustomOrganizations, Store } from '../../../store/rootReducer';
+import { translate } from '../../../helpers/l10n';
+import { LoggedInUser } from '../../../app/types';
+
+interface Props {
+ customOrganizations?: boolean;
+ user: LoggedInUser;
+}
+
+function Profile({ customOrganizations, user }: Props) {
+ return (
+ <div className="account-body account-container">
+ <div className="boxed-group boxed-group-inner">
+ <div className="spacer-bottom">
+ {translate('login')}: <strong id="login">{user.login}</strong>
+ </div>
+
+ {!user.local &&
+ user.externalProvider !== 'sonarqube' && (
+ <div className="spacer-bottom" id="identity-provider">
+ <UserExternalIdentity user={user} />
+ </div>
+ )}
+
+ {!!user.email && (
+ <div className="spacer-bottom">
+ {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
+ </div>
+ )}
+
+ {!customOrganizations && (
+ <>
+ <hr className="account-separator" />
+ <UserGroups groups={user.groups} />
+ </>
+ )}
+
+ <hr />
+
+ <UserScmAccounts scmAccounts={user.scmAccounts} user={user} />
+ </div>
+ </div>
+ );
+}
+
+const mapStateToProps = (state: Store) => ({
+ customOrganizations: areThereCustomOrganizations(state),
+ user: getCurrentUser(state) as LoggedInUser
+});
+
+export default connect(mapStateToProps)(Profile);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 { getIdentityProviders } from '../../../api/users';
-import * as theme from '../../../app/theme';
-import { getTextColor } from '../../../helpers/colors';
-
-export default class UserExternalIdentity extends React.PureComponent {
- state = {
- loading: true
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchIdentityProviders();
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.user !== this.props.user) {
- this.fetchIdentityProviders();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchIdentityProviders() {
- this.setState({ loading: true });
- getIdentityProviders()
- .then(r => r.identityProviders)
- .then(providers => {
- if (this.mounted) {
- const identityProvider = providers.find(
- provider => provider.key === this.props.user.externalProvider
- );
- this.setState({ loading: false, identityProvider });
- }
- })
- .catch(() => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- });
- }
-
- render() {
- const { user } = this.props;
- const { loading, identityProvider } = this.state;
-
- if (loading) {
- return null;
- }
-
- if (!identityProvider) {
- return (
- <div>
- {user.externalProvider}
- {': '}
- {user.externalIdentity}
- </div>
- );
- }
-
- return (
- <div
- className="identity-provider"
- style={{
- backgroundColor: identityProvider.backgroundColor,
- color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor)
- }}>
- <img
- alt={identityProvider.name}
- className="little-spacer-right"
- height="14"
- src={window.baseUrl + identityProvider.iconPath}
- width="14"
- />{' '}
- {user.externalIdentity}
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { getIdentityProviders } from '../../../api/users';
+import * as theme from '../../../app/theme';
+import { getTextColor } from '../../../helpers/colors';
+import { LoggedInUser, IdentityProvider } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+
+interface Props {
+ user: LoggedInUser;
+}
+
+interface State {
+ identityProvider?: IdentityProvider;
+ loading: boolean;
+}
+
+export default class UserExternalIdentity extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {
+ loading: true
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchIdentityProviders();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.user !== this.props.user) {
+ this.fetchIdentityProviders();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchIdentityProviders() {
+ this.setState({ loading: true });
+ getIdentityProviders()
+ .then(r => r.identityProviders)
+ .then(providers => {
+ if (this.mounted) {
+ const identityProvider = providers.find(
+ provider => provider.key === this.props.user.externalProvider
+ );
+ this.setState({ loading: false, identityProvider });
+ }
+ })
+ .catch(() => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ });
+ }
+
+ render() {
+ const { user } = this.props;
+ const { loading, identityProvider } = this.state;
+
+ if (loading) {
+ return null;
+ }
+
+ if (!identityProvider) {
+ return (
+ <div>
+ {user.externalProvider}
+ {': '}
+ {user.externalIdentity}
+ </div>
+ );
+ }
+
+ return (
+ <div
+ className="identity-provider"
+ style={{
+ backgroundColor: identityProvider.backgroundColor,
+ color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor)
+ }}>
+ <img
+ alt={identityProvider.name}
+ className="little-spacer-right"
+ height="14"
+ src={getBaseUrl() + identityProvider.iconPath}
+ width="14"
+ />{' '}
+ {user.externalIdentity}
+ </div>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 PropTypes from 'prop-types';
-import { translate } from '../../../helpers/l10n';
-
-export default class UserGroups extends React.PureComponent {
- static propTypes = {
- groups: PropTypes.arrayOf(PropTypes.string).isRequired
- };
-
- render() {
- const { groups } = this.props;
-
- return (
- <div>
- <h2 className="spacer-bottom">{translate('my_profile.groups')}</h2>
- <ul id="groups">
- {groups.map(group => (
- <li className="little-spacer-bottom" key={group} title={group}>
- {group}
- </li>
- ))}
- </ul>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ groups: string[];
+}
+
+export default function UserGroups({ groups }: Props) {
+ return (
+ <div>
+ <h2 className="spacer-bottom">{translate('my_profile.groups')}</h2>
+ <ul id="groups">
+ {groups.map(group => (
+ <li className="little-spacer-bottom" key={group} title={group}>
+ {group}
+ </li>
+ ))}
+ </ul>
+ </div>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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 PropTypes from 'prop-types';
-import { translate } from '../../../helpers/l10n';
-
-export default class UserScmAccounts extends React.PureComponent {
- static propTypes = {
- user: PropTypes.object.isRequired,
- scmAccounts: PropTypes.arrayOf(PropTypes.string).isRequired
- };
-
- render() {
- const { user, scmAccounts } = this.props;
-
- return (
- <div>
- <h2 className="spacer-bottom">{translate('my_profile.scm_accounts')}</h2>
- <ul id="scm-accounts">
- <li className="little-spacer-bottom text-ellipsis" title={user.login}>
- {user.login}
- </li>
-
- {user.email && (
- <li className="little-spacer-bottom text-ellipsis" title={user.email}>
- {user.email}
- </li>
- )}
-
- {scmAccounts.map(scmAccount => (
- <li className="little-spacer-bottom" key={scmAccount} title={scmAccount}>
- {scmAccount}
- </li>
- ))}
- </ul>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import { translate } from '../../../helpers/l10n';
+import { LoggedInUser } from '../../../app/types';
+
+interface Props {
+ scmAccounts: string[];
+ user: LoggedInUser;
+}
+
+export default function UserScmAccounts({ user, scmAccounts }: Props) {
+ return (
+ <div>
+ <h2 className="spacer-bottom">{translate('my_profile.scm_accounts')}</h2>
+ <ul id="scm-accounts">
+ <li className="little-spacer-bottom text-ellipsis" title={user.login}>
+ {user.login}
+ </li>
+
+ {user.email && (
+ <li className="little-spacer-bottom text-ellipsis" title={user.email}>
+ {user.email}
+ </li>
+ )}
+
+ {scmAccounts.map(scmAccount => (
+ <li className="little-spacer-bottom" key={scmAccount} title={scmAccount}>
+ {scmAccount}
+ </li>
+ ))}
+ </ul>
+ </div>
+ );
+}
const user: LoggedInUser = {
externalProvider: 'github',
+ groups: [],
isLoggedIn: true,
login: 'foo',
- name: 'Foo'
+ name: 'Foo',
+ scmAccounts: []
};
beforeEach(() => {
function getWrapper(props = {}) {
return shallow(
<ManualProjectCreate
- currentUser={{ isLoggedIn: true, login: 'foo', name: 'Foo' }}
+ currentUser={{ groups: [], isLoggedIn: true, login: 'foo', name: 'Foo', scmAccounts: [] }}
fetchMyOrganizations={jest.fn()}
onProjectCreate={jest.fn()}
userOrganizations={[{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]}
currentUser={
Object {
"externalProvider": "microsoft",
+ "groups": Array [],
"isLoggedIn": true,
"login": "foo",
"name": "Foo",
+ "scmAccounts": Array [],
}
}
onProjectCreate={[Function]}
};
const loggedInUser: LoggedInUser = {
+ groups: [],
isLoggedIn: true,
login: 'luke',
- name: 'Skywalker'
+ name: 'Skywalker',
+ scmAccounts: []
};
it('renders correctly', () => {
<TokenStep
currentUser={
Object {
+ "groups": Array [],
"isLoggedIn": true,
"login": "luke",
"name": "Skywalker",
+ "scmAccounts": Array [],
}
}
finished={false}