Browse Source

apply feedback on onboarding (#2175)

tags/6.5-M2
Stas Vilchik 7 years ago
parent
commit
ac756ae021
21 changed files with 745 additions and 424 deletions
  1. 33
    5
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js
  2. 4
    1
      server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js
  3. 5
    4
      server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js
  4. 5
    4
      server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js
  5. 76
    58
      server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js
  6. 7
    5
      server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js
  7. 9
    4
      server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js
  8. 18
    4
      server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js
  9. 20
    20
      server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js
  10. 3
    0
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js
  11. 24
    3
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js
  12. 20
    0
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js
  13. 27
    3
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js
  14. 36
    10
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap
  15. 36
    10
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap
  16. 265
    209
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap
  17. 5
    2
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap
  18. 129
    63
      server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
  19. 15
    2
      server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css
  20. 5
    15
      server/sonar-web/src/main/less/components/modals.less
  21. 3
    2
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 33
- 5
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js View File

@@ -25,9 +25,11 @@ import GlobalNavMenu from './GlobalNavMenu';
import GlobalNavUserContainer from './GlobalNavUserContainer';
import Search from '../../search/Search';
import GlobalHelp from '../../help/GlobalHelp';
import Tooltip from '../../../../components/controls/Tooltip';
import HelpIcon from '../../../../components/icons-components/HelpIcon';
import OnboardingModal from '../../../../apps/tutorials/onboarding/OnboardingModal';
import { getCurrentUser, getAppState, getSettingValue } from '../../../../store/rootReducer';
import { translate } from '../../../../helpers/l10n';

type Props = {
appState: { organizationsEnabled: boolean },
@@ -37,12 +39,18 @@ type Props = {

type State = {
helpOpen: boolean,
onboardingTutorialOpen: boolean
onboardingTutorialOpen: boolean,
onboardingTutorialTooltip: boolean
};

class GlobalNav extends React.PureComponent {
interval: ?number;
props: Props;
state: State = { helpOpen: false, onboardingTutorialOpen: false };
state: State = {
helpOpen: false,
onboardingTutorialOpen: false,
onboardingTutorialTooltip: false
};

componentDidMount() {
window.addEventListener('keypress', this.onKeyPress);
@@ -52,6 +60,9 @@ class GlobalNav extends React.PureComponent {
}

componentWillUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
window.removeEventListener('keypress', this.onKeyPress);
}

@@ -76,7 +87,14 @@ class GlobalNav extends React.PureComponent {

openOnboardingTutorial = () => this.setState({ helpOpen: false, onboardingTutorialOpen: true });

closeOnboardingTutorial = () => this.setState({ onboardingTutorialOpen: false });
finishOnboardingTutorial = () => this.setState({ onboardingTutorialOpen: false });

skipOnboardingTutorial = () => {
this.setState({ onboardingTutorialOpen: false, onboardingTutorialTooltip: true });
this.interval = setInterval(() => {
this.setState({ onboardingTutorialTooltip: false });
}, 3000);
};

render() {
return (
@@ -90,7 +108,14 @@ class GlobalNav extends React.PureComponent {
<Search appState={this.props.appState} currentUser={this.props.currentUser} />
<li>
<a className="navbar-help" onClick={this.handleHelpClick} href="#">
<HelpIcon />
{this.state.onboardingTutorialTooltip
? <Tooltip
defaultVisible={true}
overlay={translate('tutorials.follow_later')}
trigger="manual">
<HelpIcon />
</Tooltip>
: <HelpIcon />}
</a>
</li>
<GlobalNavUserContainer {...this.props} />
@@ -106,7 +131,10 @@ class GlobalNav extends React.PureComponent {
/>}

{this.state.onboardingTutorialOpen &&
<OnboardingModal onClose={this.closeOnboardingTutorial} />}
<OnboardingModal
onFinish={this.finishOnboardingTutorial}
onSkip={this.skipOnboardingTutorial}
/>}
</nav>
);
}

+ 4
- 1
server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js View File

@@ -50,7 +50,8 @@ export default class AnalysisStep extends React.PureComponent {

handleLanguageSelect = (result?: Result) => {
this.setState({ result });
this.props.onFinish(result && result.projectKey);
const projectKey = result && result.language !== 'java' ? result.projectKey : undefined;
this.props.onFinish(projectKey);
};

handleLanguageReset = () => {
@@ -174,6 +175,8 @@ export default class AnalysisStep extends React.PureComponent {
render() {
return (
<Step
finished={false}
onOpen={() => {}}
open={this.props.open}
renderForm={this.renderForm}
renderResult={this.renderResult}

+ 5
- 4
server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js View File

@@ -20,6 +20,7 @@
// @flow
import React from 'react';
import { debounce } from 'lodash';
import CloseIcon from '../../../components/icons-components/CloseIcon';
import {
createOrganization,
deleteOrganization,
@@ -124,9 +125,9 @@ export default class NewOrganizationForm extends React.PureComponent {
? <form onSubmit={this.handleOrganizationDelete}>
<span className="spacer-right text-middle">{organization}</span>
{loading
? <i className="spinner" />
: <button className="button-clean">
<i className="icon-delete" />
? <i className="spinner text-middle" />
: <button className="button-clean text-middle">
<CloseIcon className="icon-red" />
</button>}
</form>
: <form onSubmit={this.handleOrganizationCreate}>
@@ -142,7 +143,7 @@ export default class NewOrganizationForm extends React.PureComponent {
value={organization}
/>
{loading
? <i className="spinner" />
? <i className="spinner text-middle" />
: <button className="text-middle" disabled={!valid}>{translate('create')}</button>}
{!unique &&
<span className="big-spacer-left text-danger text-middle">

+ 5
- 4
server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js View File

@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
import CloseIcon from '../../../components/icons-components/CloseIcon';
import { createProject, deleteProject } from '../../../api/components';
import { translate } from '../../../helpers/l10n';

@@ -109,9 +110,9 @@ export default class NewProjectForm extends React.PureComponent {
? <form onSubmit={this.handleProjectDelete}>
<span className="spacer-right text-middle">{projectKey}</span>
{loading
? <i className="spinner" />
: <button className="button-clean">
<i className="icon-delete" />
? <i className="spinner text-middle" />
: <button className="button-clean text-middle">
<CloseIcon className="icon-red" />
</button>}
</form>
: <form onSubmit={this.handleProjectCreate}>
@@ -126,7 +127,7 @@ export default class NewProjectForm extends React.PureComponent {
value={projectKey}
/>
{loading
? <i className="spinner" />
? <i className="spinner text-middle" />
: <button className="text-middle" disabled={!valid}>{translate('Done')}</button>}
<div className="note spacer-top abs-width-300">
{translate('onboarding.project_key_requirement')}

+ 76
- 58
server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js View File

@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
import Helmet from 'react-helmet';
import TokenStep from './TokenStep';
import OrganizationStep from './OrganizationStep';
import AnalysisStep from './AnalysisStep';
@@ -29,12 +30,13 @@ import { getProjectUrl } from '../../../helpers/urls';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import './styles.css';

type Props = {
type Props = {|
currentUser: { login: string, isLoggedIn: boolean },
onFinish: () => void,
onSkip: () => void,
organizationsEnabled: boolean,
sonarCloud: boolean
};
|};

type State = {
finished: boolean,
@@ -74,12 +76,16 @@ export default class Onboarding extends React.PureComponent {
this.mounted = false;
}

finishOnboarding = () => {
finishOnboarding = (skipped: boolean = false) => {
this.setState({ skipping: true });
skipOnboarding().then(
() => {
if (this.mounted) {
this.props.onSkip();
if (skipped) {
this.props.onSkip();
} else {
this.props.onFinish();
}

if (this.state.projectKey) {
this.context.router.push(getProjectUrl(this.state.projectKey));
@@ -107,9 +113,13 @@ export default class Onboarding extends React.PureComponent {
this.setState({ organization, step: 'token' });
};

handleTokenOpen = () => this.setState({ step: 'token' });

handleOrganizationOpen = () => this.setState({ step: 'organization' });

handleSkipClick = (event: Event) => {
event.preventDefault();
this.finishOnboarding();
this.finishOnboarding(true);
};

handleFinish = (projectKey?: string) => this.setState({ finished: true, projectKey });
@@ -126,61 +136,69 @@ export default class Onboarding extends React.PureComponent {

let stepNumber = 1;

const header = translate(sonarCloud ? 'onboarding.header.sonarcloud' : 'onboarding.header');

return (
<div className="page page-limited">
<header className="page-header">
<h1 className="page-title">
{translate(sonarCloud ? 'onboarding.header.sonarcloud' : 'onboarding.header')}
</h1>
<div className="page-actions">
{this.state.skipping
? <i className="spinner" />
: <a className="js-skip text-muted" href="#" onClick={this.handleSkipClick}>
{translate('tutorials.skip')}
</a>}
</div>
<div className="page-description">
{translate('onboarding.header.description')}
</div>
</header>

{organizationsEnabled &&
<OrganizationStep
currentUser={this.props.currentUser}
onContinue={this.handleOrganizationDone}
open={step === 'organization'}
<div className="modal-container">
<Helmet title={header} titleTemplate="%s" />

<div className="page page-limited onboarding">
<header className="page-header">
<h1 className="page-title">{header}</h1>
<div className="page-actions">
{this.state.skipping
? <i className="spinner" />
: <a className="js-skip text-muted" href="#" onClick={this.handleSkipClick}>
{translate('tutorials.skip')}
</a>}
</div>
<div className="page-description">
{translate('onboarding.header.description')}
</div>
</header>

{organizationsEnabled &&
<OrganizationStep
currentUser={this.props.currentUser}
finished={this.state.organization != null}
onContinue={this.handleOrganizationDone}
onOpen={this.handleOrganizationOpen}
open={step === 'organization'}
stepNumber={stepNumber++}
/>}

<TokenStep
finished={this.state.token != null}
onContinue={this.handleTokenDone}
onOpen={this.handleTokenOpen}
open={step === 'token'}
stepNumber={stepNumber++}
/>}

<TokenStep
onContinue={this.handleTokenDone}
open={step === 'token'}
stepNumber={stepNumber++}
/>

<AnalysisStep
onFinish={this.handleFinish}
onReset={this.handleReset}
organization={this.state.organization}
open={step === 'analysis'}
sonarCloud={sonarCloud}
stepNumber={stepNumber}
token={token}
/>

{this.state.finished &&
!this.state.skipping &&
(this.state.projectKey
? <ProjectWatcher
onFinish={this.finishOnboarding}
onTimeout={this.handleTimeout}
projectKey={this.state.projectKey}
/>
: <footer className="text-right">
<a className="button" href="#" onClick={this.handleSkipClick}>
{translate('tutorials.finish')}
</a>
</footer>)}
/>

<AnalysisStep
onFinish={this.handleFinish}
onReset={this.handleReset}
organization={this.state.organization}
open={step === 'analysis'}
sonarCloud={sonarCloud}
stepNumber={stepNumber}
token={token}
/>

{this.state.finished &&
!this.state.skipping &&
(this.state.projectKey
? <ProjectWatcher
onFinish={this.finishOnboarding}
onTimeout={this.handleTimeout}
projectKey={this.state.projectKey}
/>
: <footer className="text-right">
<a className="button" href="#" onClick={this.handleSkipClick}>
{translate('tutorials.finish')}
</a>
</footer>)}
</div>
</div>
);
}

+ 7
- 5
server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js View File

@@ -22,9 +22,10 @@ import React from 'react';
import Modal from 'react-modal';
import { translate } from '../../../helpers/l10n';

type Props = {
onClose: () => void
};
type Props = {|
onFinish: () => void,
onSkip: () => void
|};

type State = {
OnboardingContainer?: Object
@@ -60,9 +61,10 @@ export default class OnboardingModal extends React.PureComponent {
<Modal
isOpen={true}
contentLabel={translate('tutorials.onboarding')}
className="modal modal-full-screen"
className="modal modal-large"
overlayClassName="modal-overlay">
{OnboardingContainer != null && <OnboardingContainer onSkip={this.props.onClose} />}
{OnboardingContainer != null &&
<OnboardingContainer onFinish={this.props.onFinish} onSkip={this.props.onSkip} />}
</Modal>
);
}

+ 9
- 4
server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js View File

@@ -27,11 +27,14 @@ import NewOrganizationForm from './NewOrganizationForm';
import { getMyOrganizations } from '../../../api/organizations';
import { translate } from '../../../helpers/l10n';

type Props = {
type Props = {|
currentUser: { login: string, isLoggedIn: boolean },
finished: boolean,
onOpen: () => void,
onContinue: (organization: string) => void,
open: boolean,
onContinue: (organization: string) => void
};
stepNumber: number
|};

type State = {
loading: boolean,
@@ -229,10 +232,12 @@ export default class OrganizationStep extends React.PureComponent {
render() {
return (
<Step
finished={this.props.finished}
onOpen={this.props.onOpen}
open={this.props.open}
renderForm={this.renderForm}
renderResult={this.renderResult}
stepNumber={1}
stepNumber={this.props.stepNumber}
stepTitle={translate('onboarding.organization.header')}
/>
);

+ 18
- 4
server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js View File

@@ -21,21 +21,35 @@
import React from 'react';
import classNames from 'classnames';

type Props = {
type Props = {|
finished: boolean,
onOpen: () => void,
open: boolean,
renderForm: () => React.Element<*>,
renderResult: () => ?React.Element<*>,
stepNumber: number,
stepTitle: string
};
|};

export default function Step(props: Props) {
const className = classNames('boxed-group', 'onboarding-step', {
'onboarding-step-open': props.open
'is-open': props.open,
'is-finished': props.finished
});

const clickable = !props.open && props.finished;

const handleClick = (event: Event) => {
event.preventDefault;
props.onOpen();
};

return (
<div className={className}>
<div
className={className}
onClick={clickable ? handleClick : undefined}
role={clickable ? 'button' : undefined}
tabIndex={clickable ? 0 : undefined}>
<div className="onboarding-step-number">{props.stepNumber}</div>
{!props.open && props.renderResult()}
<div className="boxed-group-header">

+ 20
- 20
server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js View File

@@ -20,14 +20,17 @@
// @flow
import React from 'react';
import Step from './Step';
import CloseIcon from '../../../components/icons-components/CloseIcon';
import { generateToken, revokeToken } from '../../../api/user-tokens';
import { translate } from '../../../helpers/l10n';

type Props = {
type Props = {|
finished: boolean,
open: boolean,
onContinue: (token: string) => void,
onOpen: () => void,
stepNumber: number
};
|};

type State = {
loading: boolean,
@@ -38,11 +41,6 @@ type State = {
export default class TokenStep extends React.PureComponent {
mounted: boolean;
props: Props;

static defaultProps = {
stepNumber: 1
};

state: State = {
loading: false
};
@@ -111,24 +109,20 @@ export default class TokenStep extends React.PureComponent {

return (
<div className="boxed-group-inner">
<div className="big-spacer-bottom width-50">
{translate('onboarding.token.text')}
</div>

{token != null
? <form onSubmit={this.handleTokenRevoke}>
{tokenName}{': '}
<span className="monospaced spacer-right">{token}</span>
<span className="text-middle">{tokenName}{': '}</span>
<strong className="spacer-right text-middle">{token}</strong>
{loading
? <i className="spinner" />
: <button className="button-clean" onClick={this.handleTokenRevoke}>
<i className="icon-delete" />
? <i className="spinner text-middle" />
: <button className="button-clean text-middle" onClick={this.handleTokenRevoke}>
<CloseIcon className="icon-red" />
</button>}
</form>
: <form onSubmit={this.handleTokenGenerate}>
<input
autoFocus={true}
className="input-large spacer-right"
className="input-large spacer-right text-middle"
onChange={this.handleTokenNameChange}
placeholder={translate('onboarding.token.placeholder')}
required={true}
@@ -136,10 +130,14 @@ export default class TokenStep extends React.PureComponent {
value={tokenName || ''}
/>
{loading
? <i className="spinner" />
: <button>{translate('onboarding.token.generate')}</button>}
? <i className="spinner text-middle" />
: <button className="text-middle">{translate('onboarding.token.generate')}</button>}
</form>}

<div className="note big-spacer-top width-50">
{translate('onboarding.token.text')}
</div>

{token != null &&
<div className="big-spacer-top">
<button className="js-continue" onClick={this.handleContinueClick}>
@@ -161,7 +159,7 @@ export default class TokenStep extends React.PureComponent {
<div className="boxed-group-actions">
<i className="icon-check spacer-right" />
{tokenName}{': '}
<strong className="monospaced">{token}</strong>
<strong>{token}</strong>
</div>
);
};
@@ -169,6 +167,8 @@ export default class TokenStep extends React.PureComponent {
render() {
return (
<Step
finished={this.props.finished}
onOpen={this.props.onOpen}
open={this.props.open}
renderForm={this.renderForm}
renderResult={this.renderResult}

+ 3
- 0
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js View File

@@ -33,6 +33,7 @@ it('guides for on-premise', () => {
const wrapper = shallow(
<Onboarding
currentUser={currentUser}
onFinish={jest.fn()}
onSkip={jest.fn()}
organizationsEnabled={false}
sonarCloud={false}
@@ -50,6 +51,7 @@ it('guides for sonarcloud', () => {
const wrapper = shallow(
<Onboarding
currentUser={currentUser}
onFinish={jest.fn()}
onSkip={jest.fn()}
organizationsEnabled={true}
sonarCloud={true}
@@ -73,6 +75,7 @@ it('skips', () => {
const wrapper = mount(
<Onboarding
currentUser={currentUser}
onFinish={jest.fn()}
onSkip={onSkip}
organizationsEnabled={false}
sonarCloud={false}

+ 24
- 3
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js View File

@@ -32,7 +32,14 @@ const currentUser = { isLoggedIn: true, login: 'user' };
it('works with personal organization', () => {
const onContinue = jest.fn();
const wrapper = mount(
<OrganizationStep currentUser={currentUser} onContinue={onContinue} open={true} />
<OrganizationStep
currentUser={currentUser}
finished={false}
onContinue={onContinue}
onOpen={jest.fn()}
open={true}
stepNumber={1}
/>
);
click(wrapper.find('.js-continue'));
expect(onContinue).toBeCalledWith('user');
@@ -41,7 +48,14 @@ it('works with personal organization', () => {
it('works with existing organization', () => {
const onContinue = jest.fn();
const wrapper = mount(
<OrganizationStep currentUser={currentUser} onContinue={onContinue} open={true} />
<OrganizationStep
currentUser={currentUser}
finished={false}
onContinue={onContinue}
onOpen={jest.fn()}
open={true}
stepNumber={1}
/>
);
return doAsync(() => {
click(wrapper.find('.js-existing'));
@@ -54,7 +68,14 @@ it('works with existing organization', () => {
it('works with new organization', () => {
const onContinue = jest.fn();
const wrapper = mount(
<OrganizationStep currentUser={currentUser} onContinue={onContinue} open={true} />
<OrganizationStep
currentUser={currentUser}
finished={false}
onContinue={onContinue}
onOpen={jest.fn()}
open={true}
stepNumber={1}
/>
);
click(wrapper.find('.js-new'));
wrapper.find('NewOrganizationForm').prop('onDone')('new');

+ 20
- 0
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js View File

@@ -21,10 +21,13 @@
import React from 'react';
import { shallow } from 'enzyme';
import Step from '../Step';
import { click } from '../../../../helpers/testUtils';

it('renders', () => {
const wrapper = shallow(
<Step
finished={true}
onOpen={jest.fn()}
open={true}
renderForm={() => <div>form</div>}
renderResult={() => <div>result</div>}
@@ -36,3 +39,20 @@ it('renders', () => {
wrapper.setProps({ open: false });
expect(wrapper).toMatchSnapshot();
});

it('re-opens', () => {
const onOpen = jest.fn();
const wrapper = shallow(
<Step
finished={true}
onOpen={onOpen}
open={false}
renderForm={() => <div>form</div>}
renderResult={() => <div>result</div>}
stepNumber={1}
stepTitle="First Step"
/>
);
click(wrapper);
expect(onOpen).toBeCalled();
});

+ 27
- 3
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js View File

@@ -29,7 +29,15 @@ jest.mock('../../../../api/user-tokens', () => ({
}));

it('generates token', () => {
const wrapper = mount(<TokenStep open={true} onContinue={jest.fn()} />);
const wrapper = mount(
<TokenStep
finished={false}
open={true}
onContinue={jest.fn()}
onOpen={jest.fn()}
stepNumber={1}
/>
);
expect(wrapper).toMatchSnapshot();
change(wrapper.find('input'), 'my token');
submit(wrapper.find('form'));
@@ -38,7 +46,15 @@ it('generates token', () => {
});

it('revokes token', () => {
const wrapper = mount(<TokenStep open={true} onContinue={jest.fn()} />);
const wrapper = mount(
<TokenStep
finished={false}
open={true}
onContinue={jest.fn()}
onOpen={jest.fn()}
stepNumber={1}
/>
);
wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
expect(wrapper).toMatchSnapshot();
submit(wrapper.find('form'));
@@ -48,7 +64,15 @@ it('revokes token', () => {

it('continues', () => {
const onContinue = jest.fn();
const wrapper = mount(<TokenStep open={true} onContinue={onContinue} />);
const wrapper = mount(
<TokenStep
finished={false}
open={true}
onContinue={onContinue}
onOpen={jest.fn()}
stepNumber={1}
/>
);
wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
click(wrapper.find('.js-continue'));
expect(onContinue).toBeCalledWith('abcd1234');

+ 36
- 10
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap View File

@@ -54,7 +54,7 @@ exports[`creates new organization 2`] = `
value="foo"
/>
<i
className="spinner"
className="spinner text-middle"
/>
<div
className="note spacer-top abs-width-300"
@@ -79,11 +79,24 @@ exports[`creates new organization 3`] = `
foo
</span>
<button
className="button-clean"
className="button-clean text-middle"
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
</NewOrganizationForm>
@@ -103,11 +116,24 @@ exports[`deletes organization 1`] = `
foo
</span>
<button
className="button-clean"
className="button-clean text-middle"
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
</NewOrganizationForm>
@@ -127,7 +153,7 @@ exports[`deletes organization 2`] = `
foo
</span>
<i
className="spinner"
className="spinner text-middle"
/>
</form>
</NewOrganizationForm>

+ 36
- 10
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap View File

@@ -69,7 +69,7 @@ exports[`creates new project 2`] = `
value="foo"
/>
<i
className="spinner"
className="spinner text-middle"
/>
<div
className="note spacer-top abs-width-300"
@@ -103,11 +103,24 @@ exports[`creates new project 3`] = `
foo
</span>
<button
className="button-clean"
className="button-clean text-middle"
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
</div>
@@ -136,11 +149,24 @@ exports[`deletes project 1`] = `
foo
</span>
<button
className="button-clean"
className="button-clean text-middle"
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
</div>
@@ -169,7 +195,7 @@ exports[`deletes project 2`] = `
foo
</span>
<i
className="spinner"
className="spinner text-middle"
/>
</form>
</div>

+ 265
- 209
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap View File

@@ -2,257 +2,313 @@

exports[`guides for on-premise 1`] = `
<div
className="page page-limited"
className="modal-container"
>
<header
className="page-header"
<HelmetWrapper
title="onboarding.header"
titleTemplate="%s"
/>
<div
className="page page-limited onboarding"
>
<h1
className="page-title"
>
onboarding.header
</h1>
<div
className="page-actions"
<header
className="page-header"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
<h1
className="page-title"
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<TokenStep
onContinue={[Function]}
open={true}
stepNumber={1}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
sonarCloud={false}
stepNumber={2}
/>
onboarding.header
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
sonarCloud={false}
stepNumber={2}
/>
</div>
</div>
`;

exports[`guides for on-premise 2`] = `
<div
className="page page-limited"
className="modal-container"
>
<header
className="page-header"
<HelmetWrapper
title="onboarding.header"
titleTemplate="%s"
/>
<div
className="page page-limited onboarding"
>
<h1
className="page-title"
<header
className="page-header"
>
onboarding.header
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
<h1
className="page-title"
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<TokenStep
onContinue={[Function]}
open={false}
stepNumber={1}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
sonarCloud={false}
stepNumber={2}
token="abcd1234"
/>
onboarding.header
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<TokenStep
finished={true}
onContinue={[Function]}
onOpen={[Function]}
open={false}
stepNumber={1}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
sonarCloud={false}
stepNumber={2}
token="abcd1234"
/>
</div>
</div>
`;

exports[`guides for sonarcloud 1`] = `
<div
className="page page-limited"
className="modal-container"
>
<header
className="page-header"
<HelmetWrapper
title="onboarding.header.sonarcloud"
titleTemplate="%s"
/>
<div
className="page page-limited onboarding"
>
<h1
className="page-title"
<header
className="page-header"
>
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
<h1
className="page-title"
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
}
}
}
onContinue={[Function]}
open={true}
stepNumber={1}
/>
<TokenStep
onContinue={[Function]}
open={false}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
sonarCloud={true}
stepNumber={3}
/>
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
/>
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={false}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
sonarCloud={true}
stepNumber={3}
/>
</div>
</div>
`;

exports[`guides for sonarcloud 2`] = `
<div
className="page page-limited"
className="modal-container"
>
<header
className="page-header"
<HelmetWrapper
title="onboarding.header.sonarcloud"
titleTemplate="%s"
/>
<div
className="page page-limited onboarding"
>
<h1
className="page-title"
>
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
<header
className="page-header"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
<h1
className="page-title"
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
}
}
}
onContinue={[Function]}
open={false}
stepNumber={1}
/>
<TokenStep
onContinue={[Function]}
open={true}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
organization="my-org"
sonarCloud={true}
stepNumber={3}
/>
finished={true}
onContinue={[Function]}
onOpen={[Function]}
open={false}
stepNumber={1}
/>
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
organization="my-org"
sonarCloud={true}
stepNumber={3}
/>
</div>
</div>
`;

exports[`guides for sonarcloud 3`] = `
<div
className="page page-limited"
className="modal-container"
>
<header
className="page-header"
<HelmetWrapper
title="onboarding.header.sonarcloud"
titleTemplate="%s"
/>
<div
className="page page-limited onboarding"
>
<h1
className="page-title"
>
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
<header
className="page-header"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
<h1
className="page-title"
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
onboarding.header.sonarcloud
</h1>
<div
className="page-actions"
>
<a
className="js-skip text-muted"
href="#"
onClick={[Function]}
>
tutorials.skip
</a>
</div>
<div
className="page-description"
>
onboarding.header.description
</div>
</header>
<OrganizationStep
currentUser={
Object {
"isLoggedIn": true,
"login": "admin",
}
}
}
onContinue={[Function]}
open={false}
stepNumber={1}
/>
<TokenStep
onContinue={[Function]}
open={false}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
organization="my-org"
sonarCloud={true}
stepNumber={3}
token="abcd1234"
/>
finished={true}
onContinue={[Function]}
onOpen={[Function]}
open={false}
stepNumber={1}
/>
<TokenStep
finished={true}
onContinue={[Function]}
onOpen={[Function]}
open={false}
stepNumber={2}
/>
<AnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
organization="my-org"
sonarCloud={true}
stepNumber={3}
token="abcd1234"
/>
</div>
</div>
`;

+ 5
- 2
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap View File

@@ -2,7 +2,7 @@

exports[`renders 1`] = `
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open is-finished"
>
<div
className="onboarding-step-number"
@@ -24,7 +24,10 @@ exports[`renders 1`] = `

exports[`renders 2`] = `
<div
className="boxed-group onboarding-step"
className="boxed-group onboarding-step is-finished"
onClick={[Function]}
role="button"
tabIndex={0}
>
<div
className="onboarding-step-number"

+ 129
- 63
server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap View File

@@ -2,11 +2,15 @@

exports[`generates token 1`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -14,7 +18,7 @@ exports[`generates token 1`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -31,27 +35,29 @@ exports[`generates token 1`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
<input
autoFocus={true}
className="input-large spacer-right"
className="input-large spacer-right text-middle"
onChange={[Function]}
placeholder="onboarding.token.placeholder"
required={true}
type="text"
value=""
/>
<button>
<button
className="text-middle"
>
onboarding.token.generate
</button>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
</div>
</div>
</Step>
@@ -60,11 +66,15 @@ exports[`generates token 1`] = `

exports[`generates token 2`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -72,7 +82,7 @@ exports[`generates token 2`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -89,17 +99,12 @@ exports[`generates token 2`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
<input
autoFocus={true}
className="input-large spacer-right"
className="input-large spacer-right text-middle"
onChange={[Function]}
placeholder="onboarding.token.placeholder"
required={true}
@@ -107,9 +112,14 @@ exports[`generates token 2`] = `
value="my token"
/>
<i
className="spinner"
className="spinner text-middle"
/>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
</div>
</div>
</Step>
@@ -118,11 +128,15 @@ exports[`generates token 2`] = `

exports[`generates token 3`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -130,7 +144,7 @@ exports[`generates token 3`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -147,30 +161,47 @@ exports[`generates token 3`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
my token
:
<span
className="monospaced spacer-right"
className="text-middle"
>
abcd1234
my token
:
</span>
<strong
className="spacer-right text-middle"
>
abcd1234
</strong>
<button
className="button-clean"
className="button-clean text-middle"
onClick={[Function]}
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
<div
className="big-spacer-top"
>
@@ -189,11 +220,15 @@ exports[`generates token 3`] = `

exports[`revokes token 1`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -201,7 +236,7 @@ exports[`revokes token 1`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -218,30 +253,47 @@ exports[`revokes token 1`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
my token
:
<span
className="monospaced spacer-right"
className="text-middle"
>
abcd1234
my token
:
</span>
<strong
className="spacer-right text-middle"
>
abcd1234
</strong>
<button
className="button-clean"
className="button-clean text-middle"
onClick={[Function]}
>
<i
className="icon-delete"
/>
<CloseIcon
className="icon-red"
>
<svg
className="icon-red"
height={16}
viewBox="0 0 16 16"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
fill="currentColor"
/>
</svg>
</CloseIcon>
</button>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
<div
className="big-spacer-top"
>
@@ -260,11 +312,15 @@ exports[`revokes token 1`] = `

exports[`revokes token 2`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -272,7 +328,7 @@ exports[`revokes token 2`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -289,25 +345,29 @@ exports[`revokes token 2`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
my token
:
<span
className="monospaced spacer-right"
className="text-middle"
>
abcd1234
my token
:
</span>
<strong
className="spacer-right text-middle"
>
abcd1234
</strong>
<i
className="spinner"
className="spinner text-middle"
/>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
<div
className="big-spacer-top"
>
@@ -326,11 +386,15 @@ exports[`revokes token 2`] = `

exports[`revokes token 3`] = `
<TokenStep
finished={false}
onContinue={[Function]}
onOpen={[Function]}
open={true}
stepNumber={1}
>
<Step
finished={false}
onOpen={[Function]}
open={true}
renderForm={[Function]}
renderResult={[Function]}
@@ -338,7 +402,7 @@ exports[`revokes token 3`] = `
stepTitle="onboarding.token.header"
>
<div
className="boxed-group onboarding-step onboarding-step-open"
className="boxed-group onboarding-step is-open"
>
<div
className="onboarding-step-number"
@@ -355,27 +419,29 @@ exports[`revokes token 3`] = `
<div
className="boxed-group-inner"
>
<div
className="big-spacer-bottom width-50"
>
onboarding.token.text
</div>
<form
onSubmit={[Function]}
>
<input
autoFocus={true}
className="input-large spacer-right"
className="input-large spacer-right text-middle"
onChange={[Function]}
placeholder="onboarding.token.placeholder"
required={true}
type="text"
value=""
/>
<button>
<button
className="text-middle"
>
onboarding.token.generate
</button>
</form>
<div
className="note big-spacer-top width-50"
>
onboarding.token.text
</div>
</div>
</div>
</Step>

+ 15
- 2
server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css View File

@@ -1,8 +1,16 @@
.onboarding {
min-height: calc(70vh - 60px);
}

.onboarding-step {
position: relative;
padding-left: 34px;
}

.onboarding-step:not(.is-open):not(.is-finished) {
opacity: 0.4;
}

.onboarding-step .boxed-group-actions {
height: 24px;
line-height: 24px;
@@ -16,16 +24,21 @@
height: 24px;
line-height: 24px;
border-radius: 24px;
background-color: #cdcdcd;
background-color: #b9b9b9;
color: #fff;
font-size: 14px;
text-align: center;
}

.onboarding-step-open .onboarding-step-number {
.onboarding-step.is-open .onboarding-step-number {
background-color: #236a97;
}

.onboarding-step.is-finished {
cursor: pointer;
outline: none;
}

.onboarding-command {
position: relative;
margin: 8px 0;

+ 5
- 15
server/sonar-web/src/main/less/components/modals.less View File

@@ -49,21 +49,11 @@
}

.modal-large {
width: 90vw;
margin-left: -45vw;
}

.modal-full-screen {
top: 30%;
width: 90vw;
height: 90vh;
margin-left: -45vw;
margin-top: -45vh;
border-radius: 2px;

&.ReactModal__Content--after-open {
top: 50%;
}
width: ~"calc(100% - 40px)";
max-width: 1280px;
min-width: 1040px;
margin-left: 0;
transform: translateX(-50%);
}

.modal-overlay,

+ 3
- 2
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -1091,9 +1091,10 @@ shortcuts.section.rules.deactivate=deactivate selected rule
shortcuts.section.code=Code Page
shortcuts.section.code.search=search components in the project scope

tutorials.onboarding=Onboarding Tutorial
tutorials.onboarding=Analyze a new project
tutorials.skip=Skip this tutorial
tutorials.finish=Finish this tutorial
tutorials.follow_later=Follow the tutorial later in the Help section


#------------------------------------------------------------------------------
@@ -2957,7 +2958,7 @@ footer.web_api=Web API
#------------------------------------------------------------------------------
onboarding.header=Welcome to SonarQube!
onboarding.header.sonarcloud=Welcome to SonarCloud!
onboarding.header.description=Let's learn how to analyze your first public project.
onboarding.header.description=Let's analyze a new project.

onboarding.token.header=Generate a token
onboarding.token.text=We'll use it as a replacement of the user login. This will increase the security of your installation by not letting your analysis user's password going through your network.

Loading…
Cancel
Save