diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-06-16 05:56:47 -0700 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-06-20 04:10:53 -0700 |
commit | ac756ae021e7a9fadc7a2cbbcd80ce4278022edd (patch) | |
tree | a42440b151c13bd3d16bfcd0b39841b2d7d6d924 /server/sonar-web/src/main/js | |
parent | 19fb2bab0cfcd5067bbde14f5b686b5f0360c27e (diff) | |
download | sonarqube-ac756ae021e7a9fadc7a2cbbcd80ce4278022edd.tar.gz sonarqube-ac756ae021e7a9fadc7a2cbbcd80ce4278022edd.zip |
apply feedback on onboarding (#2175)
Diffstat (limited to 'server/sonar-web/src/main/js')
19 files changed, 737 insertions, 407 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js index dc282991294..cb2d2eca428 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js @@ -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> ); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js index 83b7319a013..78733e66992 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js @@ -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} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js index 16a7c54d526..1f20fe29572 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js @@ -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"> diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js index 2bf64f8fe5a..11f24180d82 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js @@ -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')} 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 06a5de99f38..2f79f7add07 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 @@ -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> ); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js index 13e1af88107..3ec32829d17 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.js @@ -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> ); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js index 325e8e8ac56..9270d7c6033 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js @@ -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')} /> ); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js index 763cef635df..fba30c8102b 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js @@ -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"> 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 9a171f7bc77..443d4f5c2ec 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 @@ -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} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js index e4898897284..f336d73a79b 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js @@ -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} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js index 9352556f5d1..b566bcd10b7 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js @@ -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'); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js index 89d7a3b7ba4..daf5c8431de 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js @@ -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(); +}); 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 9498fc27ada..8a4608bb7ab 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 @@ -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'); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap index c5f05454644..fde0778232a 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap @@ -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> diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap index 50ef33521cc..1943af530a5 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap @@ -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> 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 df1611144a1..5e9291b6c85 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 @@ -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> `; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap index 1df068a503c..4667ca7ae8a 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap @@ -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" 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 73ae3896df4..65138e0b498 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 @@ -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,31 +161,48 @@ 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" > <button @@ -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,31 +253,48 @@ 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" > <button @@ -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,26 +345,30 @@ 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" > <button @@ -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> diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css b/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css index 870da20acde..ba588639db3 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css @@ -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; |