From: Stas Vilchik Date: Tue, 6 Feb 2018 15:41:32 +0000 (+0100) Subject: SONAR-10289 Update login page UI and allow to display identity providers help X-Git-Tag: 7.5~1713 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=883828c4e9fb8bbe7313cedb17ce301f3f43f400;p=sonarqube.git SONAR-10289 Update login page UI and allow to display identity providers help --- diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index 26e1470a477..b8667f54e38 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -19,28 +19,7 @@ */ import { getJSON, post, postJSON, RequestData } from '../helpers/request'; import throwGlobalError from '../app/utils/throwGlobalError'; -import { Paging, HomePage, CurrentUser } from '../app/types'; - -export interface IdentityProvider { - backgroundColor: string; - iconPath: string; - key: string; - name: string; -} - -export interface User { - login: string; - name: string; - active: boolean; - email?: string; - scmAccounts?: string[]; - groups?: string[]; - tokensCount?: number; - local: boolean; - externalIdentity?: string; - externalProvider?: string; - avatar?: string; -} +import { Paging, HomePage, CurrentUser, IdentityProvider, User } from '../app/types'; export function getCurrentUser(): Promise { return getJSON('/api/users/current'); diff --git a/server/sonar-web/src/main/js/app/components/NotFound.js b/server/sonar-web/src/main/js/app/components/NotFound.js index 1b466451aea..3f1d81ac0be 100644 --- a/server/sonar-web/src/main/js/app/components/NotFound.js +++ b/server/sonar-web/src/main/js/app/components/NotFound.js @@ -24,11 +24,17 @@ import SimpleContainer from './SimpleContainer'; export default function NotFound() { return ( -

The page you were looking for does not exist.

-

You may have mistyped the address or the page may have moved.

-

- Go back to the homepage -

+
+
+

The page you were looking for does not exist.

+

+ You may have mistyped the address or the page may have moved. +

+

+ Go back to the homepage +

+
+
); } diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx index 8db3e7299c3..b14e0475b70 100644 --- a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx @@ -77,12 +77,7 @@ export default class SimpleContainer extends React.PureComponent {
- -
-
- {this.props.children} -
-
+ {this.props.children}
diff --git a/server/sonar-web/src/main/js/app/styles/components/ui.css b/server/sonar-web/src/main/js/app/styles/components/ui.css index a88b0441216..e6bc2245ac7 100644 --- a/server/sonar-web/src/main/js/app/styles/components/ui.css +++ b/server/sonar-web/src/main/js/app/styles/components/ui.css @@ -122,8 +122,11 @@ .identity-provider { display: inline-block; line-height: 14px; - padding: 3px 5px; + padding: 2px 5px; + border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 3px; + box-sizing: border-box; + background-color: var(--darkBlue); font-size: var(--smallFontSize); color: #fff; } diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index 0d7fb8b6fec..9d380964a46 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -269,3 +269,25 @@ export enum RuleScope { Test = 'TEST', All = 'ALL' } + +export interface IdentityProvider { + backgroundColor: string; + helpMessage?: string; + iconPath: string; + key: string; + name: string; +} + +export interface User { + active: boolean; + avatar?: string; + email?: string; + externalIdentity?: string; + externalProvider?: string; + groups?: string[]; + local: boolean; + login: string; + name: string; + scmAccounts?: string[]; + tokensCount?: number; +} diff --git a/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.js b/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.js index 88b2589e0a6..89e595feed4 100644 --- a/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.js +++ b/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.js @@ -19,6 +19,8 @@ */ 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 = { @@ -80,8 +82,12 @@ export default class UserExternalIdentity extends React.PureComponent { return (
+ style={{ + backgroundColor: identityProvider.backgroundColor, + color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor) + }}> { window.location = this.options.returnTo || getBaseUrl(); diff --git a/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs b/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs index 3a7f14e72a3..44a4bc8798d 100644 --- a/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs +++ b/server/sonar-web/src/main/js/apps/maintenance/templates/maintenance-main.hbs @@ -1,26 +1,32 @@ -{{#eq status 'OFFLINE'}} +
+
- {{> '_maintenance-status-offline'}} + {{#eq status 'OFFLINE'}} -{{else}} + {{> '_maintenance-status-offline'}} - {{#unless setup}} + {{else}} - {{#eq status 'UP'}}{{> '_maintenance-status-up'}}{{/eq}} - {{#eq status 'STARTING'}}{{> '_maintenance-status-starting'}}{{/eq}} - {{#eq status 'DOWN'}}{{> '_maintenance-status-down'}}{{/eq}} - {{#eq status 'DB_MIGRATION_NEEDED'}}{{> '_maintenance-status-migration'}}{{/eq}} - {{#eq status 'DB_MIGRATION_RUNNING'}}{{> '_maintenance-status-migration'}}{{/eq}} + {{#unless setup}} - {{else}} + {{#eq status 'UP'}}{{> '_maintenance-status-up'}}{{/eq}} + {{#eq status 'STARTING'}}{{> '_maintenance-status-starting'}}{{/eq}} + {{#eq status 'DOWN'}}{{> '_maintenance-status-down'}}{{/eq}} + {{#eq status 'DB_MIGRATION_NEEDED'}}{{> '_maintenance-status-migration'}}{{/eq}} + {{#eq status 'DB_MIGRATION_RUNNING'}}{{> '_maintenance-status-migration'}}{{/eq}} - {{#eq state 'NO_MIGRATION'}}{{> '_maintenance-state-no-migration'}}{{/eq}} - {{#eq state 'MIGRATION_REQUIRED'}}{{> '_maintenance-state-migration-required'}}{{/eq}} - {{#eq state 'NOT_SUPPORTED'}}{{> '_maintenance-state-migration-not-supported'}}{{/eq}} - {{#eq state 'MIGRATION_RUNNING'}}{{> '_maintenance-state-migration-running'}}{{/eq}} - {{#eq state 'MIGRATION_SUCCEEDED'}}{{> '_maintenance-state-migration-succeeded'}}{{/eq}} - {{#eq state 'MIGRATION_FAILED'}}{{> '_maintenance-state-migration-failed'}}{{/eq}} + {{else}} - {{/unless}} + {{#eq state 'NO_MIGRATION'}}{{> '_maintenance-state-no-migration'}}{{/eq}} + {{#eq state 'MIGRATION_REQUIRED'}}{{> '_maintenance-state-migration-required'}}{{/eq}} + {{#eq state 'NOT_SUPPORTED'}}{{> '_maintenance-state-migration-not-supported'}}{{/eq}} + {{#eq state 'MIGRATION_RUNNING'}}{{> '_maintenance-state-migration-running'}}{{/eq}} + {{#eq state 'MIGRATION_SUCCEEDED'}}{{> '_maintenance-state-migration-succeeded'}}{{/eq}} + {{#eq state 'MIGRATION_FAILED'}}{{> '_maintenance-state-migration-failed'}}{{/eq}} -{{/eq}} + {{/unless}} + + {{/eq}} + +
+
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx b/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx index 2e2c92a8a61..fd9ece71a57 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx @@ -19,7 +19,10 @@ */ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import { getIdentityProviders, IdentityProvider } from '../../../api/users'; +import { getIdentityProviders } from '../../../api/users'; +import * as theme from '../../../app/theme'; +import { IdentityProvider } from '../../../app/types'; +import { getTextColor } from '../../../helpers/colors'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/urls'; @@ -75,7 +78,10 @@ export default class EmailAlreadyExists extends React.PureComponent + style={{ + backgroundColor: identityProvider.backgroundColor, + color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor) + }}> {identityProvider.name} -
-

- {query.email} }} - /> -

- {this.renderIdentityProvier(query.existingProvider, query.existingLogin)} -
+
+
+
+

+ {query.email} }} + /> +

+ {this.renderIdentityProvier(query.existingProvider, query.existingLogin)} +
-
-

{translate('sessions.email_already_exists.2')}

- {this.renderIdentityProvier(query.provider, query.login)} -
+
+

{translate('sessions.email_already_exists.2')}

+ {this.renderIdentityProvier(query.provider, query.login)} +
-
- {translate('sessions.email_already_exists.3')} -
    -
  • {translate('sessions.email_already_exists.4')}
  • -
  • {translate('sessions.email_already_exists.5')}
  • -
  • {translate('sessions.email_already_exists.6')}
  • -
-
+
+ {translate('sessions.email_already_exists.3')} +
    +
  • {translate('sessions.email_already_exists.4')}
  • +
  • {translate('sessions.email_already_exists.5')}
  • +
  • {translate('sessions.email_already_exists.6')}
  • +
+
-
); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.css b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.css index cd52e1e0851..fc74e4bba23 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.css +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.css @@ -17,6 +17,16 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +.login-page { + padding-top: 10vh; +} + +.login-form { + width: 300px; + margin-left: auto; + margin-right: auto; +} + .login-title { margin-bottom: 40px; line-height: 1.5; 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 index c581bfe000a..136f0b00522 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx @@ -21,8 +21,8 @@ import * as React from 'react'; import { Link } from 'react-router'; import OAuthProviders from './OAuthProviders'; import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer'; +import { IdentityProvider } from '../../../app/types'; import { translate } from '../../../helpers/l10n'; -import { IdentityProvider } from '../../../api/users'; import './LoginForm.css'; interface Props { @@ -70,7 +70,7 @@ export default class LoginForm extends React.PureComponent { : translate('login.login_to_sonarqube'); return ( -
+

{loginTitle}

{this.props.identityProviders.length > 0 && ( @@ -90,7 +90,7 @@ export default class LoginForm extends React.PureComponent {
) : ( -
+
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 index bedb56c1fb6..c1b706544b0 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginFormContainer.tsx @@ -22,7 +22,8 @@ import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import LoginForm from './LoginForm'; import { doLogin } from '../../../store/rootActions'; -import { IdentityProvider, getIdentityProviders } from '../../../api/users'; +import { getIdentityProviders } from '../../../api/users'; +import { IdentityProvider } from '../../../app/types'; import { getBaseUrl } from '../../../helpers/urls'; interface Props { 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 index 59f975dc9d7..8a07c646df8 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/Logout.tsx @@ -42,9 +42,9 @@ class Logout extends React.PureComponent { render() { return ( -
+
- {translate('logging_out')} +
{translate('logging_out')}
); } diff --git a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css index 99a8d520790..01d8ef46d8d 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css +++ b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css @@ -18,12 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ .oauth-providers > ul { - display: flex; - justify-content: space-around; - flex-wrap: wrap; + width: 180px; + margin-left: auto; + margin-right: auto; } .oauth-providers > ul > li { + position: relative; margin-bottom: 30px; } @@ -32,27 +33,32 @@ width: 180px; line-height: 22px; padding: 8px 12px; - border: none; + border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 2px; box-sizing: border-box; background-color: var(--darkBlue); color: #fff; white-space: nowrap; overflow: hidden; - text-align: center; text-overflow: ellipsis; } .oauth-providers > ul > li > a:hover, .oauth-providers > ul > li > a:focus { - box-shadow: inset 0 0 16px rgba(0, 0, 0, 0.3); + box-shadow: 0 0 16px rgba(0, 0, 0, 0.2); } .oauth-providers > ul > li > a > span { padding-left: 6px; } -.oauth-providers + form { +.oauth-providers-help { + position: absolute; + top: 12px; + right: -32px; +} + +.oauth-providers + .login-form { padding-top: 30px; border-top: 1px solid var(--barBorderColor); } 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 index f008e9f984a..5664080f828 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx @@ -19,18 +19,20 @@ */ import * as React from 'react'; import { translateWithParameters } from '../../../helpers/l10n'; -import { IdentityProvider } from '../../../api/users'; +import * as theme from '../../../app/theme'; +import { IdentityProvider } from '../../../app/types'; +import Tooltip from '../../../components/controls/Tooltip'; +import HelpIcon from '../../../components/icons-components/HelpIcon'; +import { getTextColor } from '../../../helpers/colors'; import { getBaseUrl } from '../../../helpers/urls'; import './OAuthProviders.css'; interface Props { - formatLabel?: (name: string) => string; identityProviders: IdentityProvider[]; returnTo: string; } export default function OAuthProviders(props: Props) { - const formatLabel = props.formatLabel || defaultFormatLabel; return (
    @@ -41,16 +43,25 @@ export default function OAuthProviders(props: Props) { `${getBaseUrl()}/sessions/init/${identityProvider.key}` + `?return_to=${encodeURIComponent(props.returnTo)}` } - style={{ backgroundColor: identityProvider.backgroundColor }} - title={formatLabel(identityProvider.name)}> + style={{ + backgroundColor: identityProvider.backgroundColor, + color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor) + }}> {identityProvider.name} - {formatLabel(identityProvider.name)} + {defaultFormatLabel(identityProvider.name)} + {identityProvider.helpMessage && ( + +
    + +
    +
    + )} ))}
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx b/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx index 712fe6065a7..c765e11ca15 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/Unauthorized.tsx @@ -33,17 +33,21 @@ export default function Unauthorized(props: Props) { const { message } = props.location.query; return ( -
-

{translate('unauthorized.message')}

+
+
+
+

{translate('unauthorized.message')}

- {!!message && ( -

- {translate('unauthorized.reason')} {message} -

- )} + {!!message && ( +

+ {translate('unauthorized.reason')} {message} +

+ )} -
- {translate('layout.home')} +
+ {translate('layout.home')} +
+
); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap index 95ec95ce038..096b7135b1c 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap @@ -1,108 +1,118 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`render 1`] = ` -
+
-

- + + mail@example.com + , + } + } + /> +

+
- mail@example.com - , + "backgroundColor": "#205081", + "color": "#fff", } } - /> -

+ > + Bitbucket + bar +
+
- Bitbucket - bar +

+ sessions.email_already_exists.2 +

+
+ GitHub + foo +
-
-
-

- sessions.email_already_exists.2 -

- GitHub - foo + sessions.email_already_exists.3 +
    +
  • + sessions.email_already_exists.4 +
  • +
  • + sessions.email_already_exists.5 +
  • +
  • + sessions.email_already_exists.6 +
  • +
-
-
- sessions.email_already_exists.3 - -
-
`; 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 index 8c6b6308238..fddd44f6bcd 100644 --- 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 @@ -2,6 +2,7 @@ exports[`expands more options 1`] = `

@@ -130,6 +133,7 @@ exports[`expands more options 2`] = ` exports[`logs in with identity provider 1`] = `

diff --git a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx index 411ddc18db8..f66cabe81ac 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx @@ -26,8 +26,8 @@ import Search from './Search'; import UsersList from './UsersList'; import { parseQuery, Query, serializeQuery } from './utils'; import ListFooter from '../../components/controls/ListFooter'; -import { getIdentityProviders, IdentityProvider, searchUsers, User } from '../../api/users'; -import { Paging } from '../../app/types'; +import { getIdentityProviders, searchUsers } from '../../api/users'; +import { Paging, IdentityProvider, User } from '../../app/types'; import { translate } from '../../helpers/l10n'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/UsersList.tsx index 556bf782802..de981b356f0 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersList.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersList.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import UserListItem from './components/UserListItem'; -import { IdentityProvider, User } from '../../api/users'; +import { IdentityProvider, User } from '../../app/types'; import { translate } from '../../helpers/l10n'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx b/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx new file mode 100644 index 00000000000..ff95230d2cf --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/__tests__/UsersList-test.tsx @@ -0,0 +1,71 @@ +/* + * 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 { shallow } from 'enzyme'; +import UsersList from '../UsersList'; + +const users = [ + { + login: 'luke', + name: 'Luke', + active: true, + scmAccounts: [], + local: false + }, + { + login: 'obi', + name: 'One', + active: true, + scmAccounts: [], + local: false + } +]; + +it('should render correctly', () => { + expect(getWrapper()).toMatchSnapshot(); +}); + +it('should show a group column', () => { + const wrapper = getWrapper({ organizationsEnabled: false }); + expect(wrapper.find('th').filterWhere(elem => elem.text() === 'my_profile.groups')).toHaveLength( + 1 + ); +}); + +function getWrapper(props = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/__tests__/UsersList.tsx deleted file mode 100644 index ff95230d2cf..00000000000 --- a/server/sonar-web/src/main/js/apps/users/__tests__/UsersList.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 { shallow } from 'enzyme'; -import UsersList from '../UsersList'; - -const users = [ - { - login: 'luke', - name: 'Luke', - active: true, - scmAccounts: [], - local: false - }, - { - login: 'obi', - name: 'One', - active: true, - scmAccounts: [], - local: false - } -]; - -it('should render correctly', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -it('should show a group column', () => { - const wrapper = getWrapper({ organizationsEnabled: false }); - expect(wrapper.find('th').filterWhere(elem => elem.text() === 'my_profile.groups')).toHaveLength( - 1 - ); -}); - -function getWrapper(props = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap new file mode 100644 index 00000000000..b3a9562ccdd --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList-test.tsx.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ + + + + + + + + + + + +
+ + + my_profile.scm_accounts + + users.tokens + +   +
+
+`; diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap deleted file mode 100644 index b3a9562ccdd..00000000000 --- a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/UsersList.tsx.snap +++ /dev/null @@ -1,70 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
- - - - - - - - - - - - -
- - - my_profile.scm_accounts - - users.tokens - -   -
-
-`; diff --git a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx index a88cab78930..a6ad6f8372d 100644 --- a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx @@ -19,7 +19,8 @@ */ import * as React from 'react'; import Modal from '../../../components/controls/Modal'; -import { deactivateUser, User } from '../../../api/users'; +import { deactivateUser } from '../../../api/users'; +import { User } from '../../../app/types'; import { translate, translateWithParameters } from '../../../helpers/l10n'; export interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx index 5a1bd050e79..fd6cc251dba 100644 --- a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx @@ -19,9 +19,9 @@ */ import * as React from 'react'; import * as escapeHtml from 'escape-html'; +import { User } from '../../../app/types'; import Modal from '../../../components/controls/Modal'; import SelectList from '../../../components/SelectList'; -import { User } from '../../../api/users'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/urls'; diff --git a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx index 6e8b686899d..053ece8b03d 100644 --- a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx @@ -21,8 +21,9 @@ import * as React from 'react'; import Modal from '../../../components/controls/Modal'; import addGlobalSuccessMessage from '../../../app/utils/addGlobalSuccessMessage'; import throwGlobalError from '../../../app/utils/throwGlobalError'; +import { User } from '../../../app/types'; import { parseError } from '../../../helpers/request'; -import { changePassword, User } from '../../../api/users'; +import { changePassword } from '../../../api/users'; import { translate } from '../../../helpers/l10n'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx index 79cf17f38cc..79676aeb23e 100644 --- a/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx @@ -38,8 +38,8 @@ */ import * as React from 'react'; import TokensForm from './TokensForm'; +import { User } from '../../../app/types'; import Modal from '../../../components/controls/Modal'; -import { User } from '../../../api/users'; import { translate } from '../../../helpers/l10n'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx b/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx index 63b30598e4b..ccd1471a245 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import DeactivateForm from './DeactivateForm'; import PasswordForm from './PasswordForm'; import UserForm from './UserForm'; -import { User } from '../../../api/users'; +import { User } from '../../../app/types'; import ActionsDropdown, { ActionsDropdownItem, ActionsDropdownDivider diff --git a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx index ab3a5f75deb..867d503b933 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx @@ -23,7 +23,8 @@ import UserScmAccountInput from './UserScmAccountInput'; import Modal from '../../../components/controls/Modal'; import throwGlobalError from '../../../app/utils/throwGlobalError'; import { parseError } from '../../../helpers/request'; -import { createUser, updateUser, User } from '../../../api/users'; +import { createUser, updateUser } from '../../../api/users'; +import { User } from '../../../app/types'; import { translate, translateWithParameters } from '../../../helpers/l10n'; export interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx b/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx index f47c43058fa..dceecaeafd1 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import GroupsForm from './GroupsForm'; import BulletListIcon from '../../../components/icons-components/BulletListIcon'; -import { User } from '../../../api/users'; +import { User } from '../../../app/types'; import { ButtonIcon } from '../../../components/ui/buttons'; import { translate, translateWithParameters } from '../../../helpers/l10n'; diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx index 8dc4a869445..4848a05c853 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx @@ -23,7 +23,7 @@ import UserActions from './UserActions'; import UserGroups from './UserGroups'; import UserListItemIdentity from './UserListItemIdentity'; import UserScmAccounts from './UserScmAccounts'; -import { IdentityProvider, User } from '../../../api/users'; +import { IdentityProvider, User } from '../../../app/types'; import BulletListIcon from '../../../components/icons-components/BulletListIcon'; import Avatar from '../../../components/ui/Avatar'; import { ButtonIcon } from '../../../components/ui/buttons'; diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx index 13a82987ef9..a609e1c9145 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx @@ -18,7 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { IdentityProvider, User } from '../../../api/users'; +import * as theme from '../../../app/theme'; +import { IdentityProvider, User } from '../../../app/types'; +import { getTextColor } from '../../../helpers/colors'; import { getBaseUrl } from '../../../helpers/urls'; interface Props { @@ -57,9 +59,13 @@ export function ExternalProvider({ identityProvider, user }: Props) {
+ style={{ + 'background-color': identityProvider.backgroundColor, + color: getTextColor(identityProvider.backgroundColor, theme.secondFontColor) + }}> {identityProvider.name} ); } - -/* eslint-disable no-bitwise, no-mixed-operators */ -function stringToColor(str: string) { - let hash = 0; - for (let i = 0; i < str.length; i++) { - hash = str.charCodeAt(i) + ((hash << 5) - hash); - } - let color = '#'; - for (let i = 0; i < 3; i++) { - const value = (hash >> (i * 8)) & 0xff; - color += ('00' + value.toString(16)).substr(-2); - } - return color; -} - -function getTextColor(background: string) { - const rgb = parseInt(background.substr(1), 16); - const r = (rgb >> 16) & 0xff; - const g = (rgb >> 8) & 0xff; - const b = (rgb >> 0) & 0xff; - const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; - return luma > 140 ? '#222' : '#fff'; -} diff --git a/server/sonar-web/src/main/js/helpers/colors.ts b/server/sonar-web/src/main/js/helpers/colors.ts new file mode 100644 index 00000000000..3d26b37b9d5 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/colors.ts @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/* eslint-disable no-bitwise, no-mixed-operators */ +export function stringToColor(str: string) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + let color = '#'; + for (let i = 0; i < 3; i++) { + const value = (hash >> (i * 8)) & 0xff; + color += ('00' + value.toString(16)).substr(-2); + } + return color; +} + +export function getTextColor(background: string, dark = '#222', light = '#fff') { + background = background.substr(1); + if (background.length === 3) { + // shortcut notation: #f90 + background = + background[0] + background[0] + background[1] + background[1] + background[2] + background[2]; + } + const rgb = parseInt(background.substr(1), 16); + const r = (rgb >> 16) & 0xff; + const g = (rgb >> 8) & 0xff; + const b = (rgb >> 0) & 0xff; + const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + return luma > 140 ? dark : light; +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index e9f5f8a0ed2..b64d7d91bc4 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -528,11 +528,11 @@ process.fail=Failed sessions.log_in=Log in sessions.email_already_exists.1=The email address {email} is already associated to this user account: -sessions.email_already_exists.2=By clicking on "Continue" you will associate this email address to a new user account: +sessions.email_already_exists.2=By clicking on "Continue" you will associate this email address to another user account: sessions.email_already_exists.3=This means the following: -sessions.email_already_exists.4=Your email address will be erased from this account. +sessions.email_already_exists.4=Your email address will be erased from the first account. sessions.email_already_exists.5=You will no longer receive email notifications from this account. -sessions.email_already_exists.6=Issues won't be automatically assigned on the first account anymore. +sessions.email_already_exists.6=Issues won't be automatically assigned to this account anymore. #------------------------------------------------------------------------------