return getJSON('/api/alm_integration/list_repositories').catch(throwGlobalError);
}
-export function provisionProject(data: { repositories: string[] }) {
- return postJSON('api/alm_integration/provision_projects', data).catch(throwGlobalError);
+export function provisionProject(data: {
+ installationKeys: string[];
+}): Promise<{ projects: Array<{ projectKey: string }> }> {
+ return postJSON('/api/alm_integration/provision_projects', {
+ ...data,
+ installationKeys: data.installationKeys.join(',')
+ }).catch(throwGlobalError);
}
const { currentUser, location } = this.props;
if (
currentUser.showOnboardingTutorial &&
- !['about', 'documentation', 'onboarding'].some(path => location.pathname.startsWith(path))
+ !['about', 'documentation', 'onboarding', 'projects/create'].some(path =>
+ location.pathname.startsWith(path)
+ )
) {
this.setState({ automatic: true });
if (isSonarCloud()) {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { Link } from 'react-router';
import * as classNames from 'classnames';
+import { Link } from 'react-router';
import { isLoggedIn, CurrentUser, AppState, Extension } from '../../../types';
import { translate } from '../../../../helpers/l10n';
import { getQualityGatesUrl, getBaseUrl } from '../../../../helpers/urls';
return null;
}
+ const active =
+ this.props.location.pathname.startsWith('projects') &&
+ this.props.location.pathname !== 'projects/create';
+
return (
<li>
- <Link activeClassName="active" to="/projects">
+ <Link activeClassName={classNames({ active })} to="/projects">
{isSonarCloud() ? translate('my_projects') : translate('projects.page')}
</Link>
</li>
return (
<li>
<Link
- className={active ? 'active' : undefined}
+ className={classNames({ active })}
to={{ pathname: '/issues', query: { resolved: 'false' } }}>
{translate('my_issues')}
</Link>
: { resolved: 'false' };
return (
<li>
- <Link className={active ? 'active' : undefined} to={{ pathname: '/issues', query }}>
+ <Link className={classNames({ active })} to={{ pathname: '/issues', query }}>
{translate('issues.page')}
</Link>
</li>
>
<li>
<Link
- activeClassName="active"
+ activeClassName=""
onlyActiveOnIndex={false}
style={Object {}}
to="/projects"
</li>
<li>
<Link
+ className=""
onlyActiveOnIndex={false}
style={Object {}}
to={
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Link } from 'react-router';
import * as theme from '../../../app/theme';
import Checkbox from '../../../components/controls/Checkbox';
import CheckIcon from '../../../components/icons-components/CheckIcon';
import { AlmRepository, IdentityProvider } from '../../../app/types';
-import { getBaseUrl } from '../../../helpers/urls';
+import { getBaseUrl, getProjectUrl } from '../../../helpers/urls';
import { translate } from '../../../helpers/l10n';
interface Props {
const { identityProvider, repository, selected } = this.props;
const alreadyImported = Boolean(repository.linkedProjectKey);
return (
- <Checkbox
- checked={selected || alreadyImported}
- disabled={alreadyImported}
- onCheck={this.handleChange}>
- <img
- alt={identityProvider.name}
- className="spacer-left"
- height={14}
- src={`${getBaseUrl()}/images/sonarcloud/${identityProvider.key}.svg`}
- style={{ opacity: alreadyImported ? 0.5 : 1 }}
- width={14}
- />
- <span className="spacer-left">{this.props.repository.label}</span>
- {alreadyImported && (
+ <>
+ <Checkbox
+ checked={selected || alreadyImported}
+ disabled={alreadyImported}
+ onCheck={this.handleChange}>
+ <img
+ alt={identityProvider.name}
+ className="spacer-left"
+ height={14}
+ src={`${getBaseUrl()}/images/sonarcloud/${identityProvider.key}.svg`}
+ style={{ opacity: alreadyImported ? 0.5 : 1 }}
+ width={14}
+ />
+ <span className="spacer-left">{this.props.repository.label}</span>
+ </Checkbox>
+ {repository.linkedProjectKey && (
<span className="big-spacer-left">
<CheckIcon className="little-spacer-right" fill={theme.green} />
- {translate('onboarding.create_project.already_imported')}
+ <Link to={getProjectUrl(repository.linkedProjectKey)}>
+ {translate('onboarding.create_project.already_imported')}
+ </Link>
</span>
)}
- </Checkbox>
+ </>
);
}
}
import AlmRepositoryItem from './AlmRepositoryItem';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import IdentityProviderLink from '../../../components/ui/IdentityProviderLink';
-import { getIdentityProviders } from '../../../api/users';
import { getRepositories, provisionProject } from '../../../api/alm-integration';
-import { IdentityProvider, LoggedInUser, AlmRepository } from '../../../app/types';
-import { ProjectBase } from '../../../api/components';
+import { IdentityProvider, AlmRepository } from '../../../app/types';
import { SubmitButton } from '../../../components/ui/buttons';
import { translateWithParameters, translate } from '../../../helpers/l10n';
interface Props {
- currentUser: LoggedInUser;
- onProjectCreate: (project: ProjectBase[]) => void;
+ identityProvider: IdentityProvider;
+ onProjectCreate: (projectKeys: string[]) => void;
}
interface State {
- identityProviders: IdentityProvider[];
installationUrl?: string;
installed?: boolean;
loading: boolean;
export default class AutoProjectCreate extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
- identityProviders: [],
loading: true,
repositories: [],
selectedRepositories: {},
componentDidMount() {
this.mounted = true;
- Promise.all([this.fetchIdentityProviders(), this.fetchRepositories()]).then(
- this.stopLoading,
- this.stopLoading
- );
+ this.fetchRepositories();
}
componentWillUnmount() {
this.mounted = false;
}
- fetchIdentityProviders = () => {
- return getIdentityProviders().then(
- ({ identityProviders }) => {
+ fetchRepositories = () => {
+ getRepositories().then(
+ ({ almIntegration, repositories }) => {
if (this.mounted) {
- this.setState({ identityProviders });
+ this.setState({ ...almIntegration, loading: false, repositories });
}
},
() => {
- return Promise.resolve();
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
}
);
};
- fetchRepositories = () => {
- return getRepositories().then(({ almIntegration, repositories }) => {
- if (this.mounted) {
- this.setState({ ...almIntegration, repositories });
- }
- });
- };
-
handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const { selectedRepositories } = this.state;
this.setState({ submitting: true });
provisionProject({
- repositories: Object.keys(selectedRepositories).filter(key =>
+ installationKeys: Object.keys(selectedRepositories).filter(key =>
Boolean(selectedRepositories[key])
)
}).then(
- ({ project }) => this.props.onProjectCreate([project]),
+ ({ projects }) => this.props.onProjectCreate(projects.map(project => project.projectKey)),
() => {
if (this.mounted) {
- this.setState({ submitting: false });
- this.reloadRepositories();
+ this.setState({ loading: true, submitting: false });
+ this.fetchRepositories();
}
}
);
);
};
- reloadRepositories = () => {
- this.setState({ loading: true });
- this.fetchRepositories().then(this.stopLoading, this.stopLoading);
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
toggleRepository = (repository: AlmRepository) => {
this.setState(({ selectedRepositories }) => ({
selectedRepositories: {
}));
};
- render() {
- if (this.state.loading) {
- return <DeferredSpinner />;
- }
-
- const { currentUser } = this.props;
- const identityProvider = this.state.identityProviders.find(
- identityProvider => identityProvider.key === currentUser.externalProvider
- );
+ renderContent = () => {
+ const { identityProvider } = this.props;
+ const { selectedRepositories, submitting } = this.state;
- if (!identityProvider) {
- return null;
+ if (this.state.installed) {
+ return (
+ <form onSubmit={this.handleFormSubmit}>
+ <ul>
+ {this.state.repositories.map(repo => (
+ <li className="big-spacer-bottom" key={repo.installationKey}>
+ <AlmRepositoryItem
+ identityProvider={identityProvider}
+ repository={repo}
+ selected={Boolean(selectedRepositories[repo.installationKey])}
+ toggleRepository={this.toggleRepository}
+ />
+ </li>
+ ))}
+ </ul>
+ <SubmitButton disabled={!this.isValid() || submitting}>
+ {translate('create')}
+ </SubmitButton>
+ <DeferredSpinner className="spacer-left" loading={submitting} />
+ </form>
+ );
}
+ return (
+ <div>
+ <p className="spacer-bottom">
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x',
+ identityProvider.name
+ )}
+ </p>
+ <IdentityProviderLink
+ className="display-inline-block"
+ identityProvider={identityProvider}
+ small={true}
+ url={this.state.installationUrl}>
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x.button',
+ identityProvider.name
+ )}
+ </IdentityProviderLink>
+ </div>
+ );
+ };
- const { selectedRepositories, submitting } = this.state;
+ render() {
+ const { identityProvider } = this.props;
+ const { loading } = this.state;
return (
<>
identityProvider.name
)}
</p>
- {this.state.installed ? (
- <form onSubmit={this.handleFormSubmit}>
- <ul>
- {this.state.repositories.map(repo => (
- <li className="big-spacer-bottom" key={repo.installationKey}>
- <AlmRepositoryItem
- identityProvider={identityProvider}
- repository={repo}
- selected={Boolean(selectedRepositories[repo.installationKey])}
- toggleRepository={this.toggleRepository}
- />
- </li>
- ))}
- </ul>
- <SubmitButton disabled={!this.isValid() || submitting}>
- {translate('onboarding.create_project.create_project')}
- </SubmitButton>
- <DeferredSpinner className="spacer-left" loading={submitting} />
- </form>
- ) : (
- <div>
- <p className="spacer-bottom">
- {translateWithParameters(
- 'onboarding.create_project.install_app_x',
- identityProvider.name
- )}
- </p>
- <IdentityProviderLink
- className="display-inline-block"
- identityProvider={identityProvider}
- small={true}
- url={this.state.installationUrl}>
- {translateWithParameters(
- 'onboarding.create_project.install_app_x.button',
- identityProvider.name
- )}
- </IdentityProviderLink>
- </div>
- )}
+ {loading ? <DeferredSpinner /> : this.renderContent()}
</>
);
}
import AutoProjectCreate from './AutoProjectCreate';
import ManualProjectCreate from './ManualProjectCreate';
import { serializeQuery, Query, parseQuery } from './utils';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import { getCurrentUser } from '../../../store/rootReducer';
-import { skipOnboarding } from '../../../store/users/actions';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions';
+import { CurrentUser, IdentityProvider, isLoggedIn, LoggedInUser } from '../../../app/types';
+import { skipOnboarding, getIdentityProviders } from '../../../api/users';
import { translate } from '../../../helpers/l10n';
-import { ProjectBase } from '../../../api/components';
-import { getProjectUrl, getOrganizationUrl } from '../../../helpers/urls';
+import { getProjectUrl } from '../../../helpers/urls';
import '../../../app/styles/sonarcloud.css';
interface OwnProps {
location: Location;
- onFinishOnboarding: () => void;
router: Pick<InjectedRouter, 'push' | 'replace'>;
}
}
interface DispatchProps {
- skipOnboarding: () => void;
+ skipOnboardingAction: () => void;
}
-type Props = OwnProps & StateProps & DispatchProps;
+interface Props extends OwnProps, StateProps, DispatchProps {
+ currentUser: LoggedInUser;
+}
+
+interface State {
+ identityProvider?: IdentityProvider;
+ loading: boolean;
+}
-export class CreateProjectPage extends React.PureComponent<Props> {
+export class CreateProjectPage extends React.PureComponent<Props, State> {
mounted = false;
constructor(props: Props) {
super(props);
+ this.state = { loading: true };
if (!this.canAutoCreate(props)) {
this.updateQuery({ manual: true });
}
document.documentElement.classList.remove('white-page');
}
- handleProjectCreate = (projects: Pick<ProjectBase, 'key'>[], organization?: string) => {
- if (projects.length > 1 && organization) {
- this.props.router.push(getOrganizationUrl(organization) + '/projects');
- } else if (projects.length === 1) {
- this.props.router.push(getProjectUrl(projects[0].key));
+ handleProjectCreate = (projectKeys: string[]) => {
+ skipOnboarding().catch(() => {});
+ this.props.skipOnboardingAction();
+ if (projectKeys.length > 1) {
+ this.props.router.push({ pathname: '/projects' });
+ } else if (projectKeys.length === 1) {
+ this.props.router.push(getProjectUrl(projectKeys[0]));
}
};
canAutoCreate = ({ currentUser } = this.props) => {
- return (
- isLoggedIn(currentUser) &&
- ['bitbucket', 'github'].includes(currentUser.externalProvider || '')
+ return ['bitbucket', 'github'].includes(currentUser.externalProvider || '');
+ };
+
+ fetchIdentityProviders = () => {
+ getIdentityProviders().then(
+ ({ identityProviders }) => {
+ if (this.mounted) {
+ this.setState({
+ identityProvider: identityProviders.find(
+ identityProvider => identityProvider.key === this.props.currentUser.externalProvider
+ ),
+ loading: false
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
);
};
render() {
const { currentUser } = this.props;
- if (!isLoggedIn(currentUser)) {
- return null;
- }
+ const { identityProvider, loading } = this.state;
const displayManual = parseQuery(this.props.location.query).manual;
const header = translate('onboarding.create_project.header');
+ const hasAutoProvisioning = this.canAutoCreate() && identityProvider;
return (
<>
<Helmet title={header} titleTemplate="%s" />
<div className="page-header">
<h1 className="page-title">{header}</h1>
</div>
-
- {this.canAutoCreate() && (
- <ul className="flex-tabs">
- <li>
- <a
- className={classNames('js-auto', { selected: !displayManual })}
- href="#"
- onClick={this.showAuto}>
- {translate('onboarding.create_project.select_repositories')}
- <span
- className={classNames(
- 'rounded alert alert-small spacer-left display-inline-block',
- {
- 'alert-info': !displayManual,
- 'alert-muted': displayManual
- }
- )}>
- {translate('beta')}
- </span>
- </a>
- </li>
- <li>
- <a
- className={classNames('js-manual', { selected: displayManual })}
- href="#"
- onClick={this.showManual}>
- {translate('onboarding.create_project.create_manually')}
- </a>
- </li>
- </ul>
- )}
-
- {displayManual || !this.canAutoCreate() ? (
- <ManualProjectCreate
- currentUser={currentUser}
- onProjectCreate={this.handleProjectCreate}
- />
+ {loading ? (
+ <DeferredSpinner />
) : (
- <AutoProjectCreate
- currentUser={currentUser}
- onProjectCreate={this.handleProjectCreate}
- />
+ <>
+ {hasAutoProvisioning && (
+ <ul className="flex-tabs">
+ <li>
+ <a
+ className={classNames('js-auto', { selected: !displayManual })}
+ href="#"
+ onClick={this.showAuto}>
+ {translate('onboarding.create_project.select_repositories')}
+ <span
+ className={classNames(
+ 'rounded alert alert-small spacer-left display-inline-block',
+ {
+ 'alert-info': !displayManual,
+ 'alert-muted': displayManual
+ }
+ )}>
+ {translate('beta')}
+ </span>
+ </a>
+ </li>
+ <li>
+ <a
+ className={classNames('js-manual', { selected: displayManual })}
+ href="#"
+ onClick={this.showManual}>
+ {translate('onboarding.create_project.create_manually')}
+ </a>
+ </li>
+ </ul>
+ )}
+
+ {displayManual || !hasAutoProvisioning ? (
+ <ManualProjectCreate
+ currentUser={currentUser}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ ) : (
+ <AutoProjectCreate
+ identityProvider={identityProvider!}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ )}
+ </>
)}
</div>
</>
};
};
-const mapDispatchToProps: DispatchProps = { skipOnboarding };
+const mapDispatchToProps: DispatchProps = { skipOnboardingAction };
export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
CreateProjectPage
import { fetchMyOrganizations } from '../../account/organizations/actions';
import { getMyOrganizations } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
-import { createProject, ProjectBase } from '../../../api/components';
+import { createProject } from '../../../api/components';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
interface StateProps {
interface OwnProps {
currentUser: LoggedInUser;
- onProjectCreate: (project: ProjectBase[]) => void;
+ onProjectCreate: (projectKeys: string[]) => void;
}
type Props = OwnProps & StateProps & DispatchProps;
name: projectName,
organization: selectedOrganization
}).then(
- ({ project }) => this.props.onProjectCreate([project]),
+ ({ project }) => this.props.onProjectCreate([project.key]),
() => {
if (this.mounted) {
this.setState({ submitting: false });
/>
</div>
<SubmitButton disabled={!this.isValid() || submitting}>
- {translate('onboarding.create_project.create_project')}
+ {translate('create')}
</SubmitButton>
<DeferredSpinner className="spacer-left" loading={submitting} />
</form>
import * as React from 'react';
import { shallow } from 'enzyme';
import AutoProjectCreate from '../AutoProjectCreate';
-import { getIdentityProviders } from '../../../../api/users';
import { getRepositories } from '../../../../api/alm-integration';
-import { LoggedInUser } from '../../../../app/types';
import { waitAndUpdate } from '../../../../helpers/testUtils';
-jest.mock('../../../../api/users', () => ({
- getIdentityProviders: jest.fn().mockResolvedValue({
- identityProviders: [
- {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- key: 'foo',
- name: 'Foo Provider'
- }
- ]
- })
-}));
-
jest.mock('../../../../api/alm-integration', () => ({
getRepositories: jest.fn().mockResolvedValue({
almIntegration: {
provisionProject: jest.fn().mockResolvedValue({ projects: [] })
}));
-const user: LoggedInUser = { isLoggedIn: true, login: 'foo', name: 'Foo', externalProvider: 'foo' };
+const identityProvider = {
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'foo',
+ name: 'Foo Provider'
+};
+
const repositories = [
{
label: 'Cool Project',
];
beforeEach(() => {
- (getIdentityProviders as jest.Mock<any>).mockClear();
(getRepositories as jest.Mock<any>).mockClear();
});
it('should display the provider app install button', async () => {
const wrapper = getWrapper();
expect(wrapper).toMatchSnapshot();
- expect(getIdentityProviders).toHaveBeenCalled();
expect(getRepositories).toHaveBeenCalled();
await waitAndUpdate(wrapper);
});
function getWrapper(props = {}) {
- return shallow(<AutoProjectCreate currentUser={user} onProjectCreate={jest.fn()} {...props} />);
+ return shallow(
+ <AutoProjectCreate identityProvider={identityProvider} onProjectCreate={jest.fn()} {...props} />
+ );
}
import { shallow } from 'enzyme';
import { Location } from 'history';
import { CreateProjectPage } from '../CreateProjectPage';
+import { getIdentityProviders } from '../../../../api/users';
import { LoggedInUser } from '../../../../app/types';
-import { click } from '../../../../helpers/testUtils';
+import { click, waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/users', () => ({
+ getIdentityProviders: jest.fn().mockResolvedValue({
+ identityProviders: [
+ {
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'github',
+ name: 'GitHub'
+ }
+ ]
+ })
+}));
const user: LoggedInUser = {
externalProvider: 'github',
name: 'Foo'
};
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
+beforeEach(() => {
+ (getIdentityProviders as jest.Mock<any>).mockClear();
+});
+
+it('should render correctly', async () => {
+ const wrapper = getWrapper();
+ expect(wrapper).toMatchSnapshot();
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
});
it('should render with Manual creation only', () => {
expect(getWrapper({ currentUser: { ...user, externalProvider: 'microsoft' } })).toMatchSnapshot();
});
-it('should switch tabs', () => {
+it('should switch tabs', async () => {
const replace = jest.fn();
const wrapper = getWrapper({ router: { replace } });
replace.mockImplementation(location => {
wrapper.setProps({ location }).update();
});
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper).toMatchSnapshot();
+
click(wrapper.find('.js-manual'));
expect(wrapper.find('Connect(ManualProjectCreate)').exists()).toBeTruthy();
click(wrapper.find('.js-auto'));
<CreateProjectPage
currentUser={user}
location={{ pathname: 'foo', query: { manual: 'false' } } as Location}
- onFinishOnboarding={jest.fn()}
router={{ push: jest.fn(), replace: jest.fn() }}
- skipOnboarding={jest.fn()}
+ skipOnboardingAction={jest.fn()}
{...props}
/>
);
expect(createProject).toBeCalledWith({ project: 'bar', name: 'Bar', organization: 'foo' });
await waitAndUpdate(wrapper);
- expect(onProjectCreate).toBeCalledWith([{ key: 'bar', name: 'Bar' }]);
+ expect(onProjectCreate).toBeCalledWith(['bar']);
});
function getWrapper(props = {}) {
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<Checkbox
- checked={false}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- style={
- Object {
- "opacity": 1,
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
+<React.Fragment>
+ <Checkbox
+ checked={false}
+ disabled={false}
+ onCheck={[Function]}
+ thirdState={false}
>
- Awesome Project
- </span>
-</Checkbox>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="/images/sonarcloud/foo.svg"
+ style={
+ Object {
+ "opacity": 1,
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Awesome Project
+ </span>
+ </Checkbox>
+</React.Fragment>
`;
exports[`should render disabled 1`] = `
-<Checkbox
- checked={true}
- disabled={true}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- style={
- Object {
- "opacity": 0.5,
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
+<React.Fragment>
+ <Checkbox
+ checked={true}
+ disabled={true}
+ onCheck={[Function]}
+ thirdState={false}
>
- Cool Project
- </span>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="/images/sonarcloud/foo.svg"
+ style={
+ Object {
+ "opacity": 0.5,
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Cool Project
+ </span>
+ </Checkbox>
<span
className="big-spacer-left"
>
className="little-spacer-right"
fill="#00aa00"
/>
- onboarding.create_project.already_imported
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/dashboard",
+ "query": Object {
+ "branch": undefined,
+ "id": "proj_cool",
+ },
+ }
+ }
+ >
+ onboarding.create_project.already_imported
+ </Link>
</span>
-</Checkbox>
+</React.Fragment>
`;
exports[`should render selected 1`] = `
-<Checkbox
- checked={true}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="/images/sonarcloud/foo.svg"
- style={
- Object {
- "opacity": 1,
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
+<React.Fragment>
+ <Checkbox
+ checked={true}
+ disabled={false}
+ onCheck={[Function]}
+ thirdState={false}
>
- Awesome Project
- </span>
-</Checkbox>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="/images/sonarcloud/foo.svg"
+ style={
+ Object {
+ "opacity": 1,
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Awesome Project
+ </span>
+ </Checkbox>
+</React.Fragment>
`;
<SubmitButton
disabled={true}
>
- onboarding.create_project.create_project
+ create
</SubmitButton>
<DeferredSpinner
className="spacer-left"
`;
exports[`should display the provider app install button 1`] = `
-<DeferredSpinner
- timeout={100}
-/>
+<React.Fragment>
+ <p
+ className="alert alert-info width-60 big-spacer-bottom"
+ >
+ onboarding.create_project.beta_feature_x.Foo Provider
+ </p>
+ <DeferredSpinner
+ timeout={100}
+ />
+</React.Fragment>
`;
exports[`should display the provider app install button 2`] = `
onboarding.create_project.header
</h1>
</div>
- <ul
- className="flex-tabs"
+ <DeferredSpinner
+ timeout={100}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`should render correctly 2`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.header"
+ titleTemplate="%s"
+ />
+ <div
+ className="sonarcloud page page-limited"
+ >
+ <div
+ className="page-header"
>
- <li>
- <a
- className="js-auto selected"
- href="#"
- onClick={[Function]}
- >
- onboarding.create_project.select_repositories
- <span
- className="rounded alert alert-small spacer-left display-inline-block alert-info"
+ <h1
+ className="page-title"
+ >
+ onboarding.create_project.header
+ </h1>
+ </div>
+ <React.Fragment>
+ <ul
+ className="flex-tabs"
+ >
+ <li>
+ <a
+ className="js-auto selected"
+ href="#"
+ onClick={[Function]}
>
- beta
- </span>
- </a>
- </li>
- <li>
- <a
- className="js-manual"
- href="#"
- onClick={[Function]}
- >
- onboarding.create_project.create_manually
- </a>
- </li>
- </ul>
- <AutoProjectCreate
- currentUser={
- Object {
- "externalProvider": "github",
- "isLoggedIn": true,
- "login": "foo",
- "name": "Foo",
+ onboarding.create_project.select_repositories
+ <span
+ className="rounded alert alert-small spacer-left display-inline-block alert-info"
+ >
+ beta
+ </span>
+ </a>
+ </li>
+ <li>
+ <a
+ className="js-manual"
+ href="#"
+ onClick={[Function]}
+ >
+ onboarding.create_project.create_manually
+ </a>
+ </li>
+ </ul>
+ <AutoProjectCreate
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "github",
+ "name": "GitHub",
+ }
}
- }
- onProjectCreate={[Function]}
- />
+ onProjectCreate={[Function]}
+ />
+ </React.Fragment>
</div>
</React.Fragment>
`;
onboarding.create_project.header
</h1>
</div>
- <Connect(ManualProjectCreate)
- currentUser={
- Object {
- "externalProvider": "microsoft",
- "isLoggedIn": true,
- "login": "foo",
- "name": "Foo",
+ <React.Fragment>
+ <Connect(ManualProjectCreate)
+ currentUser={
+ Object {
+ "externalProvider": "microsoft",
+ "isLoggedIn": true,
+ "login": "foo",
+ "name": "Foo",
+ }
}
- }
- onProjectCreate={[Function]}
- />
+ onProjectCreate={[Function]}
+ />
+ </React.Fragment>
+ </div>
+</React.Fragment>
+`;
+
+exports[`should switch tabs 1`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.header"
+ titleTemplate="%s"
+ />
+ <div
+ className="sonarcloud page page-limited"
+ >
+ <div
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ onboarding.create_project.header
+ </h1>
+ </div>
+ <React.Fragment>
+ <ul
+ className="flex-tabs"
+ >
+ <li>
+ <a
+ className="js-auto selected"
+ href="#"
+ onClick={[Function]}
+ >
+ onboarding.create_project.select_repositories
+ <span
+ className="rounded alert alert-small spacer-left display-inline-block alert-info"
+ >
+ beta
+ </span>
+ </a>
+ </li>
+ <li>
+ <a
+ className="js-manual"
+ href="#"
+ onClick={[Function]}
+ >
+ onboarding.create_project.create_manually
+ </a>
+ </li>
+ </ul>
+ <AutoProjectCreate
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "github",
+ "name": "GitHub",
+ }
+ }
+ onProjectCreate={[Function]}
+ />
+ </React.Fragment>
</div>
</React.Fragment>
`;
<SubmitButton
disabled={true}
>
- onboarding.create_project.create_project
+ create
</SubmitButton>
`;
<SubmitButton
disabled={false}
>
- onboarding.create_project.create_project
+ create
</SubmitButton>
`;
<SubmitButton
disabled={true}
>
- onboarding.create_project.create_project
+ create
</SubmitButton>
<DeferredSpinner
className="spacer-left"
import { translate } from '../../../helpers/l10n';
import { Button } from '../../../components/ui/buttons';
+type Selection = 'personal' | 'existing' | 'new';
+
interface Props {
currentUser: { login: string; isLoggedIn: boolean };
finished: boolean;
existingOrganization?: string;
existingOrganizations: Array<string>;
personalOrganization?: string;
- selection: 'personal' | 'existing' | 'new';
+ selection: Selection;
}
export default class OrganizationStep extends React.PureComponent<Props, State> {
const personalOrganization =
organizationKeys.length === 1 ? organizationKeys[0] : undefined;
const existingOrganizations = organizationKeys.length > 1 ? sortBy(organizationKeys) : [];
- const selection = personalOrganization
- ? 'personal'
- : existingOrganizations.length > 0 ? 'existing' : 'new';
+ let selection: Selection = 'personal';
+ if (!personalOrganization) {
+ selection = existingOrganizations.length > 0 ? 'existing' : 'new';
+ }
this.setState({
loading: false,
existingOrganizations,