From: Grégoire Aubert
Date: Fri, 3 Aug 2018 08:06:20 +0000 (+0200)
Subject: SONAR-11038 Fix project provisioning
X-Git-Tag: 7.5~616
X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=19db9d08eb0a4aab7909f561992f137b1e7092a9;p=sonarqube.git
SONAR-11038 Fix project provisioning
---
diff --git a/server/sonar-web/src/main/js/api/alm-integration.ts b/server/sonar-web/src/main/js/api/alm-integration.ts
index 798f16e6d89..d35ff9995e0 100644
--- a/server/sonar-web/src/main/js/api/alm-integration.ts
+++ b/server/sonar-web/src/main/js/api/alm-integration.ts
@@ -31,6 +31,11 @@ export function getRepositories(): Promise<{
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);
}
diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx
index b85885bbcd0..7930a9b7f21 100644
--- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx
+++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx
@@ -171,7 +171,9 @@ export class StartupModal extends React.PureComponent {
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()) {
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
index d734d6c1401..ccb40acc1f6 100644
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
@@ -18,8 +18,8 @@
* 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';
@@ -44,9 +44,13 @@ export default class GlobalNavMenu extends React.PureComponent {
return null;
}
+ const active =
+ this.props.location.pathname.startsWith('projects') &&
+ this.props.location.pathname !== 'projects/create';
+
return (
-
+
{isSonarCloud() ? translate('my_projects') : translate('projects.page')}
@@ -74,7 +78,7 @@ export default class GlobalNavMenu extends React.PureComponent {
return (
{translate('my_issues')}
@@ -88,7 +92,7 @@ export default class GlobalNavMenu extends React.PureComponent {
: { resolved: 'false' };
return (
-
+
{translate('issues.page')}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.tsx.snap
index b886f31dab4..2acadf725f8 100644
--- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavMenu-test.tsx.snap
@@ -6,7 +6,7 @@ exports[`should show administration menu if the user has the rights 1`] = `
>
{
const { identityProvider, repository, selected } = this.props;
const alreadyImported = Boolean(repository.linkedProjectKey);
return (
-
-
- {this.props.repository.label}
- {alreadyImported && (
+ <>
+
+
+ {this.props.repository.label}
+
+ {repository.linkedProjectKey && (
- {translate('onboarding.create_project.already_imported')}
+
+ {translate('onboarding.create_project.already_imported')}
+
)}
-
+ >
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx
index 078a54d13de..920be163938 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx
@@ -21,20 +21,17 @@ import * as React from 'react';
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;
@@ -46,7 +43,6 @@ interface State {
export default class AutoProjectCreate extends React.PureComponent {
mounted = false;
state: State = {
- identityProviders: [],
loading: true,
repositories: [],
selectedRepositories: {},
@@ -55,37 +51,28 @@ export default class AutoProjectCreate extends React.PureComponent
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) => {
event.preventDefault();
@@ -93,15 +80,15 @@ export default class AutoProjectCreate extends React.PureComponent
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();
}
}
);
@@ -114,17 +101,6 @@ export default class AutoProjectCreate extends React.PureComponent
);
};
- 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: {
@@ -136,21 +112,57 @@ export default class AutoProjectCreate extends React.PureComponent
}));
};
- render() {
- if (this.state.loading) {
- return ;
- }
-
- 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 (
+
+ );
}
+ return (
+
+
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x',
+ identityProvider.name
+ )}
+
+
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x.button',
+ identityProvider.name
+ )}
+
+
+ );
+ };
- const { selectedRepositories, submitting } = this.state;
+ render() {
+ const { identityProvider } = this.props;
+ const { loading } = this.state;
return (
<>
@@ -160,45 +172,7 @@ export default class AutoProjectCreate extends React.PureComponent
identityProvider.name
)}
- {this.state.installed ? (
-
- ) : (
-
-
- {translateWithParameters(
- 'onboarding.create_project.install_app_x',
- identityProvider.name
- )}
-
-
- {translateWithParameters(
- 'onboarding.create_project.install_app_x.button',
- identityProvider.name
- )}
-
-
- )}
+ {loading ? : this.renderContent()}
>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx
index 63224ebacec..a3cdbb510a0 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx
@@ -26,18 +26,18 @@ import Helmet from 'react-helmet';
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;
}
@@ -46,16 +46,24 @@ interface StateProps {
}
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 {
+export class CreateProjectPage extends React.PureComponent {
mounted = false;
constructor(props: Props) {
super(props);
+ this.state = { loading: true };
if (!this.canAutoCreate(props)) {
this.updateQuery({ manual: true });
}
@@ -76,18 +84,37 @@ export class CreateProjectPage extends React.PureComponent {
document.documentElement.classList.remove('white-page');
}
- handleProjectCreate = (projects: Pick[], 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 });
+ }
+ }
);
};
@@ -110,11 +137,10 @@ export class CreateProjectPage extends React.PureComponent {
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 (
<>
@@ -122,48 +148,53 @@ export class CreateProjectPage extends React.PureComponent {
{header}
-
- {this.canAutoCreate() && (
-
- )}
-
- {displayManual || !this.canAutoCreate() ? (
-
+ {loading ? (
+
) : (
-
+ <>
+ {hasAutoProvisioning && (
+
+ )}
+
+ {displayManual || !hasAutoProvisioning ? (
+
+ ) : (
+
+ )}
+ >
)}
>
@@ -177,7 +208,7 @@ const mapStateToProps = (state: any): StateProps => {
};
};
-const mapDispatchToProps: DispatchProps = { skipOnboarding };
+const mapDispatchToProps: DispatchProps = { skipOnboardingAction };
export default connect(mapStateToProps, mapDispatchToProps)(
CreateProjectPage
diff --git a/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx
index 041b09bdd4d..d1df2b59ec0 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx
@@ -27,7 +27,7 @@ import { LoggedInUser, Organization } from '../../../app/types';
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 {
@@ -40,7 +40,7 @@ interface DispatchProps {
interface OwnProps {
currentUser: LoggedInUser;
- onProjectCreate: (project: ProjectBase[]) => void;
+ onProjectCreate: (projectKeys: string[]) => void;
}
type Props = OwnProps & StateProps & DispatchProps;
@@ -91,7 +91,7 @@ export class ManualProjectCreate extends React.PureComponent {
name: projectName,
organization: selectedOrganization
}).then(
- ({ project }) => this.props.onProjectCreate([project]),
+ ({ project }) => this.props.onProjectCreate([project.key]),
() => {
if (this.mounted) {
this.setState({ submitting: false });
@@ -198,7 +198,7 @@ export class ManualProjectCreate extends React.PureComponent {
/>
- {translate('onboarding.create_project.create_project')}
+ {translate('create')}
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx
index bfe95430578..91e189f4204 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx
@@ -20,24 +20,9 @@
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: {
@@ -49,7 +34,13 @@ jest.mock('../../../../api/alm-integration', () => ({
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',
@@ -64,14 +55,12 @@ const repositories = [
];
beforeEach(() => {
- (getIdentityProviders as jest.Mock).mockClear();
(getRepositories as jest.Mock).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);
@@ -92,5 +81,7 @@ it('should display the list of repositories', async () => {
});
function getWrapper(props = {}) {
- return shallow( );
+ return shallow(
+
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx
index 6f995afd252..42f39b9fb61 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx
@@ -21,8 +21,22 @@ import * as React from 'react';
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',
@@ -31,21 +45,32 @@ const user: LoggedInUser = {
name: 'Foo'
};
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
+beforeEach(() => {
+ (getIdentityProviders as jest.Mock).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'));
@@ -57,9 +82,8 @@ function getWrapper(props = {}) {
);
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx
index b79b4e4ae35..f67db69e464 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx
@@ -63,7 +63,7 @@ it('should correctly create a project', async () => {
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 = {}) {
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
index eddcbf0214b..292a0a839c0 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
@@ -1,56 +1,60 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-
-
-
+
- Awesome Project
-
-
+
+
+ Awesome Project
+
+
+
`;
exports[`should render disabled 1`] = `
-
-
-
+
- Cool Project
-
+
+
+ Cool Project
+
+
@@ -58,34 +62,50 @@ exports[`should render disabled 1`] = `
className="little-spacer-right"
fill="#00aa00"
/>
- onboarding.create_project.already_imported
+
+ onboarding.create_project.already_imported
+
-
+
`;
exports[`should render selected 1`] = `
-
-
-
+
- Awesome Project
-
-
+
+
+ Awesome Project
+
+
+
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
index 6d6c0398864..7a0c3760929 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
@@ -63,7 +63,7 @@ exports[`should display the list of repositories 1`] = `
- onboarding.create_project.create_project
+ create
+
+
+ onboarding.create_project.beta_feature_x.Foo Provider
+
+
+
`;
exports[`should display the provider app install button 2`] = `
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
index 1880a16ba4c..fffc678a6db 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
@@ -20,44 +20,73 @@ exports[`should render correctly 1`] = `
onboarding.create_project.header
-
+
+
+`;
+
+exports[`should render correctly 2`] = `
+
+
+
`;
@@ -82,17 +111,83 @@ exports[`should render with Manual creation only 1`] = `
onboarding.create_project.header
-
+
+ onProjectCreate={[Function]}
+ />
+
+
+
+`;
+
+exports[`should switch tabs 1`] = `
+
+
+
+
+
+ onboarding.create_project.header
+
+
+
+
+
+
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
index fafb751c9bb..8f1ddb22631 100644
--- a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
@@ -4,7 +4,7 @@ exports[`should correctly create a project 1`] = `
- onboarding.create_project.create_project
+ create
`;
@@ -12,7 +12,7 @@ exports[`should correctly create a project 2`] = `
- onboarding.create_project.create_project
+ create
`;
@@ -113,7 +113,7 @@ exports[`should render correctly 1`] = `
- onboarding.create_project.create_project
+ create
;
personalOrganization?: string;
- selection: 'personal' | 'existing' | 'new';
+ selection: Selection;
}
export default class OrganizationStep extends React.PureComponent {
@@ -74,9 +76,10 @@ export default class OrganizationStep extends React.PureComponent
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,