]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9925 Rewrite session to typescript
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 4 Oct 2017 16:14:49 +0000 (18:14 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Tue, 10 Oct 2017 13:39:29 +0000 (06:39 -0700)
23 files changed:
server/sonar-web/src/main/js/api/users.ts
server/sonar-web/src/main/js/app/components/SimpleContainer.js [deleted file]
server/sonar-web/src/main/js/app/components/SimpleContainer.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/LoginForm.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/Logout.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx
server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.js [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.js.snap [deleted file]
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/l10n/core.properties
tests/src/test/resources/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html
tests/src/test/resources/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html
tests/src/test/resources/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html
tests/src/test/resources/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html

index 07a5d7996d3d7925fb148a43f5876f47dae1ffca..f42c362fc7446cb4d45c4ea10b2550689e3de58a 100644 (file)
  */
 import { getJSON, post, RequestData } from '../helpers/request';
 
+export interface IdentityProvider {
+  backgroundColor: string;
+  iconPath: string;
+  key: string;
+  name: string;
+}
+
 export function getCurrentUser(): Promise<any> {
   return getJSON('/api/users/current');
 }
@@ -43,7 +50,7 @@ export function getUserGroups(login: string, organization?: string): Promise<any
   return getJSON('/api/users/groups', data);
 }
 
-export function getIdentityProviders(): Promise<any> {
+export function getIdentityProviders(): Promise<{ identityProviders: IdentityProvider[] }> {
   return getJSON('/api/users/identity_providers');
 }
 
diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.js b/server/sonar-web/src/main/js/app/components/SimpleContainer.js
deleted file mode 100644 (file)
index 0259635..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 GlobalFooterContainer from './GlobalFooterContainer';
-import NavBar from '../../components/nav/NavBar';
-
-/*::
-type Props = {
-  children?: React.Element<*> | Array<React.Element<*>>,
-  hideLoggedInInfo?: boolean
-};
-*/
-
-export default class SimpleContainer extends React.PureComponent {
-  /*:: props: Props; */
-
-  componentDidMount() {
-    const html = document.querySelector('html');
-    if (html) {
-      html.classList.add('dashboard-page');
-    }
-  }
-
-  componentWillUnmount() {
-    const html = document.querySelector('html');
-    if (html) {
-      html.classList.remove('dashboard-page');
-    }
-  }
-
-  render() {
-    return (
-      <div className="global-container">
-        <div className="page-wrapper" id="container">
-          <NavBar className="navbar-global" id="global-navigation" height={30} />
-
-          <div id="bd" className="page-wrapper-simple">
-            <div id="nonav" className="page-simple">
-              {this.props.children}
-            </div>
-          </div>
-        </div>
-        <GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} />
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
new file mode 100644 (file)
index 0000000..51c4336
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 GlobalFooterContainer from './GlobalFooterContainer';
+import NavBar from '../../components/nav/NavBar';
+
+interface Props {
+  children?: React.ReactNode;
+  hideLoggedInInfo?: boolean;
+}
+
+export default class SimpleContainer extends React.PureComponent<Props> {
+  componentDidMount() {
+    const html = document.querySelector('html');
+    if (html) {
+      html.classList.add('dashboard-page');
+    }
+  }
+
+  componentWillUnmount() {
+    const html = document.querySelector('html');
+    if (html) {
+      html.classList.remove('dashboard-page');
+    }
+  }
+
+  render() {
+    return (
+      <div className="global-container">
+        <div className="page-wrapper" id="container">
+          <NavBar className="navbar-global" height={30} />
+
+          <div id="bd" className="page-wrapper-simple">
+            <div id="nonav" className="page-simple">
+              {this.props.children}
+            </div>
+          </div>
+        </div>
+        <GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} />
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.js b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.js
deleted file mode 100644 (file)
index 4ae970f..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 OAuthProviders from './OAuthProviders';
-import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
-import { translate } from '../../../helpers/l10n';
-
-/*::
-type Props = {
-  identityProviders: Array<{
-    backgroundColor: string,
-    iconPath: string,
-    key: string,
-    name: string
-  }>,
-  onSubmit: (string, string) => void
-};
-*/
-
-/*::
-type State = {
-  collapsed: boolean,
-  login: string,
-  password: string
-};
-*/
-
-export default class LoginForm extends React.PureComponent {
-  /*:: props: Props; */
-  /*:: state: State; */
-
-  constructor(props /*: Props */) {
-    super(props);
-    this.state = {
-      collapsed: props.identityProviders.length > 0,
-      login: '',
-      password: ''
-    };
-  }
-
-  handleSubmit = (event /*: Event */) => {
-    event.preventDefault();
-    this.props.onSubmit(this.state.login, this.state.password);
-  };
-
-  handleMoreOptionsClick = (event /*: Event */) => {
-    event.preventDefault();
-    this.setState({ collapsed: false });
-  };
-
-  render() {
-    return (
-      <div id="login_form">
-        <h1 className="maintenance-title text-center">{translate('login.login_to_sonarqube')}</h1>
-
-        {this.props.identityProviders.length > 0 && (
-          <OAuthProviders identityProviders={this.props.identityProviders} />
-        )}
-
-        {this.state.collapsed ? (
-          <div className="text-center">
-            <a
-              className="small text-muted js-more-options"
-              href="#"
-              onClick={this.handleMoreOptionsClick}>
-              {translate('login.more_options')}
-            </a>
-          </div>
-        ) : (
-          <form onSubmit={this.handleSubmit}>
-            <GlobalMessagesContainer />
-
-            <div className="big-spacer-bottom">
-              <label htmlFor="login" className="login-label">
-                {translate('login')}
-              </label>
-              <input
-                type="text"
-                id="login"
-                name="login"
-                className="login-input"
-                maxLength="255"
-                required={true}
-                autoFocus={true}
-                placeholder={translate('login')}
-                value={this.state.login}
-                onChange={e => this.setState({ login: e.target.value })}
-              />
-            </div>
-
-            <div className="big-spacer-bottom">
-              <label htmlFor="password" className="login-label">
-                {translate('password')}
-              </label>
-              <input
-                type="password"
-                id="password"
-                name="password"
-                className="login-input"
-                required={true}
-                placeholder={translate('password')}
-                value={this.state.password}
-                onChange={e => this.setState({ password: e.target.value })}
-              />
-            </div>
-
-            <div>
-              <div className="text-right overflow-hidden">
-                <button name="commit" type="submit">
-                  {translate('sessions.log_in')}
-                </button>
-                <a className="spacer-left" href={window.baseUrl + '/'}>
-                  {translate('cancel')}
-                </a>
-              </div>
-            </div>
-          </form>
-        )}
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx
new file mode 100644 (file)
index 0000000..362e7f8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 } from 'react-router';
+import OAuthProviders from './OAuthProviders';
+import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
+import { translate } from '../../../helpers/l10n';
+import { IdentityProvider } from '../../../api/users';
+
+interface Props {
+  identityProviders: IdentityProvider[];
+  onSubmit: (login: string, password: string) => void;
+}
+
+interface State {
+  collapsed: boolean;
+  login: string;
+  password: string;
+}
+
+export default class LoginForm extends React.PureComponent<Props, State> {
+  constructor(props: Props) {
+    super(props);
+    this.state = {
+      collapsed: props.identityProviders.length > 0,
+      login: '',
+      password: ''
+    };
+  }
+
+  handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+    event.preventDefault();
+    this.props.onSubmit(this.state.login, this.state.password);
+  };
+
+  handleMoreOptionsClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
+    event.preventDefault();
+    this.setState({ collapsed: false });
+  };
+
+  handleLoginChange = (event: React.SyntheticEvent<HTMLInputElement>) =>
+    this.setState({ login: event.currentTarget.value });
+
+  handlePwdChange = (event: React.SyntheticEvent<HTMLInputElement>) =>
+    this.setState({ password: event.currentTarget.value });
+
+  render() {
+    return (
+      <div id="login_form">
+        <h1 className="maintenance-title text-center">{translate('login.login_to_sonarqube')}</h1>
+
+        {this.props.identityProviders.length > 0 && (
+          <OAuthProviders identityProviders={this.props.identityProviders} />
+        )}
+
+        {this.state.collapsed ? (
+          <div className="text-center">
+            <a
+              className="small text-muted js-more-options"
+              href="#"
+              onClick={this.handleMoreOptionsClick}>
+              {translate('login.more_options')}
+            </a>
+          </div>
+        ) : (
+          <form onSubmit={this.handleSubmit}>
+            <GlobalMessagesContainer />
+
+            <div className="big-spacer-bottom">
+              <label htmlFor="login" className="login-label">
+                {translate('login')}
+              </label>
+              <input
+                type="text"
+                id="login"
+                name="login"
+                className="login-input"
+                maxLength={255}
+                required={true}
+                autoFocus={true}
+                placeholder={translate('login')}
+                value={this.state.login}
+                onChange={this.handleLoginChange}
+              />
+            </div>
+
+            <div className="big-spacer-bottom">
+              <label htmlFor="password" className="login-label">
+                {translate('password')}
+              </label>
+              <input
+                type="password"
+                id="password"
+                name="password"
+                className="login-input"
+                required={true}
+                placeholder={translate('password')}
+                value={this.state.password}
+                onChange={this.handlePwdChange}
+              />
+            </div>
+
+            <div>
+              <div className="text-right overflow-hidden">
+                <button name="commit" type="submit">
+                  {translate('sessions.log_in')}
+                </button>
+                <Link className="spacer-left" to="/">
+                  {translate('cancel')}
+                </Link>
+              </div>
+            </div>
+          </form>
+        )}
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.js b/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.js
deleted file mode 100644 (file)
index fe2197f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 PropTypes from 'prop-types';
-import { connect } from 'react-redux';
-import LoginForm from './LoginForm';
-import { doLogin } from '../../../store/rootActions';
-import { getAppState } from '../../../store/rootReducer';
-import { getIdentityProviders } from '../../../api/users';
-
-class LoginFormContainer extends React.PureComponent {
-  /*:: mounted: boolean; */
-
-  static propTypes = {
-    location: PropTypes.object.isRequired
-  };
-
-  state = {};
-
-  componentDidMount() {
-    this.mounted = true;
-    getIdentityProviders().then(r => {
-      if (this.mounted) {
-        this.setState({ identityProviders: r.identityProviders });
-      }
-    });
-  }
-
-  componentWillUnmount() {
-    this.mounted = false;
-  }
-
-  handleSuccessfulLogin = () => {
-    const { location } = this.props;
-    const queryReturnTo = location.query['return_to'];
-    const returnTo = queryReturnTo ? `${queryReturnTo}${location.hash}` : `${window.baseUrl}/`;
-    window.location = returnTo;
-  };
-
-  handleSubmit = (login /*: string */, password /*: string */) => {
-    this.props.doLogin(login, password).then(this.handleSuccessfulLogin, () => {
-      /* do nothing */
-    });
-  };
-
-  render() {
-    if (!this.state.identityProviders) {
-      return null;
-    }
-
-    return (
-      <LoginForm identityProviders={this.state.identityProviders} onSubmit={this.handleSubmit} />
-    );
-  }
-}
-
-const mapStateToProps = state => ({
-  appState: getAppState(state)
-});
-
-const mapDispatchToProps = { doLogin };
-
-export default connect(mapStateToProps, mapDispatchToProps)(LoginFormContainer);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.tsx
new file mode 100644 (file)
index 0000000..2c2152b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 LoginForm from './LoginForm';
+import { doLogin } from '../../../store/rootActions';
+import { getAppState } from '../../../store/rootReducer';
+import { IdentityProvider, getIdentityProviders } from '../../../api/users';
+import { getBaseUrl } from '../../../helpers/urls';
+
+interface Props {
+  doLogin: (login: string, password: string) => Promise<void>;
+  location: { hash?: string; pathName: string; query: { return_to?: string } };
+}
+
+interface State {
+  identityProviders?: IdentityProvider[];
+}
+
+class LoginFormContainer extends React.PureComponent<Props, State> {
+  mounted: boolean;
+  state: State = {};
+
+  componentDidMount() {
+    this.mounted = true;
+    getIdentityProviders().then(r => {
+      if (this.mounted) {
+        this.setState({ identityProviders: r.identityProviders });
+      }
+    });
+  }
+
+  componentWillUnmount() {
+    this.mounted = false;
+  }
+
+  handleSuccessfulLogin = () => {
+    const { location } = this.props;
+    const queryReturnTo = location.query['return_to'];
+    const returnTo = queryReturnTo ? `${queryReturnTo}${location.hash}` : `${getBaseUrl()}/`;
+    window.location.href = returnTo;
+  };
+
+  handleSubmit = (login: string, password: string) => {
+    this.props.doLogin(login, password).then(this.handleSuccessfulLogin, () => {});
+  };
+
+  render() {
+    if (!this.state.identityProviders) {
+      return null;
+    }
+
+    return (
+      <LoginForm identityProviders={this.state.identityProviders} onSubmit={this.handleSubmit} />
+    );
+  }
+}
+
+const mapStateToProps = (state: any) => ({
+  appState: getAppState(state)
+});
+
+const mapDispatchToProps = { doLogin };
+
+export default connect(mapStateToProps, mapDispatchToProps)(LoginFormContainer as any);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Logout.js b/server/sonar-web/src/main/js/apps/sessions/components/Logout.js
deleted file mode 100644 (file)
index 736c4cc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
-import { doLogout } from '../../../store/rootActions';
-import { translate } from '../../../helpers/l10n';
-import RecentHistory from '../../../app/components/RecentHistory';
-
-class Logout extends React.PureComponent {
-  componentDidMount() {
-    this.props
-      .doLogout()
-      .then(() => {
-        RecentHistory.clear();
-        window.location = window.baseUrl + '/';
-      })
-      .catch(() => {
-        /* do nothing */
-      });
-  }
-
-  render() {
-    return (
-      <div>
-        <GlobalMessagesContainer />
-        {translate('logging_out')}
-      </div>
-    );
-  }
-}
-
-const mapStateToProps = () => ({});
-
-const mapDispatchToProps = { doLogout };
-
-export default connect(mapStateToProps, mapDispatchToProps)(Logout);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx b/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx
new file mode 100644 (file)
index 0000000..b90ff4c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
+import RecentHistory from '../../../app/components/RecentHistory';
+import { doLogout } from '../../../store/rootActions';
+import { translate } from '../../../helpers/l10n';
+import { getBaseUrl } from '../../../helpers/urls';
+
+interface Props {
+  doLogout: () => Promise<void>;
+}
+
+class Logout extends React.PureComponent<Props> {
+  componentDidMount() {
+    this.props.doLogout().then(
+      () => {
+        RecentHistory.clear();
+        window.location.href = getBaseUrl() + '/';
+      },
+      () => {}
+    );
+  }
+
+  render() {
+    return (
+      <div>
+        <GlobalMessagesContainer />
+        {translate('logging_out')}
+      </div>
+    );
+  }
+}
+
+const mapStateToProps = () => ({});
+
+const mapDispatchToProps = { doLogout };
+
+export default connect(mapStateToProps, mapDispatchToProps)(Logout as any);
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.js b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.js
deleted file mode 100644 (file)
index d06a201..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 { translateWithParameters } from '../../../helpers/l10n';
-
-/*::
-type Props = {
-  formatLabel?: string => string,
-  identityProviders: Array<{
-    backgroundColor: string,
-    iconPath: string,
-    key: string,
-    name: string
-  }>
-};
-*/
-
-export default function OAuthProviders(props /*: Props */) {
-  return (
-    <section className="oauth-providers">
-      <ul>
-        {props.identityProviders.map(identityProvider => (
-          <li key={identityProvider.key}>
-            <a
-              href={`${window.baseUrl}/sessions/init/${identityProvider.key}`}
-              style={{ backgroundColor: identityProvider.backgroundColor }}
-              // $FlowFixMe formatLabel is always defined through defaultProps
-              title={props.formatLabel(identityProvider.name)}>
-              <img
-                alt={identityProvider.name}
-                width="20"
-                height="20"
-                src={window.baseUrl + identityProvider.iconPath}
-              />
-              <span>
-                {/* $FlowFixMe formatLabel is always defined through defaultProps */}
-                {props.formatLabel(identityProvider.name)}
-              </span>
-            </a>
-          </li>
-        ))}
-      </ul>
-    </section>
-  );
-}
-
-OAuthProviders.defaultProps = {
-  formatLabel: (name /*: string */) => translateWithParameters('login.login_with_x', name)
-};
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx
new file mode 100644 (file)
index 0000000..973f8b3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 { translateWithParameters } from '../../../helpers/l10n';
+import { IdentityProvider } from '../../../api/users';
+import { getBaseUrl } from '../../../helpers/urls';
+
+interface Props {
+  formatLabel?: (name: string) => string;
+  identityProviders: IdentityProvider[];
+}
+
+export default function OAuthProviders(props: Props) {
+  const formatLabel = props.formatLabel || defaultFormatLabel;
+  return (
+    <section className="oauth-providers">
+      <ul>
+        {props.identityProviders.map(identityProvider => (
+          <li key={identityProvider.key}>
+            <a
+              href={`${getBaseUrl()}/sessions/init/${identityProvider.key}`}
+              style={{ backgroundColor: identityProvider.backgroundColor }}
+              title={formatLabel(identityProvider.name)}>
+              <img
+                alt={identityProvider.name}
+                width="20"
+                height="20"
+                src={getBaseUrl() + identityProvider.iconPath}
+              />
+              <span>{formatLabel(identityProvider.name)}</span>
+            </a>
+          </li>
+        ))}
+      </ul>
+    </section>
+  );
+}
+
+function defaultFormatLabel(name: string) {
+  return translateWithParameters('login.login_with_x', name);
+}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.js b/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.js
deleted file mode 100644 (file)
index 29efdcd..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 SimpleContainer from '../../../app/components/SimpleContainer';
-
-/*::
-type Props = {
-  children?: React.Element<*> | Array<React.Element<*>>
-};
-*/
-
-export default function SimpleSessionsContainer({ children } /*: Props */) {
-  return <SimpleContainer hideLoggedInInfo={true}>{children}</SimpleContainer>;
-}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/SimpleSessionsContainer.tsx
new file mode 100644 (file)
index 0000000..b29c1e4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 SimpleContainer from '../../../app/components/SimpleContainer';
+
+interface Props {
+  children?: React.ReactElement<any>;
+}
+
+export default function SimpleSessionsContainer({ children }: Props) {
+  return <SimpleContainer hideLoggedInInfo={true}>{children}</SimpleContainer>;
+}
index 12bc8b8724cd7a8edff40c02021c6a6b0267e676..cb12caa296ea1f466dafe074c3823ecc2a6ce03a 100644 (file)
@@ -19,6 +19,7 @@
  */
 import * as React from 'react';
 import { Link } from 'react-router';
+import { translate } from '../../../helpers/l10n';
 
 interface Props {
   location: {
@@ -33,14 +34,16 @@ export default function Unauthorized(props: Props) {
 
   return (
     <div className="text-center">
-      <p id="unauthorized">
-        {"You're not authorized to access this page. Please contact the administrator."}
-      </p>
+      <p id="unauthorized">{translate('unauthorized.message')}</p>
 
-      {!!message && <p className="spacer-top">Reason : {message}</p>}
+      {!!message && (
+        <p className="spacer-top">
+          {translate('unauthorized.reason')} {message}
+        </p>
+      )}
 
       <div className="big-spacer-top">
-        <Link to="/">Home</Link>
+        <Link to="/">{translate('layout.home')}</Link>
       </div>
     </div>
   );
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.js b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.js
deleted file mode 100644 (file)
index 6eea812..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 { shallow } from 'enzyme';
-import LoginForm from '../LoginForm';
-import { change, click, submit } from '../../../../helpers/testUtils';
-
-const identityProvider = {
-  backgroundColor: '#000',
-  iconPath: '/some/path',
-  key: 'foo',
-  name: 'foo'
-};
-
-it('logs in with simple credentials', () => {
-  const onSubmit = jest.fn();
-  const wrapper = shallow(<LoginForm identityProviders={[]} onSubmit={onSubmit} />);
-  expect(wrapper).toMatchSnapshot();
-
-  change(wrapper.find('#login'), 'admin');
-  change(wrapper.find('#password'), 'admin');
-  submit(wrapper.find('form'));
-
-  expect(onSubmit).toBeCalledWith('admin', 'admin');
-});
-
-it('logs in with identity provider', () => {
-  const wrapper = shallow(
-    <LoginForm identityProviders={[identityProvider]} onSubmit={jest.fn()} />
-  );
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('expands more options', () => {
-  const wrapper = shallow(
-    <LoginForm identityProviders={[identityProvider]} onSubmit={jest.fn()} />
-  );
-  expect(wrapper).toMatchSnapshot();
-
-  click(wrapper.find('.js-more-options'));
-  expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/LoginForm-test.tsx
new file mode 100644 (file)
index 0000000..47f1add
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 { shallow } from 'enzyme';
+import LoginForm from '../LoginForm';
+import { change, click, submit } from '../../../../helpers/testUtils';
+
+const identityProvider = {
+  backgroundColor: '#000',
+  iconPath: '/some/path',
+  key: 'foo',
+  name: 'foo'
+};
+
+it('logs in with simple credentials', () => {
+  const onSubmit = jest.fn();
+  const wrapper = shallow(<LoginForm identityProviders={[]} onSubmit={onSubmit} />);
+  expect(wrapper).toMatchSnapshot();
+
+  change(wrapper.find('#login'), 'admin');
+  change(wrapper.find('#password'), 'admin');
+  submit(wrapper.find('form'));
+
+  expect(onSubmit).toBeCalledWith('admin', 'admin');
+});
+
+it('logs in with identity provider', () => {
+  const wrapper = shallow(
+    <LoginForm identityProviders={[identityProvider]} onSubmit={jest.fn()} />
+  );
+  expect(wrapper).toMatchSnapshot();
+});
+
+it('expands more options', () => {
+  const wrapper = shallow(
+    <LoginForm identityProviders={[identityProvider]} onSubmit={jest.fn()} />
+  );
+  expect(wrapper).toMatchSnapshot();
+
+  click(wrapper.find('.js-more-options'));
+  expect(wrapper).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.js.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.js.snap
deleted file mode 100644 (file)
index 42113f4..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`expands more options 1`] = `
-<div
-  id="login_form"
->
-  <h1
-    className="maintenance-title text-center"
-  >
-    login.login_to_sonarqube
-  </h1>
-  <OAuthProviders
-    formatLabel={[Function]}
-    identityProviders={
-      Array [
-        Object {
-          "backgroundColor": "#000",
-          "iconPath": "/some/path",
-          "key": "foo",
-          "name": "foo",
-        },
-      ]
-    }
-  />
-  <div
-    className="text-center"
-  >
-    <a
-      className="small text-muted js-more-options"
-      href="#"
-      onClick={[Function]}
-    >
-      login.more_options
-    </a>
-  </div>
-</div>
-`;
-
-exports[`expands more options 2`] = `
-<div
-  id="login_form"
->
-  <h1
-    className="maintenance-title text-center"
-  >
-    login.login_to_sonarqube
-  </h1>
-  <OAuthProviders
-    formatLabel={[Function]}
-    identityProviders={
-      Array [
-        Object {
-          "backgroundColor": "#000",
-          "iconPath": "/some/path",
-          "key": "foo",
-          "name": "foo",
-        },
-      ]
-    }
-  />
-  <form
-    onSubmit={[Function]}
-  >
-    <Connect(GlobalMessages) />
-    <div
-      className="big-spacer-bottom"
-    >
-      <label
-        className="login-label"
-        htmlFor="login"
-      >
-        login
-      </label>
-      <input
-        autoFocus={true}
-        className="login-input"
-        id="login"
-        maxLength="255"
-        name="login"
-        onChange={[Function]}
-        placeholder="login"
-        required={true}
-        type="text"
-        value=""
-      />
-    </div>
-    <div
-      className="big-spacer-bottom"
-    >
-      <label
-        className="login-label"
-        htmlFor="password"
-      >
-        password
-      </label>
-      <input
-        className="login-input"
-        id="password"
-        name="password"
-        onChange={[Function]}
-        placeholder="password"
-        required={true}
-        type="password"
-        value=""
-      />
-    </div>
-    <div>
-      <div
-        className="text-right overflow-hidden"
-      >
-        <button
-          name="commit"
-          type="submit"
-        >
-          sessions.log_in
-        </button>
-        <a
-          className="spacer-left"
-          href="/"
-        >
-          cancel
-        </a>
-      </div>
-    </div>
-  </form>
-</div>
-`;
-
-exports[`logs in with identity provider 1`] = `
-<div
-  id="login_form"
->
-  <h1
-    className="maintenance-title text-center"
-  >
-    login.login_to_sonarqube
-  </h1>
-  <OAuthProviders
-    formatLabel={[Function]}
-    identityProviders={
-      Array [
-        Object {
-          "backgroundColor": "#000",
-          "iconPath": "/some/path",
-          "key": "foo",
-          "name": "foo",
-        },
-      ]
-    }
-  />
-  <div
-    className="text-center"
-  >
-    <a
-      className="small text-muted js-more-options"
-      href="#"
-      onClick={[Function]}
-    >
-      login.more_options
-    </a>
-  </div>
-</div>
-`;
-
-exports[`logs in with simple credentials 1`] = `
-<div
-  id="login_form"
->
-  <h1
-    className="maintenance-title text-center"
-  >
-    login.login_to_sonarqube
-  </h1>
-  <form
-    onSubmit={[Function]}
-  >
-    <Connect(GlobalMessages) />
-    <div
-      className="big-spacer-bottom"
-    >
-      <label
-        className="login-label"
-        htmlFor="login"
-      >
-        login
-      </label>
-      <input
-        autoFocus={true}
-        className="login-input"
-        id="login"
-        maxLength="255"
-        name="login"
-        onChange={[Function]}
-        placeholder="login"
-        required={true}
-        type="text"
-        value=""
-      />
-    </div>
-    <div
-      className="big-spacer-bottom"
-    >
-      <label
-        className="login-label"
-        htmlFor="password"
-      >
-        password
-      </label>
-      <input
-        className="login-input"
-        id="password"
-        name="password"
-        onChange={[Function]}
-        placeholder="password"
-        required={true}
-        type="password"
-        value=""
-      />
-    </div>
-    <div>
-      <div
-        className="text-right overflow-hidden"
-      >
-        <button
-          name="commit"
-          type="submit"
-        >
-          sessions.log_in
-        </button>
-        <a
-          className="spacer-left"
-          href="/"
-        >
-          cancel
-        </a>
-      </div>
-    </div>
-  </form>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap
new file mode 100644 (file)
index 0000000..2950599
--- /dev/null
@@ -0,0 +1,241 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`expands more options 1`] = `
+<div
+  id="login_form"
+>
+  <h1
+    className="maintenance-title text-center"
+  >
+    login.login_to_sonarqube
+  </h1>
+  <OAuthProviders
+    identityProviders={
+      Array [
+        Object {
+          "backgroundColor": "#000",
+          "iconPath": "/some/path",
+          "key": "foo",
+          "name": "foo",
+        },
+      ]
+    }
+  />
+  <div
+    className="text-center"
+  >
+    <a
+      className="small text-muted js-more-options"
+      href="#"
+      onClick={[Function]}
+    >
+      login.more_options
+    </a>
+  </div>
+</div>
+`;
+
+exports[`expands more options 2`] = `
+<div
+  id="login_form"
+>
+  <h1
+    className="maintenance-title text-center"
+  >
+    login.login_to_sonarqube
+  </h1>
+  <OAuthProviders
+    identityProviders={
+      Array [
+        Object {
+          "backgroundColor": "#000",
+          "iconPath": "/some/path",
+          "key": "foo",
+          "name": "foo",
+        },
+      ]
+    }
+  />
+  <form
+    onSubmit={[Function]}
+  >
+    <Connect(GlobalMessages) />
+    <div
+      className="big-spacer-bottom"
+    >
+      <label
+        className="login-label"
+        htmlFor="login"
+      >
+        login
+      </label>
+      <input
+        autoFocus={true}
+        className="login-input"
+        id="login"
+        maxLength={255}
+        name="login"
+        onChange={[Function]}
+        placeholder="login"
+        required={true}
+        type="text"
+        value=""
+      />
+    </div>
+    <div
+      className="big-spacer-bottom"
+    >
+      <label
+        className="login-label"
+        htmlFor="password"
+      >
+        password
+      </label>
+      <input
+        className="login-input"
+        id="password"
+        name="password"
+        onChange={[Function]}
+        placeholder="password"
+        required={true}
+        type="password"
+        value=""
+      />
+    </div>
+    <div>
+      <div
+        className="text-right overflow-hidden"
+      >
+        <button
+          name="commit"
+          type="submit"
+        >
+          sessions.log_in
+        </button>
+        <Link
+          className="spacer-left"
+          onlyActiveOnIndex={false}
+          style={Object {}}
+          to="/"
+        >
+          cancel
+        </Link>
+      </div>
+    </div>
+  </form>
+</div>
+`;
+
+exports[`logs in with identity provider 1`] = `
+<div
+  id="login_form"
+>
+  <h1
+    className="maintenance-title text-center"
+  >
+    login.login_to_sonarqube
+  </h1>
+  <OAuthProviders
+    identityProviders={
+      Array [
+        Object {
+          "backgroundColor": "#000",
+          "iconPath": "/some/path",
+          "key": "foo",
+          "name": "foo",
+        },
+      ]
+    }
+  />
+  <div
+    className="text-center"
+  >
+    <a
+      className="small text-muted js-more-options"
+      href="#"
+      onClick={[Function]}
+    >
+      login.more_options
+    </a>
+  </div>
+</div>
+`;
+
+exports[`logs in with simple credentials 1`] = `
+<div
+  id="login_form"
+>
+  <h1
+    className="maintenance-title text-center"
+  >
+    login.login_to_sonarqube
+  </h1>
+  <form
+    onSubmit={[Function]}
+  >
+    <Connect(GlobalMessages) />
+    <div
+      className="big-spacer-bottom"
+    >
+      <label
+        className="login-label"
+        htmlFor="login"
+      >
+        login
+      </label>
+      <input
+        autoFocus={true}
+        className="login-input"
+        id="login"
+        maxLength={255}
+        name="login"
+        onChange={[Function]}
+        placeholder="login"
+        required={true}
+        type="text"
+        value=""
+      />
+    </div>
+    <div
+      className="big-spacer-bottom"
+    >
+      <label
+        className="login-label"
+        htmlFor="password"
+      >
+        password
+      </label>
+      <input
+        className="login-input"
+        id="password"
+        name="password"
+        onChange={[Function]}
+        placeholder="password"
+        required={true}
+        type="password"
+        value=""
+      />
+    </div>
+    <div>
+      <div
+        className="text-right overflow-hidden"
+      >
+        <button
+          name="commit"
+          type="submit"
+        >
+          sessions.log_in
+        </button>
+        <Link
+          className="spacer-left"
+          onlyActiveOnIndex={false}
+          style={Object {}}
+          to="/"
+        >
+          cancel
+        </Link>
+      </div>
+    </div>
+  </form>
+</div>
+`;
index 13443aa12e9d851725aaebcf319015894e46b6a4..60cec37405f8b9592ae4bd419ea8933fbd434bbd 100644 (file)
@@ -1350,6 +1350,9 @@ login.login_to_sonarqube=Log In to SonarQube
 login.more_options=More options
 login.login_with_x=Log in with {0}
 
+unauthorized.message=You're not authorized to access this page. Please contact the administrator.
+unauthorized.reason=Reason:
+
 #------------------------------------------------------------------------------
 #
 # USERS & GROUPS PAGE
index b62763fb7c9b4c54d1c47b82e3496f2feb422b29..d202404dfd1a80fb3a9e8b2526817d846d418bd0 100644 (file)
@@ -36,7 +36,7 @@
   <tr>
     <td>assertText</td>
     <td>bd</td>
-    <td>*Reason : A functional error has happened*</td>
+    <td>*Reason: A functional error has happened*</td>
   </tr>
   </tbody>
 </table>
index 40c300bd701c4e25f76ac1c57f45576b2bffee78..ddf1b837078dd3af0cc11ea7ca276a062f30070a 100644 (file)
@@ -31,7 +31,7 @@
   <tr>
     <td>waitForText</td>
     <td>bd</td>
-    <td>*You're not authorized to access this page. Please contact the administrator.*Reason : 'fake-base-id-provider' users are not allowed to sign up*</td>
+    <td>*You're not authorized to access this page. Please contact the administrator.*Reason: 'fake-base-id-provider' users are not allowed to sign up*</td>
   </tr>
   </tbody>
 </table>
index 6a38ed6906398fe665efae1e5b675f1d087bb493..a78424c7a91fc48755348b84e1b87906f3727b55 100644 (file)
@@ -36,7 +36,7 @@
   <tr>
     <td>assertText</td>
     <td>bd</td>
-    <td>*Reason : A functional error has happened*</td>
+    <td>*Reason: A functional error has happened*</td>
   </tr>
   </tbody>
 </table>
index a3da2de8ed0a47d10dff6bc58b7b02fdc6901c44..addc1e7818b37ce88f9ba5ab4b2916f0faef10c6 100644 (file)
@@ -31,7 +31,7 @@
   <tr>
     <td>waitForText</td>
     <td>bd</td>
-    <td>*You're not authorized to access this page. Please contact the administrator.*Reason : 'fake-oauth2-id-provider' users are not allowed to sign up*</td>
+    <td>*You're not authorized to access this page. Please contact the administrator.*Reason: 'fake-oauth2-id-provider' users are not allowed to sign up*</td>
   </tr>
   </tbody>
 </table>