aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2017-10-04 17:34:27 +0200
committerStas Vilchik <stas.vilchik@sonarsource.com>2017-10-05 12:12:43 +0200
commit76d113a7b4dae274132b2fe29f79c063d9a39588 (patch)
tree591132247a5e3774f969caefc64fcc1b6f34ed73 /server/sonar-web/src/main/js
parentaf039ace6676a976e367a6b9a2a52463028fc5a3 (diff)
downloadsonarqube-76d113a7b4dae274132b2fe29f79c063d9a39588.tar.gz
sonarqube-76d113a7b4dae274132b2fe29f79c063d9a39588.zip
SONAR-9707 Add possibility to reuse an existing token in the onboarding wizard
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js127
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js16
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap198
5 files changed, 273 insertions, 80 deletions
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js
index a9065a16b0a..d0e4b41b234 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js
@@ -172,7 +172,7 @@ export default class Onboarding extends React.PureComponent {
</div>
<div className="page-description">
{translateWithParameters(
- 'onboarding.header.description_x',
+ 'onboarding.header.description',
organizationsEnabled ? 3 : 2
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js
index 80ed22c805d..abcdb98b84e 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js
@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
+import classNames from 'classnames';
import Step from './Step';
import CloseIcon from '../../../components/icons-components/CloseIcon';
import { generateToken, revokeToken } from '../../../api/user-tokens';
@@ -36,7 +37,9 @@ type Props = {|
/*::
type State = {
+ existingToken:string,
loading: boolean,
+ selection: string,
tokenName?: string,
token?: string
};
@@ -46,7 +49,9 @@ export default class TokenStep extends React.PureComponent {
/*:: mounted: boolean; */
/*:: props: Props; */
state /*: State */ = {
- loading: false
+ existingToken: '',
+ loading: false,
+ selection: 'generate'
};
componentDidMount() {
@@ -57,6 +62,9 @@ export default class TokenStep extends React.PureComponent {
this.mounted = false;
}
+ getToken = () =>
+ this.state.selection === 'generate' ? this.state.token : this.state.existingToken;
+
handleTokenNameChange = (event /*: { target: HTMLInputElement } */) => {
this.setState({ tokenName: event.target.value });
};
@@ -103,13 +111,95 @@ export default class TokenStep extends React.PureComponent {
handleContinueClick = (event /*: Event */) => {
event.preventDefault();
- if (this.state.token) {
- this.props.onContinue(this.state.token);
+ const token = this.getToken();
+ if (token) {
+ this.props.onContinue(token);
}
};
+ handleGenerateClick = (event /*: Event */) => {
+ event.preventDefault();
+ this.setState({ selection: 'generate' });
+ };
+
+ handleUseExistingClick = (event /*: Event */) => {
+ event.preventDefault();
+ this.setState({ selection: 'use-existing' });
+ };
+
+ handleExisingTokenChange = (event /*: { currentTarget: HTMLInputElement } */) => {
+ this.setState({ existingToken: event.currentTarget.value });
+ };
+
+ renderGenerateOption = () => (
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleGenerateClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'generate'
+ })}
+ />
+ {translate('onboading.token.generate_token')}
+ </a>
+ {this.state.selection === 'generate' && (
+ <div className="big-spacer-top">
+ <form onSubmit={this.handleTokenGenerate}>
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={this.handleTokenNameChange}
+ placeholder={translate('onboading.token.generate_token.placeholder')}
+ required={true}
+ type="text"
+ value={this.state.tokenName || ''}
+ />
+ {this.state.loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <button className="text-middle" disabled={!this.state.tokenName}>
+ {translate('onboarding.token.generate')}
+ </button>
+ )}
+ </form>
+ </div>
+ )}
+ </div>
+ );
+
+ renderUseExistingOption = () => (
+ <div className="big-spacer-top">
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleUseExistingClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'use-existing'
+ })}
+ />
+ {translate('onboarding.token.use_existing_token')}
+ </a>
+ {this.state.selection === 'use-existing' && (
+ <div className="big-spacer-top">
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={this.handleExisingTokenChange}
+ placeholder={translate('onboarding.token.use_existing_token.placeholder')}
+ required={true}
+ type="text"
+ value={this.state.existingToken}
+ />
+ </div>
+ )}
+ </div>
+ );
+
renderForm = () => {
- const { loading, token, tokenName } = this.state;
+ const { existingToken, loading, selection, token, tokenName } = this.state;
return (
<div className="boxed-group-inner">
@@ -129,27 +219,16 @@ export default class TokenStep extends React.PureComponent {
)}
</form>
) : (
- <form onSubmit={this.handleTokenGenerate}>
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={this.handleTokenNameChange}
- placeholder={translate('onboarding.token.placeholder')}
- required={true}
- type="text"
- value={tokenName || ''}
- />
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <button className="text-middle">{translate('onboarding.token.generate')}</button>
- )}
- </form>
+ <div>
+ {this.renderGenerateOption()}
+ {this.renderUseExistingOption()}
+ </div>
)}
<div className="note big-spacer-top width-50">{translate('onboarding.token.text')}</div>
- {token != null && (
+ {((selection === 'generate' && token != null) ||
+ (selection === 'use-existing' && existingToken)) && (
<div className="big-spacer-top">
<button className="js-continue" onClick={this.handleContinueClick}>
{translate('continue')}
@@ -161,7 +240,8 @@ export default class TokenStep extends React.PureComponent {
};
renderResult = () => {
- const { token, tokenName } = this.state;
+ const { selection, tokenName } = this.state;
+ const token = this.getToken();
if (!token) {
return null;
@@ -170,8 +250,7 @@ export default class TokenStep extends React.PureComponent {
return (
<div className="boxed-group-actions">
<i className="icon-check spacer-right" />
- {tokenName}
- {': '}
+ {selection === 'generate' && tokenName && `${tokenName}: `}
<strong>{token}</strong>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js
index 8a4608bb7ab..2c2f07d5b75 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js
@@ -77,3 +77,19 @@ it('continues', () => {
click(wrapper.find('.js-continue'));
expect(onContinue).toBeCalledWith('abcd1234');
});
+
+it('uses existing token', () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <TokenStep
+ finished={false}
+ open={true}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ stepNumber={1}
+ />
+ );
+ wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' });
+ click(wrapper.find('.js-continue'));
+ expect(onContinue).toBeCalledWith('abcd1234');
+});
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap
index f8234801320..3fed8ff9708 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap
@@ -39,7 +39,7 @@ exports[`guides for on-premise 1`] = `
<div
className="page-description"
>
- onboarding.header.description_x.2
+ onboarding.header.description.2
</div>
</header>
<TokenStep
@@ -99,7 +99,7 @@ exports[`guides for on-premise 2`] = `
<div
className="page-description"
>
- onboarding.header.description_x.2
+ onboarding.header.description.2
</div>
</header>
<TokenStep
@@ -160,7 +160,7 @@ exports[`guides for sonarcloud 1`] = `
<div
className="page-description"
>
- onboarding.header.description_x.3
+ onboarding.header.description.3
</div>
</header>
<OrganizationStep
@@ -233,7 +233,7 @@ exports[`guides for sonarcloud 2`] = `
<div
className="page-description"
>
- onboarding.header.description_x.3
+ onboarding.header.description.3
</div>
</header>
<OrganizationStep
@@ -307,7 +307,7 @@ exports[`guides for sonarcloud 3`] = `
<div
className="page-description"
>
- onboarding.header.description_x.3
+ onboarding.header.description.3
</div>
</header>
<OrganizationStep
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
index 65138e0b498..38b83ffa20a 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
@@ -35,24 +35,57 @@ exports[`generates token 1`] = `
<div
className="boxed-group-inner"
>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.placeholder"
- required={true}
- type="text"
- value=""
- />
- <button
- className="text-middle"
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboading.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboading.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <button
+ className="text-middle"
+ disabled={true}
+ >
+ onboarding.token.generate
+ </button>
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
>
- onboarding.token.generate
- </button>
- </form>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
<div
className="note big-spacer-top width-50"
>
@@ -99,22 +132,54 @@ exports[`generates token 2`] = `
<div
className="boxed-group-inner"
>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.placeholder"
- required={true}
- type="text"
- value="my token"
- />
- <i
- className="spinner text-middle"
- />
- </form>
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboading.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboading.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value="my token"
+ />
+ <i
+ className="spinner text-middle"
+ />
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
<div
className="note big-spacer-top width-50"
>
@@ -419,24 +484,57 @@ exports[`revokes token 3`] = `
<div
className="boxed-group-inner"
>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.placeholder"
- required={true}
- type="text"
- value=""
- />
- <button
- className="text-middle"
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboading.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboading.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <button
+ className="text-middle"
+ disabled={true}
+ >
+ onboarding.token.generate
+ </button>
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
>
- onboarding.token.generate
- </button>
- </form>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
<div
className="note big-spacer-top width-50"
>